IArray provides covariant immutable arrays with rich collection operations, combining the performance characteristics of arrays with immutability guarantees.
opaque type IArray[+T] = Array[? <: T]An immutable array that has the same representation as Array[T] but cannot be updated. Unlike regular arrays, immutable arrays are covariant.
extension (arr: IArray[Byte]) def apply(n: Int): Byte
extension (arr: IArray[Short]) def apply(n: Int): Short
extension (arr: IArray[Char]) def apply(n: Int): Char
extension (arr: IArray[Int]) def apply(n: Int): Int
extension (arr: IArray[Long]) def apply(n: Int): Long
extension (arr: IArray[Float]) def apply(n: Int): Float
extension (arr: IArray[Double]) def apply(n: Int): Double
extension [T <: Object](arr: IArray[T]) def apply(n: Int): T
extension [T](arr: IArray[T]) def apply(n: Int): TSpecialized element access methods for primitive types and generic access for all types.
extension [T](arr: IArray[T]):
def length: Int
def size: Int
def isEmpty: Boolean
def nonEmpty: Boolean
def indices: RangeBasic size and emptiness checking operations.
extension [T](arr: IArray[T]):
def map[U: ClassTag](f: T => U): IArray[U]
def flatMap[U: ClassTag](f: T => IterableOnce[U]): IArray[U]
def filter(p: T => Boolean): IArray[T]
def filterNot(p: T => Boolean): IArray[T]
def collect[U: ClassTag](pf: PartialFunction[T, U]): IArray[U]Standard functional operations that return new immutable arrays.
extension [T](arr: IArray[T]):
def scan[U >: T: ClassTag](z: U)(op: (U, U) => U): IArray[U]
def scanLeft[U: ClassTag](z: U)(op: (U, T) => U): IArray[U]
def scanRight[U: ClassTag](z: U)(op: (T, U) => U): IArray[U]
def fold[U >: T](z: U)(op: (U, U) => U): U
def foldLeft[U](z: U)(op: (U, T) => U): U
def foldRight[U](z: U)(op: (T, U) => U): UAccumulation operations for computing single values or progressive results.
extension [T](arr: IArray[T]):
def head: T
def headOption: Option[T]
def last: T
def lastOption: Option[T]
def tail: IArray[T]
def init: IArray[T]Operations for accessing first, last, and boundary elements.
extension [T](arr: IArray[T]):
def take(n: Int): IArray[T]
def takeRight(n: Int): IArray[T]
def takeWhile(p: T => Boolean): IArray[T]
def drop(n: Int): IArray[T]
def dropRight(n: Int): IArray[T]
def dropWhile(p: T => Boolean): IArray[T]
def slice(from: Int, until: Int): IArray[T]
def splitAt(n: Int): (IArray[T], IArray[T])Operations for extracting subsequences and splitting arrays.
extension [T](arr: IArray[T]):
def contains(elem: T): Boolean
def indexOf(elem: T, from: Int = 0): Int
def lastIndexOf(elem: T, end: Int = arr.length - 1): Int
def indexWhere(p: T => Boolean, from: Int = 0): Int
def lastIndexWhere(p: T => Boolean, end: Int = arr.length - 1): IntMethods for finding elements and their positions.
extension [T](arr: IArray[T]):
def exists(p: T => Boolean): Boolean
def forall(p: T => Boolean): Boolean
def find(p: T => Boolean): Option[T]
def count(p: T => Boolean): IntTesting elements against predicates.
extension [T](arr: IArray[T]):
def ++[U >: T: ClassTag](suffix: IArray[U]): IArray[U]
def ++[U >: T: ClassTag](suffix: IterableOnce[U]): IArray[U]
def :+[U >: T: ClassTag](x: U): IArray[U]
def +:+[U >: T: ClassTag](suffix: IArray[U]): IArray[U]
def appended[U >: T: ClassTag](x: U): IArray[U]
def appendedAll[U >: T: ClassTag](suffix: IterableOnce[U]): IArray[U]
def prepended[U >: T: ClassTag](x: U): IArray[U]
def prependedAll[U >: T: ClassTag](prefix: IterableOnce[U]): IArray[U]
def concat[U >: T: ClassTag](suffix: IterableOnce[U]): IArray[U]Operations for combining arrays and adding elements.
extension [T](arr: IArray[T]):
def diff[U >: T](that: IArray[U]): IArray[T]
def diff[U >: T](that: Seq[U]): IArray[T]
def intersect[U >: T](that: IArray[U]): IArray[T]
def intersect[U >: T](that: Seq[U]): IArray[T]
def distinct: IArray[T]
def distinctBy[U](f: T => U): IArray[T]extension [T](arr: IArray[T]):
def sorted(using math.Ordering[T]): IArray[T]
def sortBy[U](f: T => U)(using math.Ordering[U]): IArray[T]
def sortWith(f: (T, T) => Boolean): IArray[T]
def reverse: IArray[T]Sorting operations that return new sorted arrays.
extension [T](arr: IArray[T]):
def iterator: Iterator[T]
def reverseIterator: Iterator[T]
def toSeq: Seq[T]
def toList: List[T]
def toVector: Vector[T]
def toSet: Set[T]Convert to other collection types.
extension [T](arr: IArray[T]):
@deprecated("Use IArray.genericWrapArray(myIArray).toArray instead")
def toArray: Array[T]implicit def genericWrapArray[T](arr: IArray[T]): ArraySeq[T]
implicit def wrapRefArray[T <: AnyRef](arr: IArray[T]): ArraySeq.ofRef[T]
implicit def wrapIntArray(arr: IArray[Int]): ArraySeq.ofInt
implicit def wrapDoubleIArray(arr: IArray[Double]): ArraySeq.ofDouble
implicit def wrapLongIArray(arr: IArray[Long]): ArraySeq.ofLong
implicit def wrapFloatIArray(arr: IArray[Float]): ArraySeq.ofFloat
implicit def wrapCharIArray(arr: IArray[Char]): ArraySeq.ofChar
implicit def wrapByteIArray(arr: IArray[Byte]): ArraySeq.ofByte
implicit def wrapShortIArray(arr: IArray[Short]): ArraySeq.ofShort
implicit def wrapBooleanIArray(arr: IArray[Boolean]): ArraySeq.ofBoolean
implicit def wrapUnitIArray(arr: IArray[Unit]): ArraySeq.ofUnitobject IArray:
def empty[T: ClassTag]: IArray[T]
def apply[T: ClassTag](xs: T*): IArray[T]
def apply(x: Boolean, xs: Boolean*): IArray[Boolean]
def apply(x: Byte, xs: Byte*): IArray[Byte]
def apply(x: Short, xs: Short*): IArray[Short]
def apply(x: Char, xs: Char*): IArray[Char]
def apply(x: Int, xs: Int*): IArray[Int]
def apply(x: Long, xs: Long*): IArray[Long]
def apply(x: Float, xs: Float*): IArray[Float]
def apply(x: Double, xs: Double*): IArray[Double]
def apply(x: Unit, xs: Unit*): IArray[Unit]def from[A: ClassTag](it: IterableOnce[A]): IArray[A]
def fill[T: ClassTag](n: Int)(elem: => T): IArray[T]
def fill[T: ClassTag](n1: Int, n2: Int)(elem: => T): IArray[IArray[T]]
def tabulate[T: ClassTag](n: Int)(f: Int => T): IArray[T]
def tabulate[T: ClassTag](n1: Int, n2: Int)(f: (Int, Int) => T): IArray[IArray[T]]
def range(start: Int, end: Int): IArray[Int]
def range(start: Int, end: Int, step: Int): IArray[Int]
def iterate[T: ClassTag](start: T, len: Int)(f: T => T): IArray[T]
def concat[T: ClassTag](xss: IArray[T]*): IArray[T]def unsafeFromArray[T](s: Array[T]): IArray[T]Convert an array to immutable array without copying. The original array must not be mutated after this call.
import scala.*
// Creating arrays
val empty = IArray.empty[Int]
val numbers = IArray(1, 2, 3, 4, 5)
val fromRange = IArray.range(1, 10)
val filled = IArray.fill(5)("hello")
// Element access
val first = numbers.head // 1
val last = numbers.last // 5
val third = numbers(2) // 3
val maybeFirst = numbers.headOption // Some(1)
// Basic properties
val size = numbers.length // 5
val isEmpty = numbers.isEmpty // false
val indices = numbers.indices // Range(0, 1, 2, 3, 4)val numbers = IArray(1, 2, 3, 4, 5)
// Mapping
val doubled = numbers.map(_ * 2) // IArray(2, 4, 6, 8, 10)
val strings = numbers.map(_.toString) // IArray("1", "2", "3", "4", "5")
// Filtering
val evens = numbers.filter(_ % 2 == 0) // IArray(2, 4)
val odds = numbers.filterNot(_ % 2 == 0) // IArray(1, 3, 5)
// Flat mapping
val expanded = numbers.flatMap(n => IArray.fill(n)(n))
// IArray(1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5)
// Collecting with partial functions
val evenDoubled = numbers.collect { case n if n % 2 == 0 => n * 2 }
// IArray(4, 8)val data = IArray("a", "b", "c", "d", "e")
// Taking and dropping
val firstThree = data.take(3) // IArray("a", "b", "c")
val lastTwo = data.takeRight(2) // IArray("d", "e")
val skipFirst = data.drop(1) // IArray("b", "c", "d", "e")
val skipFirstTwo = data.drop(2) // IArray("c", "d", "e")
// Conditional taking/dropping
val letters = IArray("a", "b", "c", "1", "2")
val onlyLetters = letters.takeWhile(_.forall(_.isLetter)) // IArray("a", "b", "c")
// Slicing
val middle = data.slice(1, 4) // IArray("b", "c", "d")
val (left, right) = data.splitAt(2) // (IArray("a", "b"), IArray("c", "d", "e"))val values = IArray(10, 20, 30, 20, 40)
// Finding elements
val contains20 = values.contains(20) // true
val firstIndex = values.indexOf(20) // 1
val lastIndex = values.lastIndexOf(20) // 3
val indexOver25 = values.indexWhere(_ > 25) // 2
// Predicate testing
val hasLarge = values.exists(_ > 35) // true
val allPositive = values.forall(_ > 0) // true
val firstLarge = values.find(_ > 25) // Some(30)
val countLarge = values.count(_ > 25) // 2val arr1 = IArray(1, 2, 3)
val arr2 = IArray(4, 5, 6)
val list = List(7, 8, 9)
// Concatenation
val combined = arr1 ++ arr2 // IArray(1, 2, 3, 4, 5, 6)
val withList = arr1 ++ list // IArray(1, 2, 3, 7, 8, 9)
// Adding single elements
val withZero = 0 +: arr1 // IArray(0, 1, 2, 3)
val withTen = arr1 :+ 10 // IArray(1, 2, 3, 10)
// Prepending/appending collections
val prefixed = IArray(-2, -1) ++: arr1 // IArray(-2, -1, 1, 2, 3)
val suffixed = arr1 :++ IArray(10, 11) // IArray(1, 2, 3, 10, 11)val unsorted = IArray(3, 1, 4, 1, 5, 9, 2)
// Natural ordering
val sorted = unsorted.sorted // IArray(1, 1, 2, 3, 4, 5, 9)
// Custom ordering
val descending = unsorted.sortWith(_ > _) // IArray(9, 5, 4, 3, 2, 1, 1)
// Sort by transformation
val words = IArray("hello", "hi", "world", "a")
val byLength = words.sortBy(_.length) // IArray("a", "hi", "hello", "world")
// Reverse
val reversed = sorted.reverse // IArray(9, 5, 4, 3, 2, 1, 1)val data = IArray(1, 2, 3, 4, 5)
// Scanning (cumulative operations)
val cumSum = data.scanLeft(0)(_ + _) // IArray(0, 1, 3, 6, 10, 15)
val cumProduct = data.scanLeft(1)(_ * _) // IArray(1, 1, 2, 6, 24, 120)
// Folding (reduction to single value)
val sum = data.foldLeft(0)(_ + _) // 15
val product = data.foldRight(1)(_ * _) // 120
// Grouping and partitioning
val mixed = IArray(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val (evens, odds) = mixed.partition(_ % 2 == 0)
// evens: IArray(2, 4, 6, 8, 10), odds: IArray(1, 3, 5, 7, 9)
// Set operations
val set1 = IArray(1, 2, 3, 4)
val set2 = IArray(3, 4, 5, 6)
val intersection = set1.intersect(set2) // IArray(3, 4)
val difference = set1.diff(set2) // IArray(1, 2)
val unique = IArray(1, 2, 2, 3, 3, 3).distinct // IArray(1, 2, 3)val arr = IArray("a", "b", "c", "d")
// To other collections
val list = arr.toList // List("a", "b", "c", "d")
val vector = arr.toVector // Vector("a", "b", "c", "d")
val set = arr.toSet // Set("a", "b", "c", "d")
// Iteration
arr.foreach(println) // Prints each element
val iterator = arr.iterator // Iterator for traversal
val reverseIter = arr.reverseIterator // Reverse iterator
// Side effects
arr.foreach(x => println(s"Element: $x"))// Unsafe conversion from mutable array (use with caution)
val mutableArray = Array(1, 2, 3, 4, 5)
val immutableArray = IArray.unsafeFromArray(mutableArray)
// Warning: Do not modify mutableArray after this point!
// Efficient conversion through ArraySeq
val properConversion = IArray.genericWrapArray(immutableArray).toArrayIArray provides a complete immutable array implementation with excellent performance characteristics and a rich API that integrates seamlessly with Scala's collection library while maintaining type safety and immutability guarantees.