Skip to content

Commit b92ba05

Browse files
FranzBuschphausler
andauthored
Proposal for joined and joined(separator:) (#180)
* Proposal for `joined` and `joined(separator:)` * Small fixes * Update proposal # to 0004 Co-authored-by: Philippe Hausler <[email protected]>
1 parent f44d02e commit b92ba05

File tree

1 file changed

+67
-0
lines changed

1 file changed

+67
-0
lines changed

Evolution/0004-joined.md

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Joined
2+
3+
* Proposal: [SAA-0004](https://github.com/apple/swift-async-algorithms/blob/main/Evolution/0004-joined.md)
4+
* Authors: [Philippe Hausler](https://github.com/phausler)
5+
* Review Manager: [Franz Busch](https://github.com/FranzBusch)
6+
* Status: **Implemented**
7+
8+
* Implementation: [[Source](https://github.com/apple/swift-async-algorithms/blob/main/Sources/AsyncAlgorithms/AsyncJoinedSequence.swift) |
9+
[Tests](https://github.com/apple/swift-async-algorithms/blob/main/Tests/AsyncAlgorithmsTests/TestJoin.swift)]
10+
* Decision Notes:
11+
* Bugs:
12+
13+
## Introduction
14+
15+
The `joined()` and `joined(separator:)` algorithms on `AsyncSequence`s provide APIs to concatenate an `AsyncSequence` of `AsyncSequence`s.
16+
17+
```swift
18+
extension AsyncSequence where Element: AsyncSequence {
19+
public func joined() -> AsyncJoinedSequence<Self>
20+
}
21+
22+
extension AsyncSequence where Element: AsyncSequence {
23+
public func joined<Separator: AsyncSequence>(separator: Separator) -> AsyncJoinedBySeparatorSequence<Self, Separator>
24+
}
25+
```
26+
27+
## Detailed Design
28+
29+
These algorithms iterate over the elements of each `AsyncSequence` one bye one, i.e. only after the iteration of one `AsyncSequence` has finished the next one will be started.
30+
31+
```swift
32+
let appleFeed = URL("http://www.example.com/ticker?symbol=AAPL").lines
33+
let nasdaqFeed = URL("http://www.example.com/ticker?symbol=^IXIC").lines
34+
35+
for try await line in [appleFeed, nasdaqFeed].async.joined() {
36+
print("\(line)")
37+
}
38+
```
39+
40+
Given some sample inputs the following combined events can be expected.
41+
42+
| Timestamp | appleFeed | nasdaqFeed | output |
43+
| ----------- | --------- | ---------- | ----------------------------- |
44+
| 11:40 AM | 173.91 | | 173.91 |
45+
| 12:25 AM | | 14236.78 | |
46+
| 12:40 AM | | 14218.34 | |
47+
| 1:15 PM | 173.00 | | 173.00 |
48+
| 1:15 PM | | | 14236.78 |
49+
| 1:15 PM | | | 14218.34 |
50+
51+
52+
The `joined()` and `joined(separator:)` methods are available on `AsyncSequence`s with elements that are `AsyncSequence`s themselves and produce either an `AsyncJoinedSequence` or an `AsyncJoinedBySeparatorSequence`.
53+
54+
As soon as an inner `AsyncSequence` returns `nil` the algorithm continues with iterating the next inner `AsyncSequence`.
55+
56+
The throwing behaviour of `AsyncJoinedSequence` and `AsyncJoinedBySeparatorSequence` is that if any of the inner `AsyncSequence`s throws, then the composed sequence throws on its iteration.
57+
58+
### Naming
59+
60+
The naming follows to current method naming of the standard library's [`joined`](https://developer.apple.com/documentation/swift/array/joined(separator:)-7uber) method.
61+
Prior art in the reactive community often names this method `concat`; however, we think that an alignment with the current method on `Sequence` is better.
62+
63+
### Comparison with other libraries
64+
65+
**ReactiveX** ReactiveX has an [API definition of Concat](https://reactivex.io/documentation/operators/concat.html) as a top level function for concatenating Observables.
66+
67+
**Combine** Combine has an [API definition of append](https://developer.apple.com/documentation/combine/publisher/append(_:)-5yh02) which offers similar functionality but limited to concatenating two individual `Publisher`s.

0 commit comments

Comments
 (0)