0
# BuildFrom Abstraction
1
2
This document covers the `BuildFrom` abstraction, which provides cross-compilation support for building collections with source context.
3
4
## BuildFrom Trait
5
6
### Core Interface
7
8
```scala { .api }
9
trait BuildFrom[-From, -A, +C] extends Any {
10
/**
11
* Builds a collection of type C from an iterable of elements of type A,
12
* using the source collection From for context.
13
*/
14
def fromSpecificIterable(from: From)(it: Iterable[A]): C
15
16
/**
17
* Gets a Builder for the collection. For non-strict collection types this will
18
* use an intermediate buffer. Building collections with fromSpecificIterable is
19
* preferred because it can be lazy for lazy collections.
20
*/
21
def newBuilder(from: From): Builder[A, C]
22
23
/**
24
* @deprecated Use newBuilder instead of apply()
25
* Legacy method for getting a builder.
26
*/
27
@deprecated("Use newBuilder instead of apply()", "2.13.0")
28
@inline def apply(from: From): Builder[A, C] = newBuilder(from)
29
}
30
```
31
32
The `BuildFrom` trait abstracts the process of building collections while maintaining information about the source collection type. This enables more precise type inference and better performance in collection transformations.
33
34
## BuildFrom Companion Object
35
36
### Implicit Conversions
37
38
```scala { .api }
39
object BuildFrom {
40
/**
41
* Creates a BuildFrom instance from an implicit CanBuildFrom instance.
42
* This provides compatibility with the existing CanBuildFrom-based ecosystem.
43
*/
44
implicit def fromCanBuildFrom[From, A, C](
45
implicit cbf: CanBuildFrom[From, A, C]
46
): BuildFrom[From, A, C]
47
48
/**
49
* Creates a BuildFrom instance from an implicit conversion to CanBuildFrom.
50
* This handles cases where the conversion is not direct.
51
*/
52
implicit def fromCanBuildFromConversion[X, From, A, C](x: X)(
53
implicit toCanBuildFrom: X => CanBuildFrom[From, A, C]
54
): BuildFrom[From, A, C]
55
}
56
```
57
58
## Version-Specific Implementations
59
60
### Scala 2.11/2.12 Implementation
61
62
In Scala 2.11 and 2.12, `BuildFrom` is a custom trait implemented in the compatibility library:
63
64
```scala { .api }
65
// Custom implementation that wraps CanBuildFrom
66
trait BuildFrom[-From, -A, +C] extends Any {
67
def fromSpecificIterable(from: From)(it: Iterable[A]): C
68
def newBuilder(from: From): Builder[A, C]
69
}
70
71
// Companion provides implicit conversions from CanBuildFrom
72
object BuildFrom {
73
implicit def fromCanBuildFrom[From, A, C](
74
implicit cbf: CanBuildFrom[From, A, C]
75
): BuildFrom[From, A, C] = new BuildFrom[From, A, C] {
76
def fromSpecificIterable(from: From)(it: Iterable[A]): C =
77
(cbf(from) ++= it).result()
78
def newBuilder(from: From): Builder[A, C] = cbf(from)
79
}
80
}
81
```
82
83
### Scala 2.13 Implementation
84
85
In Scala 2.13, `BuildFrom` is a type alias to the standard library's `BuildFrom`:
86
87
```scala { .api }
88
type BuildFrom[-From, -A, +C] = scala.collection.BuildFrom[From, A, C]
89
val BuildFrom = scala.collection.BuildFrom
90
```
91
92
## Usage Examples
93
94
### Basic BuildFrom Usage
95
96
```scala
97
import scala.collection.compat._
98
99
def transformCollection[From, A, B, To](
100
source: From,
101
elements: Iterable[A],
102
transform: A => B
103
)(implicit bf: BuildFrom[From, B, To]): To = {
104
val transformed = elements.map(transform)
105
bf.fromSpecificIterable(source)(transformed)
106
}
107
108
// Usage with different collection types
109
val list = List(1, 2, 3)
110
val vector = Vector("a", "b", "c")
111
112
// Transform preserving source collection type context
113
val doubledList = transformCollection(list, list, (x: Int) => x * 2)
114
// Result type inferred as List[Int]
115
116
val uppercasedVector = transformCollection(vector, vector, (s: String) => s.toUpperCase)
117
// Result type inferred as Vector[String]
118
```
119
120
### Builder Pattern with Context
121
122
```scala
123
import scala.collection.compat._
124
125
def buildFromSource[From, A, C](source: From, elements: A*)
126
(implicit bf: BuildFrom[From, A, C]): C = {
127
128
val builder = bf.newBuilder(source)
129
builder ++= elements
130
builder.result()
131
}
132
133
// Create collections with source context
134
val sourceList = List(1, 2, 3)
135
val newList = buildFromSource(sourceList, 4, 5, 6) // List[Int]
136
137
val sourceVector = Vector("x", "y")
138
val newVector = buildFromSource(sourceVector, "a", "b", "c") // Vector[String]
139
```
140
141
### Map Transformation with BuildFrom
142
143
```scala
144
import scala.collection.compat._
145
146
// Generic map transformation that preserves collection type
147
def mapPreservingType[From, A, B, To](
148
collection: From with Iterable[A]
149
)(f: A => B)(implicit bf: BuildFrom[From, B, To]): To = {
150
bf.fromSpecificIterable(collection)(collection.map(f))
151
}
152
153
val numbers = List(1, 2, 3, 4, 5)
154
val strings = mapPreservingType(numbers)(_.toString)
155
// strings: List[String] = List("1", "2", "3", "4", "5")
156
157
val vectorNumbers = Vector(10, 20, 30)
158
val vectorStrings = mapPreservingType(vectorNumbers)(_.toString)
159
// vectorStrings: Vector[String] = Vector("10", "20", "30")
160
```
161
162
### Custom Collection Integration
163
164
```scala
165
import scala.collection.compat._
166
167
// Custom collection that can work with BuildFrom
168
case class MyCollection[A](elements: List[A]) extends Iterable[A] {
169
def iterator: Iterator[A] = elements.iterator
170
}
171
172
object MyCollection {
173
implicit def buildFrom[A]: BuildFrom[MyCollection[_], A, MyCollection[A]] =
174
new BuildFrom[MyCollection[_], A, MyCollection[A]] {
175
def fromSpecificIterable(from: MyCollection[_])(it: Iterable[A]): MyCollection[A] =
176
MyCollection(it.toList)
177
178
def newBuilder(from: MyCollection[_]): Builder[A, MyCollection[A]] = {
179
val listBuilder = List.newBuilder[A]
180
listBuilder.mapResult(MyCollection(_))
181
}
182
}
183
}
184
185
// Usage with standard operations
186
val myCol = MyCollection(List(1, 2, 3))
187
val transformed = mapPreservingType(myCol)(_ * 2)
188
// transformed: MyCollection[Int] = MyCollection(List(2, 4, 6))
189
```
190
191
### Working with Different Source Types
192
193
```scala
194
import scala.collection.compat._
195
196
// BuildFrom allows different source and target types
197
def convertWithContext[From, A, To](
198
source: From,
199
elements: Iterable[A]
200
)(implicit bf: BuildFrom[From, A, To]): To = {
201
bf.fromSpecificIterable(source)(elements)
202
}
203
204
// Convert List elements to Vector using List as context
205
val listSource = List(1, 2, 3)
206
implicit val listToVector: BuildFrom[List[_], Int, Vector[Int]] =
207
new BuildFrom[List[_], Int, Vector[Int]] {
208
def fromSpecificIterable(from: List[_])(it: Iterable[Int]) = it.toVector
209
def newBuilder(from: List[_]) = Vector.newBuilder[Int]
210
}
211
212
val result = convertWithContext(listSource, List(4, 5, 6))
213
// result: Vector[Int] = Vector(4, 5, 6)
214
```
215
216
### Lazy Collection Support
217
218
```scala
219
import scala.collection.compat._
220
221
// BuildFrom supports lazy collections efficiently
222
def lazyTransform[From, A, B, To](
223
source: From with Iterable[A]
224
)(f: A => B)(implicit bf: BuildFrom[From, B, To]): To = {
225
// fromSpecificIterable can handle lazy evaluation
226
bf.fromSpecificIterable(source)(source.view.map(f))
227
}
228
229
val stream = Stream.from(1).take(5)
230
val doubled = lazyTransform(stream)(_ * 2)
231
// For streams, this maintains lazy evaluation characteristics
232
```
233
234
## Performance Considerations
235
236
### Builder Reuse
237
238
```scala
239
import scala.collection.compat._
240
241
// Efficient batch processing with builder reuse
242
def batchProcess[From, A, C](
243
source: From,
244
batches: List[Iterable[A]]
245
)(implicit bf: BuildFrom[From, A, C]): List[C] = {
246
247
batches.map { batch =>
248
// Each batch gets a fresh builder from the same source context
249
val builder = bf.newBuilder(source)
250
builder ++= batch
251
builder.result()
252
}
253
}
254
```
255
256
### Memory Efficiency
257
258
```scala
259
import scala.collection.compat._
260
261
// Memory-efficient transformation that doesn't create intermediate collections
262
def streamingTransform[From, A, B, To](
263
source: From,
264
stream: Iterator[A]
265
)(f: A => B)(implicit bf: BuildFrom[From, B, To]): To = {
266
267
val builder = bf.newBuilder(source)
268
stream.foreach(a => builder += f(a))
269
builder.result()
270
}
271
```
272
273
## Integration with Standard Library
274
275
The `BuildFrom` abstraction integrates seamlessly with existing Scala collection operations:
276
277
```scala
278
import scala.collection.compat._
279
280
// Works with standard library transformations
281
val data = List(1, 2, 3, 4, 5)
282
283
// BuildFrom enables type-preserving operations
284
def filterMap[From, A, B, To](
285
collection: From with Iterable[A]
286
)(p: A => Boolean)(f: A => B)(implicit bf: BuildFrom[From, B, To]): To = {
287
bf.fromSpecificIterable(collection)(collection.filter(p).map(f))
288
}
289
290
val filtered = filterMap(data)(_ > 2)(_.toString)
291
// filtered: List[String] = List("3", "4", "5")
292
```
293
294
The `BuildFrom` abstraction provides a unified interface for collection building that works across Scala versions while maintaining the performance and type safety characteristics expected from the Scala collections library.