or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

arrayseq.mdbuildfrom.mdcollection-extensions.mdfactory-operations.mdindex.mdmigration-tools.md

buildfrom.mddocs/

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.