0
# Utility Features
1
2
Additional utilities including chaining operations, annotations for cross-compilation, enhanced regex functionality, and other helper features that improve code quality and cross-version compatibility.
3
4
## Capabilities
5
6
### Chaining Operations
7
8
Fluent interface methods that enable method chaining and functional programming patterns on any type.
9
10
```scala { .api }
11
/**
12
* Trait providing chaining syntax for all types
13
*/
14
trait ChainingSyntax {
15
/**
16
* Add chaining methods to any type
17
* @param a Value to add chaining methods to
18
* @return ChainingOps instance with chaining methods
19
*/
20
implicit final def scalaUtilChainingOps[A](a: A): ChainingOps[A]
21
}
22
23
/**
24
* Import target for chaining operations
25
*/
26
object chaining extends ChainingSyntax
27
28
/**
29
* Value class providing chaining methods
30
* @param self The wrapped value
31
*/
32
final class ChainingOps[A](self: A) extends AnyVal {
33
/**
34
* Apply side effect function and return original value
35
* Useful for debugging, logging, or other side effects in method chains
36
* @param f Side effect function
37
* @return Original value unchanged
38
*/
39
def tap[U](f: A => U): A
40
41
/**
42
* Transform value by applying function (alias for function application)
43
* Useful for applying transformations in a fluent style
44
* @param f Transformation function
45
* @return Transformed value
46
*/
47
def pipe[B](f: A => B): B
48
}
49
```
50
51
**Usage Examples:**
52
53
```scala
54
import scala.util.chaining._
55
56
// Basic tap usage for side effects
57
val result = List(1, 2, 3, 4, 5)
58
.filter(_ % 2 == 0)
59
.tap(filtered => println(s"After filter: $filtered"))
60
.map(_ * 2)
61
.tap(mapped => println(s"After map: $mapped"))
62
63
// Pipe for transformations
64
val processed = "hello world"
65
.pipe(_.split(" "))
66
.pipe(_.map(_.capitalize))
67
.pipe(_.mkString("-"))
68
// Result: "Hello-World"
69
70
// Debugging chains with tap
71
val calculation = 42
72
.tap(x => println(s"Starting with: $x"))
73
.pipe(_ * 2)
74
.tap(x => println(s"After doubling: $x"))
75
.pipe(_ + 10)
76
.tap(x => println(s"After adding 10: $x"))
77
// Result: 94
78
79
// Complex data processing pipeline
80
case class User(name: String, age: Int, email: String)
81
82
val users = List(
83
User("Alice", 25, "alice@example.com"),
84
User("Bob", 17, "bob@example.com"),
85
User("Charlie", 30, "charlie@example.com")
86
)
87
88
val processedUsers = users
89
.filter(_.age >= 18)
90
.tap(adults => println(s"Found ${adults.length} adult users"))
91
.sortBy(_.age)
92
.pipe(_.take(10)) // Top 10 by age
93
.map(user => user.copy(email = user.email.toLowerCase))
94
.tap(final => println(s"Final result: ${final.length} users"))
95
```
96
97
### Cross-Compilation Annotations
98
99
Annotations that facilitate cross-compilation between different Scala versions by suppressing warnings and marking unused code.
100
101
```scala { .api }
102
/**
103
* Local warning suppression annotation
104
* On Scala 2.13+: Suppresses compiler warnings locally
105
* On Scala 2.11: No functionality, but enables cross-compilation
106
* @param value Warning category to suppress (optional)
107
*/
108
class nowarn(value: String = "") extends scala.annotation.ClassfileAnnotation
109
110
/**
111
* Mark parameters or definitions as unused to suppress warnings
112
* Extends deprecated to suppress unused warnings across Scala versions
113
*/
114
final class unused extends deprecated("unused", "unused")
115
```
116
117
**Usage Examples:**
118
119
```scala
120
import scala.annotation.unused
121
122
// Suppress specific warnings
123
@nowarn("cat=deprecation")
124
def useDeprecatedApi(): Unit = {
125
// Use deprecated API without warnings
126
legacyLibrary.deprecatedMethod()
127
}
128
129
// Suppress all warnings in a scope
130
@nowarn
131
def experimentalCode(): Unit = {
132
// Experimental code with potential warnings
133
val x = unsafeOperation()
134
riskyTransformation(x)
135
}
136
137
// Mark unused parameters
138
def processData(data: List[String], @unused debugMode: Boolean): List[String] = {
139
// debugMode parameter is unused but kept for API compatibility
140
data.filter(_.nonEmpty).map(_.trim)
141
}
142
143
// Mark unused variables in pattern matching
144
def handleResponse(response: Either[Error, Success]): String = response match {
145
case Left(@unused error) => "Error occurred" // error details unused
146
case Right(success) => s"Success: ${success.message}"
147
}
148
149
// Mark unused imports (useful for cross-compilation)
150
import scala.collection.compat._ // @unused - needed for 2.11/2.12 but not 2.13
151
152
// Cross-version compatibility pattern
153
class CrossVersionService {
154
@nowarn("cat=unused")
155
private val compatImport = {
156
// Import needed for older Scala versions but unused in newer ones
157
import scala.collection.compat._
158
()
159
}
160
161
def processCollection[A](items: List[A]): Option[A] = {
162
items.maxOption // Available through compat import on older versions
163
}
164
}
165
```
166
167
### Enhanced Regex Operations
168
169
Additional regex functionality providing more intuitive matching operations.
170
171
```scala { .api }
172
/**
173
* Extension methods for Regex
174
* @param regex The regex to extend
175
*/
176
implicit class RegexOps(regex: Regex) {
177
/**
178
* Test if regex matches entire character sequence with anchoring
179
* More intuitive than findFirstIn for full string matching
180
* @param source Character sequence to test
181
* @return true if regex matches the entire sequence
182
*/
183
def matches(source: CharSequence): Boolean
184
}
185
```
186
187
**Usage Examples:**
188
189
```scala
190
import scala.util.matching.Regex
191
import scala.util.matching.compat._
192
193
val emailPattern = """[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}""".r
194
val phonePattern = """\d{3}-\d{3}-\d{4}""".r
195
196
// Full string matching
197
emailPattern.matches("user@example.com") // true
198
emailPattern.matches("not-an-email") // false
199
emailPattern.matches("user@example.com!") // false (extra character)
200
201
phonePattern.matches("555-123-4567") // true
202
phonePattern.matches("555-123-456") // false (too short)
203
204
// Validation functions
205
def isValidEmail(email: String): Boolean = {
206
emailPattern.matches(email)
207
}
208
209
def isValidPhoneNumber(phone: String): Boolean = {
210
phonePattern.matches(phone)
211
}
212
213
// Form validation
214
case class ContactForm(email: String, phone: String) {
215
def validate(): List[String] = {
216
val errors = List.newBuilder[String]
217
218
if (!emailPattern.matches(email)) {
219
errors += "Invalid email format"
220
}
221
222
if (!phonePattern.matches(phone)) {
223
errors += "Invalid phone number format"
224
}
225
226
errors.result()
227
}
228
}
229
230
// Pattern matching with validation
231
def processUserInput(input: String): String = input match {
232
case emailPattern.matches(_) if emailPattern.matches(input) => "Valid email"
233
case phonePattern.matches(_) if phonePattern.matches(input) => "Valid phone"
234
case _ => "Invalid format"
235
}
236
```
237
238
### Random Number Extensions
239
240
Enhanced random number generation with support for long ranges.
241
242
```scala { .api }
243
/**
244
* Extension methods for scala.util.Random
245
* @param self Random instance to extend
246
*/
247
final class RandomExtensions(self: Random) {
248
/**
249
* Generate random long in range [0, n)
250
* Extends Random to support long ranges beyond Int.MaxValue
251
* @param n Upper bound (exclusive)
252
* @return Random long between 0 (inclusive) and n (exclusive)
253
*/
254
def nextLong(n: Long): Long
255
}
256
```
257
258
**Usage Examples:**
259
260
```scala
261
import scala.util.Random
262
import scala.collection.compat._
263
264
val random = new Random()
265
266
// Generate random longs in large ranges
267
val bigRandomId = random.nextLong(1000000000000L) // 0 to 1 trillion
268
val timestampOffset = random.nextLong(86400000L) // 0 to 24 hours in milliseconds
269
270
// Generate random data for testing
271
def generateTestData(count: Int): List[TestRecord] = {
272
(1 to count).map { _ =>
273
TestRecord(
274
id = random.nextLong(Long.MaxValue),
275
timestamp = System.currentTimeMillis() + random.nextLong(86400000L),
276
value = random.nextDouble()
277
)
278
}.toList
279
}
280
281
// Random sampling from large datasets
282
def sampleLargeDataset[A](data: Vector[A], sampleSize: Int): List[A] = {
283
val indices = (1 to sampleSize).map(_ => random.nextLong(data.length.toLong).toInt).toSet
284
indices.map(data(_)).toList
285
}
286
```
287
288
### Factory and Collection Extensions
289
290
Additional factory methods and collection utilities for enhanced collection creation patterns.
291
292
```scala { .api }
293
/**
294
* Extension methods for Array companion object
295
* @param fact Array companion object
296
*/
297
class ArrayExtensions(fact: Array.type) {
298
/**
299
* Create array from collection
300
* @param source Source collection
301
* @param elemTag ClassTag for element type
302
* @return New array containing elements from source
303
*/
304
def from[A: ClassTag](source: TraversableOnce[A]): Array[A]
305
}
306
307
/**
308
* Extension methods for SortedMap companion object
309
* @param fact SortedMap companion object
310
*/
311
class ImmutableSortedMapExtensions(fact: immutable.SortedMap.type) {
312
/**
313
* Create SortedMap from collection of pairs
314
* @param source Source collection of key-value pairs
315
* @param ordering Ordering for keys
316
* @return New SortedMap containing pairs from source
317
*/
318
def from[K: Ordering, V](source: TraversableOnce[(K, V)]): immutable.SortedMap[K, V]
319
}
320
321
/**
322
* Extension methods for Option companion object
323
* @param fact Option companion object
324
*/
325
class OptionCompanionExtensionMethods(fact: Option.type) {
326
/**
327
* Create Option based on condition
328
* @param cond Condition to test
329
* @param a Value to wrap if condition is true (call-by-name)
330
* @return Some(a) if cond is true, None otherwise
331
*/
332
def when[A](cond: Boolean)(a: => A): Option[A]
333
334
/**
335
* Create Option based on negated condition
336
* @param cond Condition to test
337
* @param a Value to wrap if condition is false (call-by-name)
338
* @return Some(a) if cond is false, None otherwise
339
*/
340
def unless[A](cond: Boolean)(a: => A): Option[A]
341
}
342
```
343
344
**Usage Examples:**
345
346
```scala
347
import scala.collection.compat._
348
349
// Array creation from collections
350
val list = List(1, 2, 3, 4, 5)
351
val array = Array.from(list)
352
353
val stringArray = Array.from("hello".toCharArray.map(_.toString))
354
355
// SortedMap creation
356
val pairs = List("c" -> 3, "a" -> 1, "b" -> 2)
357
val sortedMap = immutable.SortedMap.from(pairs)
358
// Result: SortedMap("a" -> 1, "b" -> 2, "c" -> 3)
359
360
// Conditional Option creation
361
val userAge = 25
362
val drinkingAge = Option.when(userAge >= 21)(userAge) // Some(25)
363
val invalidAge = Option.when(userAge < 0)(userAge) // None
364
365
val message = Option.unless(userAge < 18)("Welcome, adult user!")
366
367
// Complex conditional logic
368
def processUser(user: User): Option[ProcessedUser] = {
369
Option.when(user.isActive && user.email.nonEmpty) {
370
ProcessedUser(
371
id = user.id,
372
name = user.name.trim,
373
email = user.email.toLowerCase,
374
lastLogin = user.lastLogin.getOrElse(Instant.now())
375
)
376
}
377
}
378
379
// Configuration-based instantiation
380
def createService(config: Config): Option[DatabaseService] = {
381
Option.when(config.databaseEnabled) {
382
new DatabaseService(
383
url = config.databaseUrl,
384
username = config.databaseUser,
385
password = config.databasePassword
386
)
387
}
388
}
389
```
390
391
### Size and Sorting Extensions
392
393
Enhanced operations for size checking and sorting on various collection types.
394
395
```scala { .api }
396
/**
397
* Extension methods for Sorted collections
398
* @param fact Sorted collection instance
399
*/
400
class SortedExtensionMethods[K, T <: Sorted[K, T]](fact: Sorted[K, T]) {
401
/**
402
* Elements from key onwards
403
* @param from Starting key (inclusive)
404
* @return Collection containing elements from key onwards
405
*/
406
def rangeFrom(from: K): T
407
408
/**
409
* Elements up to key
410
* @param to Ending key (inclusive)
411
* @return Collection containing elements up to key
412
*/
413
def rangeTo(to: K): T
414
415
/**
416
* Elements up to but not including key
417
* @param until Ending key (exclusive)
418
* @return Collection containing elements before key
419
*/
420
def rangeUntil(until: K): T
421
}
422
423
/**
424
* Extension methods for SortedMap instances
425
* @param self SortedMap to extend
426
*/
427
class SortedMapExtensionMethods[K, V](self: collection.SortedMap[K, V]) {
428
/**
429
* First entry after given key
430
* @param key Key to search after
431
* @return Some((key, value)) of first entry after key, None if not found
432
*/
433
def minAfter(key: K): Option[(K, V)]
434
435
/**
436
* Last entry before given key
437
* @param key Key to search before
438
* @return Some((key, value)) of last entry before key, None if not found
439
*/
440
def maxBefore(key: K): Option[(K, V)]
441
}
442
443
/**
444
* Extension methods for SortedSet instances
445
* @param self SortedSet to extend
446
*/
447
class SortedSetExtensionMethods[A](self: collection.SortedSet[A]) {
448
/**
449
* First element after given key
450
* @param key Key to search after
451
* @return Some(element) of first element after key, None if not found
452
*/
453
def minAfter(key: A): Option[A]
454
455
/**
456
* Last element before given key
457
* @param key Key to search before
458
* @return Some(element) of last element before key, None if not found
459
*/
460
def maxBefore(key: A): Option[A]
461
}
462
```
463
464
**Usage Examples:**
465
466
```scala
467
import scala.collection.compat._
468
import scala.collection.{SortedMap, SortedSet}
469
470
// Sorted collection range operations
471
val sortedNumbers = SortedSet(1, 3, 5, 7, 9, 11, 13, 15)
472
473
val fromFive = sortedNumbers.rangeFrom(5) // SortedSet(5, 7, 9, 11, 13, 15)
474
val upToTen = sortedNumbers.rangeTo(10) // SortedSet(1, 3, 5, 7, 9)
475
val beforeTen = sortedNumbers.rangeUntil(10) // SortedSet(1, 3, 5, 7, 9)
476
477
// SortedMap neighbor searches
478
val scores = SortedMap("Alice" -> 95, "Bob" -> 87, "Charlie" -> 92, "Diana" -> 98)
479
480
val nextAfterBob = scores.minAfter("Bob") // Some(("Charlie", 92))
481
val prevBeforeCharlie = scores.maxBefore("Charlie") // Some(("Bob", 87))
482
483
// SortedSet neighbor searches
484
val timestamps = SortedSet(100L, 200L, 300L, 400L, 500L)
485
486
val nextAfter250 = timestamps.minAfter(250L) // Some(300L)
487
val prevBefore350 = timestamps.maxBefore(350L) // Some(300L)
488
489
// Range-based querying
490
def findScoresInRange(scores: SortedMap[String, Int],
491
minScore: Int,
492
maxScore: Int): Map[String, Int] = {
493
scores.filter { case (_, score) => score >= minScore && score <= maxScore }
494
}
495
496
// Time-based operations
497
case class Event(timestamp: Long, data: String)
498
499
def findEventsAfter(events: SortedSet[Event], afterTime: Long): Option[Event] = {
500
implicit val eventOrdering: Ordering[Event] = Ordering.by(_.timestamp)
501
val dummyEvent = Event(afterTime, "")
502
events.minAfter(dummyEvent)
503
}
504
```
505
506
These utility features provide essential cross-compilation support, enhanced debugging capabilities, and improved collection operations that make Scala code more maintainable and functional across different versions.