Skip to content

Commit 10e1ecb

Browse files
committed
Support cljdoc
Update documentation and metadata
1 parent 4543494 commit 10e1ecb

20 files changed

+69
-48
lines changed

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,4 @@ pom.xml.asc
88
/.lein-*
99
/.nrepl-port
1010
*DS_Store
11-
/doc
1211
push
13-
/doc

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
[![Clojars Project](https://img.shields.io/clojars/v/manifold.svg)](https://clojars.org/manifold)
22
[![cljdoc badge](https://cljdoc.org/badge/manifold/manifold)](https://cljdoc.org/d/manifold/manifold)
33
[![CircleCI](https://circleci.com/gh/clj-commons/manifold.svg?style=svg)](https://circleci.com/gh/clj-commons/manifold)
4-
![](docs/manifold.png)
4+
![](doc/manifold.png)
55

6-
This library provides basic building blocks for asynchronous programming, and can be used as a translation layer between libraries which use similar but incompatible abstractions.
6+
Manifold provides basic building blocks for asynchronous programming, and can be used as a translation layer between libraries which use similar, but incompatible, abstractions.
77

88
Manifold provides two core abstractions: **deferreds**, which represent a single asynchronous value, and **streams**, which represent an ordered sequence of asynchronous values.
99

10-
A detailed discussion of Manifold's rationale can be found [here](http://aleph.io/manifold/rationale.html). Full documentation can be found [here](https://cljdoc.org/d/manifold/manifold).
10+
A detailed discussion of Manifold's rationale can be found [here](doc/rationale.md). Full documentation can be found [here](https://cljdoc.org/d/manifold/manifold).
1111

1212

1313
```clojure
@@ -59,7 +59,7 @@ success! :foo
5959
true
6060
```
6161

62-
Callbacks are a useful building block, but they're a painful way to create asynchronous workflows. In practice, **no one should ever need to use `on-realized`**. Manifold provides a number of operators for composing over deferred values, [which can be read about here](/docs/deferred.md).
62+
Callbacks are a useful building block, but they're a painful way to create asynchronous workflows. In practice, **no one should ever need to use `on-realized`**. Manifold provides a number of operators for composing over deferred values, [which can be read about here](/doc/deferred.md).
6363

6464
### Streams
6565

@@ -110,7 +110,7 @@ nil
110110
1
111111
```
112112

113-
Manifold can use any transducer, which are applied via `transform`. It also provides stream-specific transforms, including `zip`, `reduce`, `buffer`, `batch`, and `throttle`. [To learn more about streams, go here](/docs/stream.md).
113+
Manifold can use any transducer, which are applied via `transform`. It also provides stream-specific transforms, including `zip`, `reduce`, `buffer`, `batch`, and `throttle`. [To learn more about streams, go here](/doc/stream.md).
114114

115115
### Clojurescript
116116

doc/cljdoc.edn

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{:cljdoc.doc/tree [["Read Me" {:file "README.md"}]
2+
["Rationale" {:file "doc/rationale.md"}]
3+
["Deferreds" {:file "doc/deferred.md"}]
4+
["Streams" {:file "doc/stream.md"}]
5+
["Execution" {:file "doc/execution.md"}]]}

docs/deferred.md renamed to doc/deferred.md

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,8 @@ Let's say that we have two services which provide us numbers, and want to get th
131131
(let [a (call-service-a)
132132
b (call-service-b)]
133133
(chain (zip a b)
134-
(fn [[a b]]
135-
(+ a b)))))
134+
(fn [[a b]]
135+
(+ a b)))))
136136
```
137137

138138
However, this isn't a very direct expression of what we're doing. For more complex relationships between deferred values, our code will become even more difficult to understand. In these cases, it's often best to use `let-flow`.
@@ -158,38 +158,45 @@ but not this:
158158
```clojure
159159
(let-flow [a (future 1)
160160
b (let [c (future 1)]
161-
(+ a c))]
161+
(+ a c))]
162162
(+ b 1))
163163
```
164164

165165
In this example, `c` is declared within a normal `let` binding, and as such we can't treat it as if it were realized.
166166

167167
It can be helpful to think of `let-flow` as similar to Prismatic's [Graph](https://github.com/prismatic/plumbing#graph-the-functional-swiss-army-knife) library, except that the dependencies between values are inferred from the code, rather than explicitly specified. Comparisons to core.async's goroutines are less accurate, since `let-flow` allows for concurrent execution of independent paths within the bindings, whereas operations within a goroutine are inherently sequential.
168168

169-
### manifold.go-off
169+
### go-off
170170

171-
An alternate way to write code using deferreds is the macro `manifold.go-off/go-off`. This macro is an almost exact mirror of the `go` macro from [clojure/core.async](https://github.com/clojure/core.async), to the point where it actually utilizes the state machine functionality from core.async. In order to use this macro, `core.async` must be a dependency provided by the user. The main difference between `go` and `go-off`, besides go-off working with deferrables instead of core.async channels, is the `take` function being `<!?` instead of `<!`. The difference in function names is used to indicate exceptions behave the same as a non-async clojure block (i.e. are thrown) instead of silently swallowed & returning `nil`.
171+
An alternate way to write code using deferreds is the macro `manifold.go-off/go-off`. This macro is an almost-exact mirror of the `go` macro from [core.async](https://github.com/clojure/core.async), to the point where it actually utilizes the state machine functionality from core.async. In order to use this macro, `core.async` must be provided as a dependency by the user.
172172

173-
The benefit of this macro over `let-flow` is that it gives complete control of when deferreds should be realized to the user of the macro, removing any potential surprises (especially around timeouts).
173+
There are a few major differences between `go` and `go-off`. First, `go-off` (unsurprisingly) works with Manifold deferreds and streams instead of core.async channels. Second, in addition to the `<!` fn, which always returns a value, there's also the `<!?` macro, which behaves the same unless a Throwable is retrieved, in which case it's automatically rethrown for you. Finally, there's no `>!` equivalent in `go-off`, as there's no way without altering the syntax to distinguish between success and error when putting into a deferred.
174174

175-
```clj
175+
The benefit of `go-off` over `let-flow` is that it gives complete control of when deferreds should be realized to the user, removing any potential surprises (especially around timeouts).
176+
177+
```clojure
178+
;; basic usage
176179
@(go-off (+ (<!? (d/future 10))
177-
(<!? (d/future 20)))) ;; ==> 30
180+
(<!? (d/future 20)))) ;; 30
178181
```
179182

180-
```clj
181-
(<!! (core.async/go (try (<! (go (/ 5 0)))
182-
(catch Exception e
183-
"ERROR")))) ; ==> nil
183+
```clojure
184+
;; <!? usage
185+
186+
;; if you forget to catch an exception in go, it won't be returned
187+
(<!! (go (try (<! (go (/ 5 0)))
188+
(catch Exception e
189+
"ERROR")))) ;; nil
184190

191+
;; d/future returns any exceptions, and <!? rethrows it for you
185192
@(go-off (try (<!? (d/future (/ 5 0)))
186-
(catch Exception e
187-
"ERROR"))) ; ==> "ERROR"
193+
(catch Exception e
194+
"ERROR"))) ;; "ERROR"
188195
```
189196

190-
### `manifold.deferred/loop`
197+
### loop
191198

192-
Manifold also provides a `loop` macro, which allows for asynchronous loops to be defined. Consider `manifold.stream/consume`, which allows a function to be invoked with each new message from a stream. We can implement similar behavior like so:
199+
Manifold also provides a `loop` macro, which allows for asynchronous loops to be defined. Consider `manifold.stream/consume`, which allows a function to be invoked with each new message from a stream. We can implement similar behavior like so:
193200

194201
```clojure
195202
(require
@@ -215,8 +222,7 @@ Manifold also provides a `loop` macro, which allows for asynchronous loops to be
215222

216223
Here we define a loop which takes messages one at a time from `stream`, and passes them into `f`. If `f` returns an unrealized value, the loop will pause until it's realized. To recur, we make sure the value returned from the final stage is `(manifold.deferred/recur & args)`, which will cause the loop to begin again from the top.
217224

218-
While Manifold doesn't provide anything as general purpose as core.async's `go` macro, the combination of `loop` and `let-flow` can allow for the specification of highly intricate asynchronous workflows.
219225

220226
### Custom execution models
221227

222-
Both deferreds and streams allow for custom execution models to be specified. To learn more, [go here](/docs/execution.md).
228+
Both deferreds and streams allow for custom execution models to be specified. To learn more, [go here](/doc/execution.md).
File renamed without changes.
File renamed without changes.

docs/rationale.md renamed to doc/rationale.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This means that we not only need to correctly process the data, we need to have
44

55
Backpressure is a fundamental property of Java's threading model, as shown by `BlockingQueues`, `Futures`, `InputStreams`, and others. It's also a fundamental property of `core.async` channels, though it uses a completely different execution model built on callbacks and macros. It's also a fundamental property of Clojure's lazy sequences, which like Java's abstractions are blocking, but unlike both Java and `core.async` relies on pulling data towards the consumer rather than having it pushed.
66

7-
Unfortunately, while all of these abstractions (or [RxJava](https://github.com/Netflix/RxJava), or [Reactive Streams](http://www.reactive-streams.org/), or ...) can be used to similar effects, they don't necessarily work well with each other. The practical effect of this is that by choosing one abstraction, we often make the others off-limits. When writing an application, this may be acceptable, if not really desirable. When writing a library or something meant to be reused, though, it's much worse; only people who have chosen your particular walled garden can use your work.
7+
Unfortunately, while all of these abstractions (or [RxJava](https://github.com/ReactiveX/RxJava), or [Reactive Streams](http://www.reactive-streams.org/), or ...) can be used to similar effects, they don't necessarily work well with each other. The practical effect of this is that by choosing one abstraction, we often make the others off-limits. When writing an application, this may be acceptable, if not really desirable. When writing a library or something meant to be reused, though, it's much worse; only people who have chosen your particular walled garden can use your work.
88

99
Manifold provides abstractions that sits at the intersection of all these similar, but incompatible, approaches. It provides an extensible mechanism for coercing unrealized data into a generic form, and piping data from these generic forms into other stream representations.
1010

docs/stream.md renamed to doc/stream.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ A stream can be thought of as two separate halves: a **sink** which consumes me
1818
<< 1 >>
1919
```
2020

21-
Notice that both `put!` and `take!` return [deferred values](/docs/deferred.md). The deferred returned by `put!` will yield `true` if the message was accepted by the stream, and `false` otherwise; the deferred returned by `take!` will yield the message.
21+
Notice that both `put!` and `take!` return [deferred values](/doc/deferred.md). The deferred returned by `put!` will yield `true` if the message was accepted by the stream, and `false` otherwise; the deferred returned by `take!` will yield the message.
2222

2323
Sinks can be **closed** by calling `close!`, which means they will no longer accept messages.
2424

src/manifold/debug.clj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
(ns manifold.debug)
1+
(ns manifold.debug
2+
{:no-doc true})
23

34
(def ^:dynamic *dropped-error-logging-enabled?* true)
45

src/manifold/go_off.clj

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
(ns ^{:author "Ryan Smith"
2-
:doc "Provide a variant of `core.async/go` that works with manifold's deferreds and executors. Utilizes core.async's state-machine generator, so core.async must be provided as a dependency."}
3-
manifold.go-off
1+
(ns manifold.go-off
2+
{:author "Ryan Smith"
3+
:doc "Provides a variant of `core.async/go` that works with manifold's deferreds and streams. Utilizes core.async's state-machine generator, so core.async must be provided by consumers as a dependency."
4+
:added "0.2.0"}
45
(:require [manifold
56
[executor :as ex]
67
[deferred :as d]]
@@ -15,21 +16,21 @@
1516
d))
1617

1718
(defn <!
18-
"Takes value from a deferred/stream. Must be called inside a (go ...) block. Will
19+
"Takes value from a deferred/stream. Must be called inside a `(go-off ...)` block. Will
1920
return nil if a stream is closed. Will park if nothing is available. If an error
20-
is thrown inside the body, that error will be placed as the return value.
21+
is thrown inside the body, that error will be the return value.
2122
2223
N.B. To make `go-off` usage idiomatic with the rest of manifold, use `<!?`
2324
instead."
24-
[port]
25+
[deferred-or-stream]
2526
(assert nil "<! used not in (go-off ...) block"))
2627

2728
(defmacro <!?
28-
"Takes a val from a deferred/stream. Must be called inside a (go-off ...) block.
29-
Will park if nothing is available. If value that is returned is a Throwable,
30-
it will re-throw."
31-
[port]
32-
`(let [r# (<! ~port)]
29+
"Takes a value from a deferred/stream. Must be called inside a `(go-off ...)` block.
30+
Will park if nothing is available. If the value returned is a Throwable,
31+
it will be re-thrown."
32+
[deferred-or-stream]
33+
`(let [r# (<! ~deferred-or-stream)]
3334
(if (instance? Throwable r#)
3435
;; this is a re-throw of the original throwable. the expectation is that
3536
;; it still will maintain the original stack trace
@@ -42,7 +43,7 @@
4243
(d/error! (ioc/aget-object state ioc/USER-START-IDX) ex)
4344
(throw ex))))
4445

45-
(defn take! [state blk d]
46+
(defn ^:no-doc take! [state blk d]
4647
(let [handler (fn [x]
4748
(ioc/aset-all! state ioc/VALUE-IDX x ioc/STATE-IDX blk)
4849
(run-state-machine-wrapped state))
@@ -72,7 +73,7 @@
7273
:Return `return-deferred})
7374

7475
(defmacro go-off-with
75-
"Implementation of go-off that allows specifying executor. See docstring of go-off for usage."
76+
"An implementation of `go-off` that allows specifying the executor to run on. See docstring of [[go-off]] for usage."
7677
[executor & body]
7778
(let [executor (vary-meta executor assoc :tag 'java.util.concurrent.Executor)
7879
crossing-env (zipmap (keys &env) (repeatedly gensym))]
@@ -92,8 +93,8 @@
9293

9394
(defmacro go-off
9495
"Asynchronously executes the body on manifold's default executor, returning
95-
immediately to the calling thread. Additionally, any visible calls to <!?
96-
and <! deferred operations within the body will block (if necessary)
96+
immediately to the calling thread. Additionally, any visible calls to `<!?`
97+
and `<!` deferred operations within the body will block (if necessary)
9798
by 'parking' the calling thread rather than tying up an OS thread.
9899
Upon completion of the operation, the body will be resumed.
99100
@@ -106,16 +107,16 @@
106107
to address the following major points from core.async & vanilla manifold deferreds:
107108
108109
- `core.async/go` assumes that all of your code is able to be purely async
109-
and will never block the handling threads. go-off removes the concept of handling
110-
threads, which means blocking is not an issue, but if you spawn too many of these you
111-
can create too many threads for the OS to handle.
110+
and will never block the handling threads. `go-off` removes the concept of handling
111+
threads, which means blocking is not an issue, but if you spawn too many of these, you
112+
can create more threads than the OS can handle.
112113
- `core.async/go` has no built-in way of handling exceptions and assumes all async
113114
code will be either written defensively, or have custom error propagation, which
114115
differs from how clojure code blocks typically work outside of the async world.
115-
- `deferred/let-flow` presumes that every deferrable needs to be resolved. This prevents
116+
- [[deferred/let-flow]] presumes that every deferrable needs to be resolved. This prevents
116117
more complex handling of parallelism or being able to pass deferreds into other functions
117118
from within the `let-flow` block.
118-
- `deferred/chain` only works with single deferreds, which means having to write code in
119+
- [[deferred/chain]] only works with single deferreds, which means having to write code in
119120
unnatural ways to handle multiple deferreds."
120121
[& body]
121122
`(go-off-with (ex/execute-pool) ~@body))

0 commit comments

Comments
 (0)