zio.blocks.scope

Scope: A compile-time safe resource management library using scope-local opaque types.

==Quick Start==

import zio.blocks.scope._

Scope.global.scoped { scope =>
 import scope._
 val db: $[Database] = allocate(Resource[Database])
 val result: $[Int] = (scope $ db)(_.query("SELECT 1"))
 result  // Returns $[Int], unwrapped to Int at boundary
}

==Key Concepts==

  • '''Scoped values''' (scope.$[A]): Values tied to a scope, preventing escape
  • '''import scope._''': Bring scope operations into lexical scope
  • '''allocate(resource)''': Allocate a value in the current scope
  • '''(scope $ value)(f)''': Apply a function to a scoped value
  • '''scoped { s => ... }''': Create a child scope
  • '''defer { ... }''': Register cleanup to run when scope closes

==How It Works==

Each scope has its own $[A] opaque type. Child scopes create structurally incompatible $[A] types, preventing sibling-scoped values from being mixed. Parent-scoped values can be lowered into child scopes via lower().

The .scoped method requires Unscoped[A] evidence on the return type, ensuring only pure data (not resources or closures) can escape.

Attributes

See also

scope.Scope for scope types and operations scope.Resource for creating scoped values scope.Unscoped for types that can cross scope boundaries

Members list

Packages

Type members

Classlikes

case object BuildInfo

This object was generated by sbt-buildinfo.

This object was generated by sbt-buildinfo.

Attributes

Source
BuildInfo.scala
Supertypes
trait Singleton
trait Product
trait Mirror
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
Self type
BuildInfo.type
object DeferHandle

Attributes

Companion
class
Source
DeferHandle.scala
Supertypes
class Object
trait Matchable
class Any
Self type
abstract class DeferHandle

A handle returned by Scope.defer that allows cancelling a registered finalizer before the scope closes.

A handle returned by Scope.defer that allows cancelling a registered finalizer before the scope closes.

When scope.defer(cleanup) is called, the cleanup action is registered to run when the scope closes, and a DeferHandle is returned. The handle can be used to remove that finalizer early, attempting to prevent it from running when the scope closes. If cancellation races with scope closure, the finalizer may already be in the process of running. This is useful when a resource is explicitly released before the scope ends, and running the finalizer again would be unnecessary or harmful.

Attributes

See also

Scope.defer for registering finalizers

Companion
object
Source
DeferHandle.scala
Supertypes
class Object
trait Matchable
class Any
object Finalization

Attributes

Companion
class
Source
Finalization.scala
Supertypes
class Object
trait Matchable
class Any
Self type
final class Finalization(val errors: Chunk[Throwable])

The result of running finalizers, collecting any errors that occurred.

The result of running finalizers, collecting any errors that occurred.

When a scope closes, each registered finalizer runs in LIFO order. Finalizers that throw are caught and their exceptions are collected into a Finalization. This type provides convenient methods for inspecting and re-throwing those errors.

Value parameters

errors

the errors collected from running finalizers

Attributes

Companion
object
Source
Finalization.scala
Supertypes
class Object
trait Matchable
class Any
trait Finalizer

A handle for registering cleanup actions (finalizers).

A handle for registering cleanup actions (finalizers).

Finalizers run in LIFO order when the scope closes. This trait exposes only the defer capability, preventing user code from accessing scope internals like allocate or close.

Attributes

Source
Finalizer.scala
Supertypes
class Object
trait Matchable
class Any
Known subtypes
class Scope
class Child[P]
object global
object Resource

Attributes

Companion
trait
Source
Resource.scala
Supertypes
class Object
trait Matchable
class Any
Self type
Resource.type
sealed trait Resource[+A]

A description of how to acquire and release a resource.

A description of how to acquire and release a resource.

Resources encapsulate both acquisition and finalization, tying a value's lifecycle to a Scope. When a resource is created via scope.allocate(resource), the scope registers any finalizers and ensures they run when the scope closes.

Resources are lazy—they describe ''what'' to do, not ''when''. Creation only happens when passed to a scope via scope.allocate(resource).

==Creating Resources==

  • Resource(=> a): By-name value; auto-registers close() if AutoCloseable
  • Resource.acquireRelease(acquire)(release): Explicit acquire/release
  • Resource.fromAutoCloseable(=> a): For AutoCloseable subtypes
  • Resource.from[T] macro: Derives from constructor

Type parameters

A

the type of value this resource produces

Attributes

See also

[[Scope.allocateA* Scope.allocate]] for using resources

Wire.toResource for converting wires

Example
 Scope.global.scoped { scope =>
   import scope._
   val db = allocate(Resource.fromAutoCloseable(new Database()))
   (scope $ db)(_.query("SELECT 1"))
 }
Companion
object
Source
Resource.scala
Supertypes
class Object
trait Matchable
class Any
Self type
object Scope

Companion object for Scope, providing the global scope, child scope implementation, and the OpenScope handle.

Companion object for Scope, providing the global scope, child scope implementation, and the OpenScope handle.

Attributes

Companion
class
Source
Scope.scala
Supertypes
class Object
trait Matchable
class Any
Self type
Scope.type
sealed abstract class Scope extends Finalizer

A scope that manages resource lifecycle with compile-time verified safety.

A scope that manages resource lifecycle with compile-time verified safety.

==Closed-scope safety==

The operations allocate, open, and $ throw java.lang.IllegalStateException if called on a scope that has already closed. The exception message explains what went wrong and how to fix it. This prevents silent use-after-free bugs where a scope reference escapes its scoped { } block and a resource is accessed after its finalizers have run.

defer on a closed scope is silently ignored (no-op), and scoped on a closed scope creates a born-closed child.

Attributes

Companion
object
Source
Scope.scala
Supertypes
trait Finalizer
class Object
trait Matchable
class Any
Known subtypes
class Child[P]
object global
Self type
object Unscoped

Companion object providing given instances for common types.

Companion object providing given instances for common types.

==Adding Custom Instances==

To mark your own type as safe to escape scopes, define a given instance:

case class UserId(value: Long)
object UserId {
 given Unscoped[UserId] = new Unscoped[UserId] {}
}

Only add Unscoped instances for pure data types that don't hold resources. Resource types (streams, connections, handles) should NOT have instances.

Attributes

Companion
trait
Source
Unscoped.scala
Supertypes
class Object
trait Matchable
class Any
Self type
Unscoped.type
trait Unscoped[A]

Marker typeclass for types that can escape a scope unscoped.

Marker typeclass for types that can escape a scope unscoped.

Types with an Unscoped instance are considered "safe data" - they don't hold resources and can be freely extracted from a scope without tracking.

==Default Instances==

The following types have Unscoped instances by default:

  • Primitives: Int, Long, Short, Byte, Char, Boolean, Float, Double, Unit
  • Text: String
  • Numeric: BigInt, BigDecimal
  • Collections: Array, List, Vector, Set, Seq, IndexedSeq, Iterable, Map (when elements are Unscoped)
  • Containers: Option, Either (when elements are Unscoped)
  • Tuples: up to 4-tuples (when elements are Unscoped)
  • Time: java.time.* value types, scala.concurrent.duration.*
  • Other: java.util.UUID, zio.blocks.chunk.Chunk

==Resource Types==

Types representing resources (streams, connections, handles, etc.) should NOT have Unscoped instances. This ensures they remain tracked by the scope system and cannot accidentally escape.

Type parameters

A

the type that can escape scopes

Attributes

Example
 // Primitives escape freely (auto-unwrapped by $)
 Scope.global.scoped { s =>
   import s._
   (s $ stream)(_.read()) // returns Int directly since Int: Unscoped
 }
 // Resources stay scoped
 val body: $[InputStream] = (scope $ request)(_.body)  // InputStream stays scoped (no Unscoped instance)
Companion
object
Source
Unscoped.scala
Supertypes
class Object
trait Matchable
class Any
sealed trait Wire[-In, +Out]

A recipe for constructing a service and its dependencies.

A recipe for constructing a service and its dependencies.

Wires are the building blocks of dependency injection in Scope. They describe how to construct a service given access to its dependencies via a context.

==Wire Types==

==Creating Wires==

Use Wire.shared[T] and Wire.unique[T] macros for automatic derivation from constructors, or create wires manually for custom construction logic.

==Usage Example==

// Define a service with its wire
class Database(config: Config)
object Database {
 val wire: Wire[Config, Database] = Wire.shared[Database]
}

// Create a unique wire for request-scoped services
class RequestHandler(db: Database)
object RequestHandler {
 val wire: Wire[Database, RequestHandler] = Wire.unique[RequestHandler]
}

// Create a Resource from wires
val appResource = Resource.from[App](
 Wire(Config("localhost", 8080)),
 Wire.shared[Database]
)

Type parameters

In

the dependencies required (contravariant - accepts supertypes)

Out

the service(s) produced (covariant - produces subtypes)

Attributes

Companion
object
Source
Wire.scala
Supertypes
class Object
trait Matchable
class Any
Known subtypes
class Shared[In, Out]
class Unique[In, Out]
object Wire

Companion object providing wire factory methods and wire classes.

Companion object providing wire factory methods and wire classes.

Attributes

Companion
trait
Source
Wire.scala
Supertypes
trait Sum
trait Mirror
class Object
trait Matchable
class Any
Self type
Wire.type

Deprecated classlikes

trait InStack[-T, +Stack]

Type parameters

Stack

the HList-style stack to search within

T

the type to search for in the stack

Attributes

Companion
object
Deprecated
[Since version 0.1.0] InStack is no longer used in the new Scope design

InStack is no longer used in the new Scope design. Dependencies are resolved via Resource and Wire, not via HList type-level search.

Source
InStack.scala
Supertypes
class Object
trait Matchable
class Any
object InStack

Attributes

Companion
trait
Deprecated
[Since version 0.1.0] InStack is no longer used in the new Scope design

InStack is no longer used in the new Scope design.

Source
InStack.scala
Supertypes
class Object
trait Matchable
class Any
Self type
InStack.type

Value members

Concrete methods

def defer(finalizer: => Unit)(using fin: Finalizer): DeferHandle

Registers a finalizer to run when the current scope closes.

Registers a finalizer to run when the current scope closes.

Finalizers run in LIFO order (last registered runs first). If a finalizer throws, subsequent finalizers still run.

Value parameters

fin

the finalizer capability to register cleanup with

finalizer

a by-name expression to execute on scope close

Attributes

Example
 Scope.global.scoped { scope =>
   val resource = acquire()
   scope.defer { resource.release() }
   // use resource...
 }
Source
package.scala