0
# Backported Collections
1
2
Complete implementations of Scala 2.13 collection types for use on Scala 2.11 and 2.12. These backported types provide full feature parity with their 2.13 counterparts, enabling forward compatibility and smooth migration paths.
3
4
## Capabilities
5
6
### ArraySeq - Immutable Array-Backed Sequence
7
8
An immutable sequence backed by an Array, providing efficient indexed access and minimal memory overhead.
9
10
```scala { .api }
11
abstract class ArraySeq[+T] extends IndexedSeq[T] {
12
protected[this] def elemTag: ClassTag[T]
13
def length: Int
14
def apply(index: Int): T
15
def unsafeArray: Array[T @uncheckedVariance]
16
override def clone(): ArraySeq[T]
17
}
18
19
object ArraySeq {
20
/**
21
* Create ArraySeq from elements
22
* @param elems Elements to include
23
* @param elemTag ClassTag for element type
24
* @return New ArraySeq containing elements
25
*/
26
def apply[T](elems: T*)(implicit elemTag: ClassTag[T]): ArraySeq[T]
27
28
/**
29
* Create ArraySeq from a collection (available through compat import)
30
* Note: This method is provided via implicit extension from scala.collection.compat._
31
* @param source Source collection
32
* @param elemTag ClassTag for element type
33
* @return New ArraySeq with elements from source
34
*/
35
def from[T](source: TraversableOnce[T])(implicit elemTag: ClassTag[T]): ArraySeq[T]
36
37
/**
38
* Create empty ArraySeq
39
* @return Empty ArraySeq
40
*/
41
def empty[T <: AnyRef]: ArraySeq[T]
42
43
/**
44
* Wrap existing array without copying (unsafe - array must not be mutated)
45
* @param x Source array to wrap
46
* @return ArraySeq wrapping the array
47
*/
48
def unsafeWrapArray[T](x: Array[T]): ArraySeq[T]
49
50
/**
51
* Create builder for ArraySeq
52
* @param elemTag ClassTag for element type
53
* @return Builder for constructing ArraySeq
54
*/
55
def newBuilder[T](implicit elemTag: ClassTag[T]): Builder[T, ArraySeq[T]]
56
57
/**
58
* Pattern matching extractor
59
* @param seq ArraySeq to extract from
60
* @return Some(seq) for pattern matching
61
*/
62
def unapplySeq[T](seq: ArraySeq[T]): Some[ArraySeq[T]]
63
}
64
```
65
66
**Specialized Implementations:**
67
68
ArraySeq provides specialized implementations for primitive types to avoid boxing:
69
70
```scala { .api }
71
final class ofRef[T <: AnyRef](val unsafeArray: Array[T]) extends ArraySeq[T]
72
final class ofByte(val unsafeArray: Array[Byte]) extends ArraySeq[Byte]
73
final class ofShort(val unsafeArray: Array[Short]) extends ArraySeq[Short]
74
final class ofChar(val unsafeArray: Array[Char]) extends ArraySeq[Char]
75
final class ofInt(val unsafeArray: Array[Int]) extends ArraySeq[Int]
76
final class ofLong(val unsafeArray: Array[Long]) extends ArraySeq[Long]
77
final class ofFloat(val unsafeArray: Array[Float]) extends ArraySeq[Float]
78
final class ofDouble(val unsafeArray: Array[Double]) extends ArraySeq[Double]
79
final class ofBoolean(val unsafeArray: Array[Boolean]) extends ArraySeq[Boolean]
80
final class ofUnit(val unsafeArray: Array[Unit]) extends ArraySeq[Unit]
81
```
82
83
**Usage Examples:**
84
85
```scala
86
import scala.collection.compat.immutable.ArraySeq
87
import scala.collection.compat._ // Required for .from method
88
89
// Create from elements
90
val numbers = ArraySeq(1, 2, 3, 4, 5)
91
val strings = ArraySeq("hello", "world")
92
93
// Create from existing collection (requires compat import for .from method)
94
val fromList = ArraySeq.from(List(1, 2, 3))
95
val fromRange = ArraySeq.from(1 to 10)
96
97
// Efficient indexed access
98
val third = numbers(2) // 3
99
val length = numbers.length // 5
100
101
// Wrap existing array (unsafe - don't mutate the source array!)
102
val array = Array(1, 2, 3)
103
val wrapped = ArraySeq.unsafeWrapArray(array)
104
105
// Builder pattern
106
val builder = ArraySeq.newBuilder[Int]
107
builder += 1
108
builder += 2
109
val built = builder.result()
110
111
// Pattern matching
112
ArraySeq(1, 2, 3) match {
113
case ArraySeq(first, rest @ _*) => println(s"First: $first, Rest: $rest")
114
}
115
```
116
117
### LazyList - Lazy Immutable Linked List
118
119
An immutable linked list that evaluates elements lazily with memoization, perfect for infinite sequences and memory-efficient data processing.
120
121
```scala { .api }
122
final class LazyList[+A] extends LinearSeq[A] {
123
/**
124
* Size if known, -1 otherwise (avoids forcing evaluation)
125
* @return Known size or -1
126
*/
127
def knownSize: Int
128
129
/**
130
* Test if LazyList is empty
131
* @return true if empty
132
*/
133
override def isEmpty: Boolean
134
135
/**
136
* Get first element (forces evaluation of head)
137
* @return First element
138
* @throws NoSuchElementException if empty
139
*/
140
override def head: A
141
142
/**
143
* Get remaining elements (forces evaluation of head only)
144
* @return Tail LazyList
145
* @throws UnsupportedOperationException if empty
146
*/
147
override def tail: LazyList[A]
148
149
/**
150
* Force evaluation of all elements
151
* @return This LazyList with all elements evaluated
152
*/
153
def force: this.type
154
155
/**
156
* Lazy concatenation with another collection
157
* @param suffix Collection to append lazily
158
* @return New LazyList with suffix appended
159
*/
160
def lazyAppendedAll[B >: A](suffix: => GenTraversableOnce[B]): LazyList[B]
161
162
/**
163
* Apply side effect while preserving laziness
164
* @param f Side effect function
165
* @return LazyList with side effects applied during traversal
166
*/
167
def tapEach[U](f: A => U): LazyList[A]
168
169
/**
170
* Partition and map simultaneously (lazy evaluation)
171
* @param f Function returning Either for partitioning and transformation
172
* @return Tuple of (left LazyList, right LazyList)
173
*/
174
def partitionMap[A1, A2](f: A => Either[A1, A2]): (LazyList[A1], LazyList[A2])
175
176
/**
177
* Remove duplicates by function (lazy evaluation)
178
* @param f Function to extract comparison key
179
* @return LazyList with duplicates removed
180
*/
181
def distinctBy[B](f: A => B): LazyList[B]
182
}
183
```
184
185
**LazyList Factory Methods:**
186
187
```scala { .api }
188
object LazyList {
189
/**
190
* Empty LazyList
191
* @return Empty LazyList
192
*/
193
def empty[A]: LazyList[A]
194
195
/**
196
* Create LazyList from elements
197
* @param elems Elements to include
198
* @return LazyList containing elements
199
*/
200
def apply[A](elems: A*): LazyList[A]
201
202
/**
203
* Create LazyList from collection
204
* @param coll Source collection
205
* @return LazyList with elements from collection
206
*/
207
def from[A](coll: GenTraversableOnce[A]): LazyList[A]
208
209
/**
210
* Create infinite LazyList by iteration
211
* @param start Starting value (call-by-name)
212
* @param f Function to generate next value
213
* @return Infinite LazyList
214
*/
215
def iterate[A](start: => A)(f: A => A): LazyList[A]
216
217
/**
218
* Create infinite numeric sequence
219
* @param start Starting number
220
* @param step Step size
221
* @return Infinite LazyList of numbers
222
*/
223
def from(start: Int, step: Int): LazyList[Int]
224
225
/**
226
* Create infinite numeric sequence with step 1
227
* @param start Starting number
228
* @return Infinite LazyList of numbers
229
*/
230
def from(start: Int): LazyList[Int]
231
232
/**
233
* Create infinite LazyList repeating element
234
* @param elem Element to repeat (call-by-name)
235
* @return Infinite LazyList of repeated element
236
*/
237
def continually[A](elem: => A): LazyList[A]
238
239
/**
240
* Create LazyList with n copies of element
241
* @param n Number of copies
242
* @param elem Element to repeat (call-by-name)
243
* @return LazyList with n copies
244
*/
245
def fill[A](n: Int)(elem: => A): LazyList[A]
246
247
/**
248
* Create LazyList by tabulation
249
* @param n Number of elements
250
* @param f Function from index to element
251
* @return LazyList created by applying function to indices
252
*/
253
def tabulate[A](n: Int)(f: Int => A): LazyList[A]
254
255
/**
256
* Create LazyList by unfolding from seed value
257
* @param init Initial seed value
258
* @param f Function that produces (element, next seed) or None to stop
259
* @return LazyList created by unfolding
260
*/
261
def unfold[A, S](init: S)(f: S => Option[(A, S)]): LazyList[A]
262
263
/**
264
* Concatenate multiple iterables into LazyList
265
* @param xss Iterables to concatenate
266
* @return LazyList containing all elements
267
*/
268
def concat[A](xss: collection.Iterable[A]*): LazyList[A]
269
}
270
```
271
272
**Cons Operations and Syntax:**
273
274
```scala { .api }
275
/**
276
* Alternative cons construction
277
*/
278
object cons {
279
def unapply[A](xs: LazyList[A]): Option[(A, LazyList[A])]
280
}
281
282
/**
283
* Pattern matching cons extractor
284
*/
285
object #:: {
286
def unapply[A](xs: LazyList[A]): Option[(A, LazyList[A])]
287
}
288
289
/**
290
* Implicit conversion to enable #:: syntax
291
* @param l LazyList (call-by-name)
292
* @return Deferrer for cons operations
293
*/
294
implicit def toDeferrer[A](l: => LazyList[A]): Deferrer[A]
295
296
final class Deferrer[A] {
297
/**
298
* Prepend element to LazyList
299
* @param elem Element to prepend (call-by-name)
300
* @return New LazyList with element prepended
301
*/
302
def #::[B >: A](elem: => B): LazyList[B]
303
304
/**
305
* Prepend LazyList to LazyList
306
* @param prefix LazyList to prepend
307
* @return Combined LazyList
308
*/
309
def #:::[B >: A](prefix: LazyList[B]): LazyList[B]
310
}
311
```
312
313
**Usage Examples:**
314
315
```scala
316
import scala.collection.compat.immutable.LazyList
317
318
// Create finite LazyList
319
val finite = LazyList(1, 2, 3, 4, 5)
320
val fromRange = LazyList.from(1 to 100)
321
322
// Create infinite LazyList
323
val naturals = LazyList.from(1) // 1, 2, 3, 4, ...
324
val evens = LazyList.from(0, 2) // 0, 2, 4, 6, ...
325
val fibonacci = LazyList.iterate((0, 1)) { case (a, b) => (b, a + b) }.map(_._1)
326
327
// Cons syntax
328
val list1 = 1 #:: 2 #:: 3 #:: LazyList.empty
329
val list2 = 0 #:: list1 // Prepend element
330
val list3 = LazyList(-2, -1) #::: list2 // Prepend LazyList
331
332
// Lazy operations (elements computed on demand)
333
val squares = naturals.map(n => n * n)
334
val first10Squares = squares.take(10).toList
335
336
// Pattern matching
337
fibonacci match {
338
case a #:: b #:: rest => println(s"First two: $a, $b")
339
case _ => println("Not enough elements")
340
}
341
342
// Force evaluation
343
val evaluated = LazyList(1, 2, 3).force
344
345
// Infinite data processing
346
val primes = naturals.drop(1).filter(isPrime)
347
val first100Primes = primes.take(100).toList
348
349
// Lazy concatenation
350
val combined = finite.lazyAppendedAll(naturals)
351
352
// Side effects with preserved laziness
353
val logged = naturals.tapEach(n => if (n % 1000 == 0) println(s"Processed $n"))
354
355
// Memory-efficient processing of large datasets
356
def processLargeFile(lines: LazyList[String]): LazyList[ProcessedData] =
357
lines
358
.filter(_.nonEmpty)
359
.map(parseLine)
360
.tapEach(validateData)
361
.distinctBy(_.id)
362
```
363
364
### Version Compatibility
365
366
On Scala 2.13, these types are implemented as type aliases to the standard library implementations:
367
368
```scala { .api }
369
// Scala 2.13 compatibility aliases
370
package scala.collection.compat.immutable {
371
type ArraySeq[+A] = scala.collection.immutable.ArraySeq[A]
372
val ArraySeq = scala.collection.immutable.ArraySeq
373
374
type LazyList[+A] = scala.collection.immutable.LazyList[A]
375
val LazyList = scala.collection.immutable.LazyList
376
}
377
```
378
379
This ensures that code written using the compat library works identically across all Scala versions while providing full implementations for older versions that lack these collection types.