Additional utilities including chaining operations, annotations for cross-compilation, enhanced regex functionality, and other helper features that improve code quality and cross-version compatibility.
Fluent interface methods that enable method chaining and functional programming patterns on any type.
/**
* Trait providing chaining syntax for all types
*/
trait ChainingSyntax {
/**
* Add chaining methods to any type
* @param a Value to add chaining methods to
* @return ChainingOps instance with chaining methods
*/
implicit final def scalaUtilChainingOps[A](a: A): ChainingOps[A]
}
/**
* Import target for chaining operations
*/
object chaining extends ChainingSyntax
/**
* Value class providing chaining methods
* @param self The wrapped value
*/
final class ChainingOps[A](self: A) extends AnyVal {
/**
* Apply side effect function and return original value
* Useful for debugging, logging, or other side effects in method chains
* @param f Side effect function
* @return Original value unchanged
*/
def tap[U](f: A => U): A
/**
* Transform value by applying function (alias for function application)
* Useful for applying transformations in a fluent style
* @param f Transformation function
* @return Transformed value
*/
def pipe[B](f: A => B): B
}Usage Examples:
import scala.util.chaining._
// Basic tap usage for side effects
val result = List(1, 2, 3, 4, 5)
.filter(_ % 2 == 0)
.tap(filtered => println(s"After filter: $filtered"))
.map(_ * 2)
.tap(mapped => println(s"After map: $mapped"))
// Pipe for transformations
val processed = "hello world"
.pipe(_.split(" "))
.pipe(_.map(_.capitalize))
.pipe(_.mkString("-"))
// Result: "Hello-World"
// Debugging chains with tap
val calculation = 42
.tap(x => println(s"Starting with: $x"))
.pipe(_ * 2)
.tap(x => println(s"After doubling: $x"))
.pipe(_ + 10)
.tap(x => println(s"After adding 10: $x"))
// Result: 94
// Complex data processing pipeline
case class User(name: String, age: Int, email: String)
val users = List(
User("Alice", 25, "alice@example.com"),
User("Bob", 17, "bob@example.com"),
User("Charlie", 30, "charlie@example.com")
)
val processedUsers = users
.filter(_.age >= 18)
.tap(adults => println(s"Found ${adults.length} adult users"))
.sortBy(_.age)
.pipe(_.take(10)) // Top 10 by age
.map(user => user.copy(email = user.email.toLowerCase))
.tap(final => println(s"Final result: ${final.length} users"))Annotations that facilitate cross-compilation between different Scala versions by suppressing warnings and marking unused code.
/**
* Local warning suppression annotation
* On Scala 2.13+: Suppresses compiler warnings locally
* On Scala 2.11: No functionality, but enables cross-compilation
* @param value Warning category to suppress (optional)
*/
class nowarn(value: String = "") extends scala.annotation.ClassfileAnnotation
/**
* Mark parameters or definitions as unused to suppress warnings
* Extends deprecated to suppress unused warnings across Scala versions
*/
final class unused extends deprecated("unused", "unused")Usage Examples:
import scala.annotation.unused
// Suppress specific warnings
@nowarn("cat=deprecation")
def useDeprecatedApi(): Unit = {
// Use deprecated API without warnings
legacyLibrary.deprecatedMethod()
}
// Suppress all warnings in a scope
@nowarn
def experimentalCode(): Unit = {
// Experimental code with potential warnings
val x = unsafeOperation()
riskyTransformation(x)
}
// Mark unused parameters
def processData(data: List[String], @unused debugMode: Boolean): List[String] = {
// debugMode parameter is unused but kept for API compatibility
data.filter(_.nonEmpty).map(_.trim)
}
// Mark unused variables in pattern matching
def handleResponse(response: Either[Error, Success]): String = response match {
case Left(@unused error) => "Error occurred" // error details unused
case Right(success) => s"Success: ${success.message}"
}
// Mark unused imports (useful for cross-compilation)
import scala.collection.compat._ // @unused - needed for 2.11/2.12 but not 2.13
// Cross-version compatibility pattern
class CrossVersionService {
@nowarn("cat=unused")
private val compatImport = {
// Import needed for older Scala versions but unused in newer ones
import scala.collection.compat._
()
}
def processCollection[A](items: List[A]): Option[A] = {
items.maxOption // Available through compat import on older versions
}
}Additional regex functionality providing more intuitive matching operations.
/**
* Extension methods for Regex
* @param regex The regex to extend
*/
implicit class RegexOps(regex: Regex) {
/**
* Test if regex matches entire character sequence with anchoring
* More intuitive than findFirstIn for full string matching
* @param source Character sequence to test
* @return true if regex matches the entire sequence
*/
def matches(source: CharSequence): Boolean
}Usage Examples:
import scala.util.matching.Regex
import scala.util.matching.compat._
val emailPattern = """[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}""".r
val phonePattern = """\d{3}-\d{3}-\d{4}""".r
// Full string matching
emailPattern.matches("user@example.com") // true
emailPattern.matches("not-an-email") // false
emailPattern.matches("user@example.com!") // false (extra character)
phonePattern.matches("555-123-4567") // true
phonePattern.matches("555-123-456") // false (too short)
// Validation functions
def isValidEmail(email: String): Boolean = {
emailPattern.matches(email)
}
def isValidPhoneNumber(phone: String): Boolean = {
phonePattern.matches(phone)
}
// Form validation
case class ContactForm(email: String, phone: String) {
def validate(): List[String] = {
val errors = List.newBuilder[String]
if (!emailPattern.matches(email)) {
errors += "Invalid email format"
}
if (!phonePattern.matches(phone)) {
errors += "Invalid phone number format"
}
errors.result()
}
}
// Pattern matching with validation
def processUserInput(input: String): String = input match {
case emailPattern.matches(_) if emailPattern.matches(input) => "Valid email"
case phonePattern.matches(_) if phonePattern.matches(input) => "Valid phone"
case _ => "Invalid format"
}Enhanced random number generation with support for long ranges.
/**
* Extension methods for scala.util.Random
* @param self Random instance to extend
*/
final class RandomExtensions(self: Random) {
/**
* Generate random long in range [0, n)
* Extends Random to support long ranges beyond Int.MaxValue
* @param n Upper bound (exclusive)
* @return Random long between 0 (inclusive) and n (exclusive)
*/
def nextLong(n: Long): Long
}Usage Examples:
import scala.util.Random
import scala.collection.compat._
val random = new Random()
// Generate random longs in large ranges
val bigRandomId = random.nextLong(1000000000000L) // 0 to 1 trillion
val timestampOffset = random.nextLong(86400000L) // 0 to 24 hours in milliseconds
// Generate random data for testing
def generateTestData(count: Int): List[TestRecord] = {
(1 to count).map { _ =>
TestRecord(
id = random.nextLong(Long.MaxValue),
timestamp = System.currentTimeMillis() + random.nextLong(86400000L),
value = random.nextDouble()
)
}.toList
}
// Random sampling from large datasets
def sampleLargeDataset[A](data: Vector[A], sampleSize: Int): List[A] = {
val indices = (1 to sampleSize).map(_ => random.nextLong(data.length.toLong).toInt).toSet
indices.map(data(_)).toList
}Additional factory methods and collection utilities for enhanced collection creation patterns.
/**
* Extension methods for Array companion object
* @param fact Array companion object
*/
class ArrayExtensions(fact: Array.type) {
/**
* Create array from collection
* @param source Source collection
* @param elemTag ClassTag for element type
* @return New array containing elements from source
*/
def from[A: ClassTag](source: TraversableOnce[A]): Array[A]
}
/**
* Extension methods for SortedMap companion object
* @param fact SortedMap companion object
*/
class ImmutableSortedMapExtensions(fact: immutable.SortedMap.type) {
/**
* Create SortedMap from collection of pairs
* @param source Source collection of key-value pairs
* @param ordering Ordering for keys
* @return New SortedMap containing pairs from source
*/
def from[K: Ordering, V](source: TraversableOnce[(K, V)]): immutable.SortedMap[K, V]
}
/**
* Extension methods for Option companion object
* @param fact Option companion object
*/
class OptionCompanionExtensionMethods(fact: Option.type) {
/**
* Create Option based on condition
* @param cond Condition to test
* @param a Value to wrap if condition is true (call-by-name)
* @return Some(a) if cond is true, None otherwise
*/
def when[A](cond: Boolean)(a: => A): Option[A]
/**
* Create Option based on negated condition
* @param cond Condition to test
* @param a Value to wrap if condition is false (call-by-name)
* @return Some(a) if cond is false, None otherwise
*/
def unless[A](cond: Boolean)(a: => A): Option[A]
}Usage Examples:
import scala.collection.compat._
// Array creation from collections
val list = List(1, 2, 3, 4, 5)
val array = Array.from(list)
val stringArray = Array.from("hello".toCharArray.map(_.toString))
// SortedMap creation
val pairs = List("c" -> 3, "a" -> 1, "b" -> 2)
val sortedMap = immutable.SortedMap.from(pairs)
// Result: SortedMap("a" -> 1, "b" -> 2, "c" -> 3)
// Conditional Option creation
val userAge = 25
val drinkingAge = Option.when(userAge >= 21)(userAge) // Some(25)
val invalidAge = Option.when(userAge < 0)(userAge) // None
val message = Option.unless(userAge < 18)("Welcome, adult user!")
// Complex conditional logic
def processUser(user: User): Option[ProcessedUser] = {
Option.when(user.isActive && user.email.nonEmpty) {
ProcessedUser(
id = user.id,
name = user.name.trim,
email = user.email.toLowerCase,
lastLogin = user.lastLogin.getOrElse(Instant.now())
)
}
}
// Configuration-based instantiation
def createService(config: Config): Option[DatabaseService] = {
Option.when(config.databaseEnabled) {
new DatabaseService(
url = config.databaseUrl,
username = config.databaseUser,
password = config.databasePassword
)
}
}Enhanced operations for size checking and sorting on various collection types.
/**
* Extension methods for Sorted collections
* @param fact Sorted collection instance
*/
class SortedExtensionMethods[K, T <: Sorted[K, T]](fact: Sorted[K, T]) {
/**
* Elements from key onwards
* @param from Starting key (inclusive)
* @return Collection containing elements from key onwards
*/
def rangeFrom(from: K): T
/**
* Elements up to key
* @param to Ending key (inclusive)
* @return Collection containing elements up to key
*/
def rangeTo(to: K): T
/**
* Elements up to but not including key
* @param until Ending key (exclusive)
* @return Collection containing elements before key
*/
def rangeUntil(until: K): T
}
/**
* Extension methods for SortedMap instances
* @param self SortedMap to extend
*/
class SortedMapExtensionMethods[K, V](self: collection.SortedMap[K, V]) {
/**
* First entry after given key
* @param key Key to search after
* @return Some((key, value)) of first entry after key, None if not found
*/
def minAfter(key: K): Option[(K, V)]
/**
* Last entry before given key
* @param key Key to search before
* @return Some((key, value)) of last entry before key, None if not found
*/
def maxBefore(key: K): Option[(K, V)]
}
/**
* Extension methods for SortedSet instances
* @param self SortedSet to extend
*/
class SortedSetExtensionMethods[A](self: collection.SortedSet[A]) {
/**
* First element after given key
* @param key Key to search after
* @return Some(element) of first element after key, None if not found
*/
def minAfter(key: A): Option[A]
/**
* Last element before given key
* @param key Key to search before
* @return Some(element) of last element before key, None if not found
*/
def maxBefore(key: A): Option[A]
}Usage Examples:
import scala.collection.compat._
import scala.collection.{SortedMap, SortedSet}
// Sorted collection range operations
val sortedNumbers = SortedSet(1, 3, 5, 7, 9, 11, 13, 15)
val fromFive = sortedNumbers.rangeFrom(5) // SortedSet(5, 7, 9, 11, 13, 15)
val upToTen = sortedNumbers.rangeTo(10) // SortedSet(1, 3, 5, 7, 9)
val beforeTen = sortedNumbers.rangeUntil(10) // SortedSet(1, 3, 5, 7, 9)
// SortedMap neighbor searches
val scores = SortedMap("Alice" -> 95, "Bob" -> 87, "Charlie" -> 92, "Diana" -> 98)
val nextAfterBob = scores.minAfter("Bob") // Some(("Charlie", 92))
val prevBeforeCharlie = scores.maxBefore("Charlie") // Some(("Bob", 87))
// SortedSet neighbor searches
val timestamps = SortedSet(100L, 200L, 300L, 400L, 500L)
val nextAfter250 = timestamps.minAfter(250L) // Some(300L)
val prevBefore350 = timestamps.maxBefore(350L) // Some(300L)
// Range-based querying
def findScoresInRange(scores: SortedMap[String, Int],
minScore: Int,
maxScore: Int): Map[String, Int] = {
scores.filter { case (_, score) => score >= minScore && score <= maxScore }
}
// Time-based operations
case class Event(timestamp: Long, data: String)
def findEventsAfter(events: SortedSet[Event], afterTime: Long): Option[Event] = {
implicit val eventOrdering: Ordering[Event] = Ordering.by(_.timestamp)
val dummyEvent = Event(afterTime, "")
events.minAfter(dummyEvent)
}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.