Skip to content

Commit

Permalink
docs: adjusted buttons + readme
Browse files Browse the repository at this point in the history
  • Loading branch information
tassiluca committed Mar 4, 2024
1 parent 7a77702 commit 20dfdd8
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 15 deletions.
64 changes: 62 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,63 @@
# Direct style for Functional Reactive Programming experiments
# Direct style for Functional Reactive Programming: an analysis in Scala & Kotlin

`TBD`
## Goals of the project

> In the realm of asynchronous programming, the Scala ecosystem offers a set of solid monads constructs to tackle complex task functionally with elegance and efficiency, like [Monix Tasks](https://monix.io/docs/current/eval/task.html) and [Cats Effect](https://typelevel.org/cats-effect/).
>
> However, we are assisting to the increase in adoption of continuation and coroutines in modern runtimes, either exploiting some kind of fibers support, like the project Loom with Virtual Threads, or via code generation, like Kotlin Coroutines.
>
> The goal of this project is to delve into this field through the lens of direct style, developing few examples (not too complex) leveraging the new *strawman* library [Scala Gears](https://github.com/lampepfl/gears), comparing it with Kotlin's Coroutines and the current implementation of monadic Futures, seeking to analyze aspects such as:
>
> - ergonomics of the two styles (which one results more thoughtful and/or verbose);
> - which of the two approaches has a real advantage in adoption;
> - pros and cons of the two styles;
> - how and when to use one approach rather than the other;
> - any limitations and difficulties encountered in using them;
## Overview

The project is built around three main examples, delving from the fundamentals of the direct style frameworks for simple asynchronous computation to more complex reactive-like systems.

Here's the outline of the conducted analysis:

1. [`Boundary` and `break`](./docs/01-boundaries)
2. [Basic asynchronous constructs](./docs/02-basics)
3. [Channels as a communication primitive](./docs/03-channels)
4. [Reactivity in direct style](./docs/04-rears)
5. [Conclusions](./docs/05-going-further)

Code has been organized in Gradle submodules, one for each version of the examples (current monadic futures, Scala Gears, Kotlin Coroutines).
Here an overview of the project folder structure:

```plaintext
direct-style-experiments
├── analyzer-commons # common code for analyzers (UI, controller, ...)
├── analyzer-direct # analyzer example using Scala Gears
├── analyzer-direct-kt # analyzer example using Kotlin Coroutines
├── analyzer-monadic # analyzer example using current Futures
├── blog-ws-commons # common code for the blog service example
├── blog-ws-direct # blog service example using Scala Gears
├── blog-ws-direct-kt # blog service example using Kotlin Coroutines
├── blog-ws-monadic # blog service example using current Futures
├── commons/ # modules with common code for entire project
│ ├─ src/
│ │ └─ main/
│ │ └─ scala/
│ │ ├─ boundaries # `boundary` and `break` implementations
│ │ ├─ examples # some common examples
│ │ └─ pimping # proposed extensions to the Scala Gears library
│ └─ test # general tests (cancellation, structured concurrency, ...)
├── rears # extensions to the Scala Gears library for Rx
├── smart-hub-direct # smart hub example using Scala Gears
└── smart-hub-direct-kt # smart hub example using Kotlin Coroutines
```

Generally speaking, the runnable examples can be run by simply executing the `run` Gradle task in the respective submodule, like:

```bash
./gradlew :analyzer-direct:run
```

Detailed instructions follows in the specific sections.

**Examples works with a version of the JDK > 21** (Virtual Threads are needed!).
12 changes: 11 additions & 1 deletion docs/assets/_custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,17 @@

&.smallest {
width: 50%;
}
}

@media screen and (max-width: 768px) {
&.smaller {
width: 100%;
}

&.smallest {
width: 100%;
}
}
}

figure.center {
Expand Down
36 changes: 35 additions & 1 deletion docs/content/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,38 @@ Here's the outline of the conducted analysis:
4. [Reactivity in direct style](./docs/04-rears)
5. [Conclusions](./docs/05-going-further)

Code has been organized in Gradle submodules, one for each version of the examples (current monadic futures, Scala Gears, Kotlin Coroutines):
Code has been organized in Gradle submodules, one for each version of the examples (current monadic futures, Scala Gears, Kotlin Coroutines).
Here an overview of the project folder structure:

```plaintext
direct-style-experiments
├── analyzer-commons # common code for analyzers (UI, controller, ...)
├── analyzer-direct # analyzer example using Scala Gears
├── analyzer-direct-kt # analyzer example using Kotlin Coroutines
├── analyzer-monadic # analyzer example using current Futures
├── blog-ws-commons # common code for the blog service example
├── blog-ws-direct # blog service example using Scala Gears
├── blog-ws-direct-kt # blog service example using Kotlin Coroutines
├── blog-ws-monadic # blog service example using current Futures
├── commons/ # modules with common code for entire project
│ ├─ src/
│ │ └─ main/
│ │ └─ scala/
│ │ ├─ boundaries # `boundary` and `break` implementations
│ │ ├─ examples # some common examples
│ │ └─ pimping # proposed extensions to the Scala Gears library
│ └─ test # general tests (cancellation, structured concurrency, ...)
├── rears # extensions to the Scala Gears library for Rx
├── smart-hub-direct # smart hub example using Scala Gears
└── smart-hub-direct-kt # smart hub example using Kotlin Coroutines
```

Generally speaking, the runnable examples can be run by simply executing the `run` Gradle task in the respective submodule, like:

```bash
./gradlew :analyzer-direct:run
```

Detailed instructions follows in the specific sections.

**Examples works with a version of the JDK > 21** (Virtual Threads are needed!).
4 changes: 2 additions & 2 deletions docs/content/docs/01-boundaries.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,6 @@ object EitherConversions:

This kind of data type will be particularly useful in the next examples to quickly break in case of failures, returning the caller a meaningful error message, and simplifying the error-handling code.

{{< button href="https://tassiluca.github.io/PPS-22-direct-style-experiments/PPS-22-direct-style-experiments/" >}} **Home** {{< /button >}}
{{< button relref="/" >}} **Home** {{< /button >}}

{{< button href="https://tassiluca.github.io/PPS-22-direct-style-experiments/PPS-22-direct-style-experiments/docs/02-basics/" >}} **Next**: Basic asynchronous constructs {{< /button >}}
{{< button relref="/02-basics" >}} **Next**: Basic asynchronous constructs {{< /button >}}
4 changes: 2 additions & 2 deletions docs/content/docs/02-basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,6 @@ private suspend fun verifyContent(title: String, body: String): PostContent { ..
> - Kotlin Coroutines handles the cancellation of nested coroutines more easily than Scala Gears, where special attention is required;
> - As [stated by M. Odersky](https://github.com/lampepfl/gears/issues/19#issuecomment-1732586362) the `Async` capability is better than `suspend` in Kotlin because let defines functions that work for synchronous as well as asynchronous function arguments.
{{< button href="https://tassiluca.github.io/PPS-22-direct-style-experiments/PPS-22-direct-style-experiments/docs/01-boundaries" >}} **Previous**: boundary & break{{< /button >}}
{{< button relref="/01-boundaries" >}} **Previous**: boundary & break{{< /button >}}

{{< button href="https://tassiluca.github.io/PPS-22-direct-style-experiments/PPS-22-direct-style-experiments/docs/03-channels/" >}} **Next**: Channels as a communication primitive {{< /button >}}
{{< button relref="/03-channels" >}} **Next**: Channels as a communication primitive {{< /button >}}
4 changes: 2 additions & 2 deletions docs/content/docs/03-channels.md
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,6 @@ Success(The Tell-Tale Heart)
> - The `Flow` abstraction in Kotlin Coroutines is a powerful tool for handling cold streams of data, and it is a perfect fit for functions that need to return a stream of asynchronously computed values **by request**.
> - A similar abstraction can be implemented in Scala Gears leveraging `Task`s and `TerminableChannel`s, enabling improved support for an asynchronous flow of data also in Gears, which is currently lacking.
{{< button href="https://tassiluca.github.io/PPS-22-direct-style-experiments/PPS-22-direct-style-experiments/docs/02-basics" >}} **Previous**: Basic asynchronous constructs{{< /button >}}
{{< button relref="/02-basics" >}} **Previous**: Basic asynchronous constructs{{< /button >}}

{{< button href="https://tassiluca.github.io/PPS-22-direct-style-experiments/PPS-22-direct-style-experiments/docs/04-rears" >}} **Next**: Reactivity in direct style{{< /button >}}
{{< button relref="/04-rears" >}} **Next**: Reactivity in direct style{{< /button >}}
12 changes: 8 additions & 4 deletions docs/content/docs/04-rears.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ The attempt, described in the following, has been to extend this framework addin
- A `Producer` is a runnable entity, programmed with a `Task`, producing items on a channel. It exposes the `publishingChannel` method, which returns a `ReadableChannel` through which interested consumers can read produced items.
- A `Consumer` is a runnable entity devoted to consuming data from a channel, exposed by the `listeningChannel` method which returns a `SendableChannel` to send items to.
- It can be made stateful by mixing it with the `State` trait, allowing it to keep track of its state, which is updated every time with the result of the `react`ion (i.e. its return type).
- **Warning**: like in an event-loop, the `react`ion logic should not perform long-lasting blocking operation, otherwise, the whole system will not react to new events.
- **Warning** Like in an event-loop, the `react`ion logic should not perform long-lasting blocking operation, otherwise, the whole system will not react to new events: the `Async` capability is though needed if you want to give the client the ability to invoke `Future`s within this block; otherwise, another option (alternative to the following) would be to encapsulate the reaction behavior within a `Task` and run it at every received data. However, race conditions could take place in this last case.

```scala
/** A producer, i.e. a runnable entity producing items on a channel. */
Expand Down Expand Up @@ -468,6 +468,8 @@ Going back to the example here is presented a schema summarizing the flows of da
).run
```

---

To produce a testable version of this example, a simulated source of sensor data has been created, backed to a GUI, through which the user can simulate the behavior of the sensors.
The example is runnable via:

Expand All @@ -480,6 +482,8 @@ Entering some value in the panels and pressing the "Send" button, after 5 second

{{< figure src="../../res/img/smart-hub.png" alt="Smart Hub application" width="90%" >}}

---

### Kotlin Coroutines version

Kotlin Coroutines offers two other abstractions to deal with asynchronous data streams, belonging to the `flow` "family", which are: `SharedFlow` and `StateFlow`.
Expand Down Expand Up @@ -551,8 +555,8 @@ suspend fun run(sensorSource: Flow<TemperatureEntry>) {
## Takeaways

- Channels in Scala Gears are fine to model flow of data **that exist without application's request from them**: incoming network connections, event streams, etc...
-

{{< button href="https://tassiluca.github.io/PPS-22-direct-style-experiments/PPS-22-direct-style-experiments/docs/03-channels" >}} **Previous**: Channels as a communication primitive{{< /button >}}

{{< button href="https://tassiluca.github.io/PPS-22-direct-style-experiments/PPS-22-direct-style-experiments/docs/05-conclusions" >}} **Next**: Conclusions{{< /button >}}
{{< button relref="/03-channels" >}} **Previous**: Channels as a communication primitive{{< /button >}}

{{< button relref="/05-conclusions" >}} **Next**: Conclusions{{< /button >}}
2 changes: 1 addition & 1 deletion docs/content/docs/05-conclusions.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ bookToc: false
To conclude, in this project, the main direct-style asynchronous programming abstractions offered by the Kotlin Coroutines and Scala's new, still entirely experimental library proposal, Gears, were analyzed.
During the analysis, input was also provided for its possible extension where it was deemed lacking compared to the Kotlin framework.

{{< button href="https://tassiluca.github.io/PPS-22-direct-style-experiments/PPS-22-direct-style-experiments/" >}} **Home** {{< /button >}}
{{< button relref="/" >}} **Home** {{< /button >}}

0 comments on commit 20dfdd8

Please sign in to comment.