or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

annotations.mdcompile-time.mdgeneric-programming.mdimmutable-arrays.mdindex.mdmacros.mdstructural-types.mdtuples.mdtype-safe-equality.md
tile.json

immutable-arrays.mddocs/

Immutable Arrays

IArray provides covariant immutable arrays with rich collection operations, combining the performance characteristics of arrays with immutability guarantees.

Core API

IArray Type

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.

Element Access

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): T

Specialized element access methods for primitive types and generic access for all types.

Size Operations

extension [T](arr: IArray[T]):
  def length: Int
  def size: Int
  def isEmpty: Boolean
  def nonEmpty: Boolean
  def indices: Range

Basic size and emptiness checking operations.

Transformation Operations

Mapping and Filtering

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.

Scanning and Folding

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): U

Accumulation operations for computing single values or progressive results.

Slicing and Selection

Element Selection

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.

Slicing Operations

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.

Search and Query Operations

Element Search

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): Int

Methods for finding elements and their positions.

Predicate Testing

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): Int

Testing elements against predicates.

Combination Operations

Array Combination

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.

Set-like Operations

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]

Sorting and Ordering

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.

Conversion Operations

Collection Conversions

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.

Array Conversions

extension [T](arr: IArray[T]):
  @deprecated("Use IArray.genericWrapArray(myIArray).toArray instead")
  def toArray: Array[T]

Implicit Conversions to ArraySeq

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.ofUnit

Factory Methods

Basic Construction

object 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]

Generation Methods

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]

Unsafe Construction

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.

Usage Examples

Basic Operations

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)

Transformations

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)

Slicing and Selection

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"))

Search and Query

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)             // 2

Combining Arrays

val 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)

Sorting and Ordering

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)

Advanced Operations

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)

Conversion and Iteration

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 Operations and Performance

// 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).toArray

IArray 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.