Skip to content

MutableList.ts

Mutable lists for collecting ordered values and draining them from the front. A MutableList<A> can append values to the end, prepend values to the beginning, take one or more values from the front, inspect its contents as an array, filter values, remove values, and clear itself. All operations update the same list object in place and keep its length field current. Taking from an empty list returns the Empty symbol.

Since v4.0.0



Creates an empty MutableList.

Example (Creating an empty mutable list)

import { MutableList } from "effect"
const list = MutableList.make<string>()
// Add elements
MutableList.append(list, "first")
MutableList.append(list, "second")
MutableList.prepend(list, "beginning")
console.log(list.length) // 3
// Take elements in FIFO order (from head)
console.log(MutableList.take(list)) // "beginning"
console.log(MutableList.take(list)) // "first"
console.log(MutableList.take(list)) // "second"

Signature

declare const make: <A>() => MutableList<A>

Source

Since v2.0.0

Takes a single element from the beginning of the MutableList. Returns the element if available, or the Empty symbol if the list is empty. The taken element is removed from the list.

Example (Taking one element)

import { MutableList } from "effect"
const list = MutableList.make<string>()
MutableList.appendAll(list, ["first", "second", "third"])
// Take elements one by one
console.log(MutableList.take(list)) // "first"
console.log(list.length) // 2
console.log(MutableList.take(list)) // "second"
console.log(MutableList.take(list)) // "third"
console.log(list.length) // 0
// Take from empty list
console.log(MutableList.take(list)) // Empty symbol
// Check for empty using the Empty symbol
const result = MutableList.take(list)
if (result === MutableList.Empty) {
console.log("List is empty")
} else {
console.log("Got element:", result)
}
// Consumer pattern
function processNext<T>(queue: MutableList.MutableList<T>, processor: (item: T) => void): boolean {
const item = MutableList.take(queue)
if (item !== MutableList.Empty) {
processor(item)
return true
}
return false
}

Signature

declare const take: <A>(self: MutableList<A>) => Empty | A

Source

Since v4.0.0

Takes all elements from the MutableList and returns them as an array. The list becomes empty after this operation. This is equivalent to takeN(list, list.length).

Example (Draining all elements)

import { MutableList } from "effect"
const list = MutableList.make<string>()
MutableList.appendAll(list, ["apple", "banana", "cherry"])
console.log(list.length) // 3
// Take all elements
const allItems = MutableList.takeAll(list)
console.log(allItems) // ["apple", "banana", "cherry"]
console.log(list.length) // 0
// Useful for converting to array and clearing
const queue = MutableList.make<number>()
MutableList.appendAll(queue, [1, 2, 3, 4, 5])
const snapshot = MutableList.takeAll(queue)
console.log("Queue contents:", snapshot)
console.log("Queue is now empty:", queue.length === 0)
// Drain pattern for processing
function drainAndProcess<T>(list: MutableList.MutableList<T>, processor: (items: Array<T>) => void) {
if (list.length > 0) {
const items = MutableList.takeAll(list)
processor(items)
}
}

Signature

declare const takeAll: <A>(self: MutableList<A>) => Array<A>

Source

Since v4.0.0

Takes up to N elements from the beginning of the MutableList and returns them as an array. The taken elements are removed from the list. This operation is optimized for performance and includes zero-copy optimizations when possible.

Example (Taking batches)

import { MutableList } from "effect"
const list = MutableList.make<number>()
MutableList.appendAll(list, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
console.log(list.length) // 10
// Take first 3 elements
const first3 = MutableList.takeN(list, 3)
console.log(first3) // [1, 2, 3]
console.log(list.length) // 7
// Take more than available
const remaining = MutableList.takeN(list, 20)
console.log(remaining) // [4, 5, 6, 7, 8, 9, 10]
console.log(list.length) // 0
// Take from empty list
const empty = MutableList.takeN(list, 5)
console.log(empty) // []
// Batch processing pattern
const queue = MutableList.make<string>()
MutableList.appendAll(queue, ["task1", "task2", "task3", "task4", "task5"])
while (queue.length > 0) {
const batch = MutableList.takeN(queue, 2) // Process 2 at a time
console.log("Processing batch:", batch)
}

Signature

declare const takeN: <A>(self: MutableList<A>, n: number) => Array<A>

Source

Since v4.0.0

Removes up to n elements from the beginning of the MutableList without returning them.

When to use

Use to discard a bounded number of values from the head of a MutableList when the removed values are not needed.

Details

If n is less than or equal to zero, or the list is empty, the list is left unchanged. If n is greater than or equal to the current length, the list is cleared.

See

  • takeN for removing up to n values and returning them as an array
  • clear for removing every value from the list

Signature

declare const takeNVoid: <A>(self: MutableList<A>, n: number) => void

Source

Since v4.0.0

Copies all current elements of the MutableList into a new array without modifying the list.

When to use

Use when you need a snapshot of all current elements while keeping the list unchanged.

See

  • takeAll for converting all elements to an array and clearing the list

Signature

declare const toArray: <A>(self: MutableList<A>) => Array<A>

Source

Since v4.0.0

Copies up to n elements from the beginning of the MutableList into a new array without modifying the list.

When to use

Use when you need to inspect or snapshot a bounded prefix of the list without consuming it.

See

  • takeN for removing up to n values and returning them as an array

Signature

declare const toArrayN: <A>(self: MutableList<A>, n: number) => Array<A>

Source

Since v4.0.0

A mutable linked list data structure optimized for high-throughput operations. MutableList provides efficient append/prepend operations and is ideal for producer-consumer patterns, queues, and streaming scenarios.

Example (Creating and consuming a mutable list)

import { MutableList } from "effect"
// Create a mutable list
const list: MutableList.MutableList<number> = MutableList.make()
// Add elements
MutableList.append(list, 1)
MutableList.append(list, 2)
MutableList.prepend(list, 0)
// Access properties
console.log(list.length) // 3
console.log(list.head?.array) // Contains elements from head bucket
console.log(list.tail?.array) // Contains elements from tail bucket
// Take elements
console.log(MutableList.take(list)) // 0
console.log(MutableList.take(list)) // 1
console.log(MutableList.take(list)) // 2

Signature

export interface MutableList<in out A> {
head: MutableList.Bucket<A> | undefined
tail: MutableList.Bucket<A> | undefined
length: number
}

Source

Since v2.0.0

Appends an element to the end of the MutableList. This operation is optimized for high-frequency usage.

Example (Appending elements)

import { MutableList } from "effect"
const list = MutableList.make<number>()
// Append elements one by one
MutableList.append(list, 1)
MutableList.append(list, 2)
MutableList.append(list, 3)
console.log(list.length) // 3
// Elements are taken from head (FIFO)
console.log(MutableList.take(list)) // 1
console.log(MutableList.take(list)) // 2
console.log(MutableList.take(list)) // 3
// High-throughput usage
for (let i = 0; i < 10000; i++) {
MutableList.append(list, i)
}

Signature

declare const append: <A>(self: MutableList<A>, message: A) => void

Source

Since v2.0.0

Appends all elements from an iterable to the end of the MutableList. Returns the number of elements added.

Example (Appending multiple elements)

import { MutableList } from "effect"
const list = MutableList.make<number>()
MutableList.append(list, 1)
MutableList.append(list, 2)
// Append multiple elements
const added = MutableList.appendAll(list, [3, 4, 5])
console.log(added) // 3
console.log(list.length) // 5
// Elements maintain order: [1, 2, 3, 4, 5]
console.log(MutableList.takeAll(list)) // [1, 2, 3, 4, 5]
// Works with any iterable
const newList = MutableList.make<string>()
MutableList.appendAll(newList, new Set(["a", "b", "c"]))
console.log(MutableList.takeAll(newList)) // ["a", "b", "c"]
// Useful for bulk loading
const bulkList = MutableList.make<number>()
const count = MutableList.appendAll(
bulkList,
Array.from({ length: 1000 }, (_, i) => i)
)
console.log(count) // 1000

Signature

declare const appendAll: <A>(self: MutableList<A>, messages: Iterable<A>) => number

Source

Since v4.0.0

Appends all elements from a ReadonlyArray to the end of the MutableList. This is an optimized version that can reuse the array when mutable=true. Returns the number of elements added.

When to use

Use when appending a trusted array directly is worth the optimized path and you control whether the input may be reused.

Gotchas

When mutable=true, the input array may be modified internally. Only use mutable=true when you control the array lifecycle.

Example (Appending arrays with optional mutation)

import { MutableList } from "effect"
const list = MutableList.make<number>()
MutableList.append(list, 1)
// Safe usage (default mutable=false)
const items = [2, 3, 4]
const added = MutableList.appendAllUnsafe(list, items)
console.log(added) // 3
console.log(items) // [2, 3, 4] - unchanged
// Unsafe but efficient usage (mutable=true)
const mutableItems = [5, 6, 7]
MutableList.appendAllUnsafe(list, mutableItems, true)
// mutableItems may be modified internally for efficiency
console.log(MutableList.takeAll(list)) // [1, 2, 3, 4, 5, 6, 7]
// High-performance bulk operations
const bigArray = new Array(10000).fill(0).map((_, i) => i)
MutableList.appendAllUnsafe(list, bigArray, true) // Very efficient

Signature

declare const appendAllUnsafe: <A>(self: MutableList<A>, messages: ReadonlyArray<A>, mutable?: boolean) => number

Source

Since v4.0.0

Removes all elements from the MutableList, resetting it to an empty state. This operation is highly optimized and releases all internal memory.

Example (Clearing a mutable list)

import { MutableList } from "effect"
const list = MutableList.make<number>()
MutableList.appendAll(list, [1, 2, 3, 4, 5])
console.log(list.length) // 5
// Clear all elements
MutableList.clear(list)
console.log(list.length) // 0
console.log(MutableList.take(list)) // Empty
// Can still use the list after clearing
MutableList.append(list, 42)
console.log(list.length) // 1
// Useful for resetting queues or buffers
function resetBuffer<T>(buffer: MutableList.MutableList<T>) {
MutableList.clear(buffer)
console.log("Buffer cleared and ready for reuse")
}

Signature

declare const clear: <A>(self: MutableList<A>) => void

Source

Since v4.0.0

Filters the MutableList in place, keeping only elements that satisfy the predicate. This operation modifies the list and rebuilds its internal structure for efficiency.

Example (Filtering in place)

import { MutableList } from "effect"
const list = MutableList.make<number>()
MutableList.appendAll(list, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
console.log(list.length) // 10
// Keep only even numbers
MutableList.filter(list, (n) => n % 2 === 0)
console.log(MutableList.takeAll(list)) // [2, 4, 6, 8, 10]
// Filter with index
const indexed = MutableList.make<string>()
MutableList.appendAll(indexed, ["a", "b", "c", "d", "e"])
// Keep elements at even indices
MutableList.filter(indexed, (value, index) => index % 2 === 0)
console.log(MutableList.takeAll(indexed)) // ["a", "c", "e"]
// Real-world example: filtering a log queue
const logs = MutableList.make<{ level: string; message: string }>()
MutableList.appendAll(logs, [
{ level: "INFO", message: "App started" },
{ level: "ERROR", message: "Connection failed" },
{ level: "DEBUG", message: "Cache hit" },
{ level: "ERROR", message: "Timeout" }
])
// Keep only errors
MutableList.filter(logs, (log) => log.level === "ERROR")
console.log(MutableList.takeAll(logs).map((log) => log.message)) // ["Connection failed", "Timeout"]

Signature

declare const filter: <A>(self: MutableList<A>, f: (value: A, i: number) => boolean) => void

Source

Since v4.0.0

Prepends an element to the beginning of the MutableList. This operation is optimized for high-frequency usage.

Example (Prepending elements)

import { MutableList } from "effect"
const list = MutableList.make<string>()
// Prepend elements (they'll be at the front)
MutableList.prepend(list, "third")
MutableList.prepend(list, "second")
MutableList.prepend(list, "first")
console.log(list.length) // 3
// Elements taken from head (most recently prepended first)
console.log(MutableList.take(list)) // "first"
console.log(MutableList.take(list)) // "second"
console.log(MutableList.take(list)) // "third"
// Use case: priority items or stack-like behavior
MutableList.append(list, "normal")
MutableList.prepend(list, "priority") // This will be taken first
console.log(MutableList.take(list)) // "priority"

Signature

declare const prepend: <A>(self: MutableList<A>, message: A) => void

Source

Since v2.0.0

Prepends all elements from an iterable to the beginning of the MutableList. The elements are added in order, so the first element in the iterable becomes the new head of the list.

Example (Prepending multiple elements)

import { MutableList } from "effect"
const list = MutableList.make<number>()
MutableList.append(list, 4)
MutableList.append(list, 5)
// Prepend multiple elements
MutableList.prependAll(list, [1, 2, 3])
console.log(list.length) // 5
// Elements are taken in order: [1, 2, 3, 4, 5]
console.log(MutableList.takeAll(list)) // [1, 2, 3, 4, 5]
// Works with any iterable
const newList = MutableList.make<string>()
MutableList.prependAll(newList, "hello") // Prepends each character
console.log(MutableList.takeAll(newList)) // ["h", "e", "l", "l", "o"]

Signature

declare const prependAll: <A>(self: MutableList<A>, messages: Iterable<A>) => void

Source

Since v4.0.0

Prepends all elements from a ReadonlyArray to the beginning of the MutableList. This is an optimized version that can reuse the array when mutable=true.

When to use

Use when prepending a trusted array directly is worth the optimized path and you control whether the input may be reused.

Gotchas

When mutable=true, the input array may be modified internally. Only use mutable=true when you control the array lifecycle.

Example (Prepending arrays with optional mutation)

import { MutableList } from "effect"
const list = MutableList.make<number>()
MutableList.append(list, 4)
// Safe usage (default mutable=false)
const items = [1, 2, 3]
MutableList.prependAllUnsafe(list, items)
console.log(items) // [1, 2, 3] - unchanged
// Unsafe but efficient usage (mutable=true)
const mutableItems = [10, 20, 30]
MutableList.prependAllUnsafe(list, mutableItems, true)
// mutableItems may be modified internally for efficiency
console.log(MutableList.takeAll(list)) // [10, 20, 30, 1, 2, 3, 4]

Signature

declare const prependAllUnsafe: <A>(self: MutableList<A>, messages: ReadonlyArray<A>, mutable?: boolean) => void

Source

Since v4.0.0

Removes all occurrences of a value from the MutableList using JavaScript strict equality semantics.

When to use

Use when in-place removal should use JavaScript identity/strict equality rather than Effect structural equality.

Details

The list is modified in place.

Gotchas

Values are compared with !==, so this does not use Effect structural equality.

Example (Removing matching values)

import { MutableList } from "effect"
const list = MutableList.make<string>()
MutableList.appendAll(list, ["apple", "banana", "apple", "cherry", "apple"])
console.log(list.length) // 5
// Remove all occurrences of "apple"
MutableList.remove(list, "apple")
console.log(MutableList.takeAll(list)) // ["banana", "cherry"]
// Remove non-existent value (no effect)
const colors = MutableList.make<string>()
MutableList.appendAll(colors, ["red", "blue"])
MutableList.remove(colors, "green")
console.log(MutableList.takeAll(colors)) // ["red", "blue"]
// Real-world example: removing completed tasks
const tasks = MutableList.make<{ id: number; status: string }>()
MutableList.appendAll(tasks, [
{ id: 1, status: "pending" },
{ id: 2, status: "completed" },
{ id: 3, status: "pending" },
{ id: 4, status: "completed" }
])
// Remove completed tasks by filtering status
MutableList.filter(tasks, (task) => task.status !== "completed")
console.log(MutableList.takeAll(tasks).map((task) => task.id)) // [1, 3]

Signature

declare const remove: <A>(self: MutableList<A>, value: A) => void

Source

Since v4.0.0

Defines the unique symbol used to represent an empty result when taking elements from a MutableList. This symbol is returned by take when the list is empty, allowing for safe type checking.

When to use

Use to detect that take returned no element before handling the result as a list item.

Example (Checking for empty results)

import { MutableList } from "effect"
const list = MutableList.make<string>()
// Take from empty list returns Empty symbol
const result = MutableList.take(list)
console.log(result === MutableList.Empty) // true
// Safe pattern for checking emptiness
const processNext = (queue: MutableList.MutableList<string>) => {
const item = MutableList.take(queue)
if (item === MutableList.Empty) {
console.log("Queue is empty")
return null
}
return item.toUpperCase()
}
// Compare with other empty results
MutableList.append(list, "hello")
const next = MutableList.take(list)
console.log(next !== MutableList.Empty) // true, got "hello"
const empty = MutableList.take(list)
console.log(empty === MutableList.Empty) // true, list is empty

Signature

declare const Empty: unique symbol

Source

Since v4.0.0

The type of the Empty symbol, used for type checking when taking elements from a MutableList. This provides compile-time safety when checking for empty results.

Example (Handling empty results type-safely)

import { MutableList } from "effect"
const list = MutableList.make<number>()
// Type-safe handling of empty results
const takeAndDouble = (queue: MutableList.MutableList<number>): number | null => {
const item: number | MutableList.Empty = MutableList.take(queue)
if (item === MutableList.Empty) {
return null
}
// TypeScript knows item is number here
return item * 2
}
console.log(takeAndDouble(list)) // null (empty list)
MutableList.append(list, 5)
console.log(takeAndDouble(list)) // 10
// Type guard function
const isEmpty = (result: number | MutableList.Empty): result is MutableList.Empty => {
return result === MutableList.Empty
}
const value = MutableList.take(list)
if (isEmpty(value)) {
console.log("List is empty")
} else {
console.log("Got value:", value)
}

Signature

type Empty = typeof Empty

Source

Since v4.0.0

The MutableList namespace contains type definitions and utilities for working with mutable linked lists.

Example (Typing queue processors)

import { MutableList } from "effect"
// Type annotation using the namespace
const processQueue = (queue: MutableList.MutableList<string>) => {
while (queue.length > 0) {
const item = MutableList.take(queue)
if (item !== MutableList.Empty) {
console.log("Processing:", item)
}
}
}
// Using the namespace for type definitions
const createProcessor = <T>(): {
queue: MutableList.MutableList<T>
add: (item: T) => void
process: () => Array<T>
} => {
const queue = MutableList.make<T>()
return {
queue,
add: (item) => MutableList.append(queue, item),
process: () => MutableList.takeAll(queue)
}
}

Source

Since v2.0.0

Storage node used by the exposed head and tail fields of a MutableList.

Details

Most code should treat buckets as an implementation detail and use MutableList operations such as append, prepend, and take instead of constructing or mutating buckets directly.

Example (Inspecting buckets)

import { MutableList } from "effect"
const list = MutableList.make<number>()
MutableList.append(list, 1)
MutableList.append(list, 2)
// Access bucket information (for debugging or advanced usage)
const inspectBucket = (bucket: MutableList.MutableList.Bucket<number> | undefined) => {
if (bucket) {
console.log("Bucket array:", bucket.array)
console.log("Bucket offset:", bucket.offset)
console.log("Bucket mutable:", bucket.mutable)
console.log("Has next bucket:", bucket.next !== undefined)
}
}
inspectBucket(list.head)
inspectBucket(list.tail)

Signature

export interface Bucket<A> {
readonly array: Array<A>
mutable: boolean
offset: number
next: Bucket<A> | undefined
}

Source

Since v4.0.0