or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application.mdconcurrency.mdcore-effects.mddependency-injection.mderror-handling.mdindex.mdmetrics.mdresource-management.mdservices.mdstm.mdstreams.mdtesting.md

core-effects.mddocs/

0

# Core Effects

1

2

The ZIO effect system provides the foundational `ZIO[R, E, A]` type and operations for building functional, concurrent applications with comprehensive error handling and resource safety.

3

4

## Capabilities

5

6

### ZIO Effect Type

7

8

The core effect type representing computations that require environment R, may fail with E, or succeed with A.

9

10

```scala { .api }

11

/**

12

* A ZIO effect represents an async workflow that:

13

* - Requires environment R to execute

14

* - May fail with error type E

15

* - Succeeds with value type A

16

*/

17

sealed trait ZIO[-R, +E, +A] extends Product with Serializable

18

19

// Type aliases for common patterns

20

type IO[+E, +A] = ZIO[Any, E, A] // No requirements

21

type Task[+A] = ZIO[Any, Throwable, A] // May fail with Throwable

22

type RIO[-R, +A] = ZIO[R, Throwable, A] // Requires R, may fail

23

type UIO[+A] = ZIO[Any, Nothing, A] // Cannot fail

24

type URIO[-R, +A] = ZIO[R, Nothing, A] // Requires R, cannot fail

25

```

26

27

### Effect Construction

28

29

Create ZIO effects from values, failures, and side-effecting code.

30

31

```scala { .api }

32

/**

33

* Create an effect that always succeeds with the given value

34

*/

35

def succeed[A](a: => A): UIO[A]

36

37

/**

38

* Create an effect that always fails with the given error

39

*/

40

def fail[E](error: => E): IO[E, Nothing]

41

42

/**

43

* Convert side-effecting code into a ZIO effect

44

* Catches exceptions and converts them to typed failures

45

*/

46

def attempt[A](code: => A): Task[A]

47

48

/**

49

* Create an effect that succeeds with Unit

50

*/

51

val unit: UIO[Unit]

52

53

/**

54

* Create an effect that succeeds with None

55

*/

56

val none: UIO[Option[Nothing]]

57

58

/**

59

* Create an effect that terminates the fiber with a defect

60

*/

61

def die(t: => Throwable): UIO[Nothing]

62

63

/**

64

* Create an async effect from a callback registration function

65

*/

66

def async[R, E, A](register: (ZIO[R, E, A] => Unit) => Any): ZIO[R, E, A]

67

68

/**

69

* Convert a Scala Future to a ZIO effect

70

*/

71

def fromFuture[A](make: ExecutionContext => scala.concurrent.Future[A]): Task[A]

72

73

/**

74

* Convert an Either to a ZIO effect

75

*/

76

def fromEither[E, A](v: => Either[E, A]): IO[E, A]

77

```

78

79

**Usage Examples:**

80

81

```scala

82

import zio._

83

84

// Simple success

85

val greeting = ZIO.succeed("Hello, World!")

86

87

// Convert side-effecting code

88

val readFile = ZIO.attempt {

89

scala.io.Source.fromFile("config.txt").mkString

90

}

91

92

// Async callback integration

93

val timer = ZIO.async[Any, Nothing, Unit] { callback =>

94

val timer = new java.util.Timer()

95

timer.schedule(new java.util.TimerTask {

96

def run(): Unit = callback(ZIO.succeed(()))

97

}, 1000)

98

}

99

100

// From Future

101

val futureResult = ZIO.fromFuture { implicit ec =>

102

scala.concurrent.Future.successful(42)

103

}

104

```

105

106

### Effect Transformation

107

108

Transform the success value, error type, or environment requirements of effects.

109

110

```scala { .api }

111

/**

112

* Transform the success value of an effect

113

*/

114

def map[B](f: A => B): ZIO[R, E, B]

115

116

/**

117

* Chain effects together, with the second effect depending on the first

118

*/

119

def flatMap[R1 <: R, E1 >: E, B](k: A => ZIO[R1, E1, B]): ZIO[R1, E1, B]

120

121

/**

122

* Transform the error type of an effect

123

*/

124

def mapError[E2](f: E => E2): ZIO[R, E2, A]

125

126

/**

127

* Handle both success and failure cases

128

*/

129

def fold[B](failure: E => B, success: A => B): URIO[R, B]

130

131

/**

132

* Replace the success value with a constant

133

*/

134

def as[B](b: => B): ZIO[R, E, B]

135

136

/**

137

* Transform both success and error values

138

*/

139

def bimap[E2, A2](f: E => E2, g: A => A2): ZIO[R, E2, A2]

140

141

/**

142

* Provide part of the environment

143

*/

144

def provideSomeEnvironment[R0](f: ZEnvironment[R0] => ZEnvironment[R]): ZIO[R0, E, A]

145

146

/**

147

* Provide the entire environment

148

*/

149

def provideEnvironment(r: => ZEnvironment[R]): IO[E, A]

150

```

151

152

**Usage Examples:**

153

154

```scala

155

// Transform success value

156

val doubled = ZIO.succeed(21).map(_ * 2)

157

158

// Chain effects

159

val program = for {

160

line <- Console.readLine

161

_ <- Console.printLine(s"You entered: $line")

162

} yield ()

163

164

// Handle errors

165

val handled = readFile.fold(

166

error => s"Failed: $error",

167

content => s"Success: ${content.length} characters"

168

)

169

```

170

171

### Error Handling

172

173

Comprehensive error handling with recovery, fallback, and retry mechanisms.

174

175

```scala { .api }

176

/**

177

* Recover from all errors using a recovery function

178

*/

179

def catchAll[R1 <: R, E2, A1 >: A](h: E => ZIO[R1, E2, A1]): ZIO[R1, E2, A1]

180

181

/**

182

* Recover from specific errors matching a partial function

183

*/

184

def catchSome[R1 <: R, E1 >: E, A1 >: A](pf: PartialFunction[E, ZIO[R1, E1, A1]]): ZIO[R1, E1, A1]

185

186

/**

187

* Provide a fallback effect if this one fails

188

*/

189

def orElse[R1 <: R, E2, A1 >: A](that: => ZIO[R1, E2, A1]): ZIO[R1, E2, A1]

190

191

/**

192

* Retry this effect according to a schedule

193

*/

194

def retry[R1 <: R, S](policy: => Schedule[R1, E, S]): ZIO[R1, E, A]

195

196

/**

197

* Convert error to a defect (unrecoverable failure)

198

*/

199

def orDie(implicit ev: E <:< Throwable): URIO[R, A]

200

201

/**

202

* Convert defects to failures

203

*/

204

def sandbox: ZIO[R, Cause[E], A]

205

206

/**

207

* Ignore errors and return Option

208

*/

209

def option: URIO[R, Option[A]]

210

211

/**

212

* Convert errors to Either

213

*/

214

def either: URIO[R, Either[E, A]]

215

```

216

217

**Usage Examples:**

218

219

```scala

220

// Recover from errors

221

val recovered = readFile.catchAll { error =>

222

Console.printLineError(s"Failed to read file: $error") *>

223

ZIO.succeed("default content")

224

}

225

226

// Fallback chain

227

val withFallback =

228

readFile("primary.txt")

229

.orElse(readFile("backup.txt"))

230

.orElse(ZIO.succeed("default"))

231

232

// Retry with exponential backoff

233

val resilient = httpRequest.retry(

234

Schedule.exponential(100.millis) && Schedule.recurs(3)

235

)

236

```

237

238

### Concurrency Operations

239

240

Execute effects concurrently with fibers, racing, and parallel composition.

241

242

```scala { .api }

243

/**

244

* Fork this effect into a new fiber

245

*/

246

def fork: URIO[R, Fiber.Runtime[E, A]]

247

248

/**

249

* Race two effects, returning the result of whichever completes first

250

*/

251

def race[R1 <: R, E1 >: E, A1 >: A](that: => ZIO[R1, E1, A1]): ZIO[R1, E1, A1]

252

253

/**

254

* Execute two effects in parallel and combine results

255

*/

256

def zipPar[R1 <: R, E1 >: E, B](that: => ZIO[R1, E1, B]): ZIO[R1, E1, (A, B)]

257

258

/**

259

* Execute with a timeout, returning None if it takes too long

260

*/

261

def timeout(d: => Duration): ZIO[R, E, Option[A]]

262

263

/**

264

* Execute with a timeout, failing if it takes too long

265

*/

266

def timeoutFail[E1 >: E](e: => E1)(d: => Duration): ZIO[R, E1, A]

267

268

/**

269

* Make this effect interruptible

270

*/

271

def interruptible: ZIO[R, E, A]

272

273

/**

274

* Make this effect uninterruptible

275

*/

276

def uninterruptible: ZIO[R, E, A]

277

```

278

279

**Usage Examples:**

280

281

```scala

282

// Fork and join

283

val fiberProgram = for {

284

fiber <- heavyComputation.fork

285

_ <- otherWork

286

result <- fiber.join

287

} yield result

288

289

// Race multiple operations

290

val fastest =

291

httpRequest("server1")

292

.race(httpRequest("server2"))

293

.race(httpRequest("server3"))

294

295

// Parallel execution

296

val parallel =

297

fetchUser(userId).zipPar(fetchPreferences(userId))

298

299

// With timeout

300

val timedOut = longRunningTask.timeout(30.seconds)

301

```

302

303

### Collection Operations

304

305

Work with collections of effects using foreach, collectAll, and parallel variants.

306

307

```scala { .api }

308

/**

309

* Transform each element of a collection with an effect

310

*/

311

def foreach[R, E, A, B](as: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, List[B]]

312

313

/**

314

* Execute all effects in a collection sequentially

315

*/

316

def collectAll[R, E, A](effects: Iterable[ZIO[R, E, A]]): ZIO[R, E, List[A]]

317

318

/**

319

* Transform each element in parallel

320

*/

321

def foreachPar[R, E, A, B](as: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, List[B]]

322

323

/**

324

* Execute all effects in parallel

325

*/

326

def collectAllPar[R, E, A](effects: Iterable[ZIO[R, E, A]]): ZIO[R, E, List[A]]

327

328

/**

329

* Partition results based on success/failure

330

*/

331

def partition[R, E, A, B](as: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, Nothing, (List[E], List[B])]

332

333

/**

334

* Validate all elements, collecting failures

335

*/

336

def validatePar[R, E, A, B](as: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, List[E], List[B]]

337

```

338

339

**Usage Examples:**

340

341

```scala

342

// Process each item

343

val processed = ZIO.foreach(userIds) { id =>

344

fetchUser(id).map(_.name)

345

}

346

347

// Execute multiple effects

348

val allResults = ZIO.collectAll(List(

349

fetchUser(1),

350

fetchUser(2),

351

fetchUser(3)

352

))

353

354

// Parallel processing with bounded parallelism

355

val parallelBatch = ZIO.foreachPar(largeDataSet.take(100)) { item =>

356

processItem(item)

357

}

358

```

359

360

### Conditional Execution

361

362

Execute effects conditionally based on predicates and optional values.

363

364

```scala { .api }

365

/**

366

* Execute effect only if condition is true

367

*/

368

def when[R, E, A](p: => Boolean)(zio: => ZIO[R, E, A]): ZIO[R, E, Option[A]]

369

370

/**

371

* Execute effect only if condition is false

372

*/

373

def unless[R, E, A](p: => Boolean)(zio: => ZIO[R, E, A]): ZIO[R, E, Option[A]]

374

375

/**

376

* Execute effect for Some values

377

*/

378

def foreach[R, E, A, B](option: Option[A])(f: A => ZIO[R, E, B]): ZIO[R, E, Option[B]]

379

380

/**

381

* Convert Option to ZIO, failing with provided error for None

382

*/

383

def fromOption[A](option: => Option[A]): IO[Unit, A]

384

```

385

386

**Usage Examples:**

387

388

```scala

389

// Conditional execution

390

val maybeLog = ZIO.when(debugMode) {

391

Console.printLine("Debug mode enabled")

392

}

393

394

// Process optional values

395

val processedUser = ZIO.foreach(maybeUser) { user =>

396

validateUser(user) *> saveUser(user)

397

}

398

```

399

400

### Environment Access

401

402

Access and manipulate the ZIO environment for dependency injection.

403

404

```scala { .api }

405

/**

406

* Access a service from the environment

407

*/

408

def service[A: Tag]: URIO[A, A]

409

410

/**

411

* Use a service from the environment

412

*/

413

def serviceWith[Service](f: Service => A): ZIO[Service, Nothing, A]

414

415

/**

416

* Use a service to create an effect

417

*/

418

def serviceWithZIO[Service]: ServiceWithZIOPartiallyApplied[Service]

419

420

/**

421

* Access the full environment

422

*/

423

def environment[R]: URIO[R, ZEnvironment[R]]

424

425

/**

426

* Access part of the environment

427

*/

428

def environmentWith[R](f: ZEnvironment[R] => A): URIO[R, A]

429

430

/**

431

* Create an effect that accesses environment to produce another effect

432

*/

433

def environmentWithZIO[R]: EnvironmentWithZIOPartiallyApplied[R]

434

```

435

436

**Usage Examples:**

437

438

```scala

439

// Access a service

440

val program = for {

441

config <- ZIO.service[AppConfig]

442

_ <- Console.printLine(s"App running on port ${config.port}")

443

} yield ()

444

445

// Use service with transformation

446

val userCount = ZIO.serviceWith[UserRepository](_.countUsers())

447

448

// Access multiple services

449

val businessLogic = for {

450

db <- ZIO.service[Database]

451

cache <- ZIO.service[Cache]

452

user <- db.findUser(userId)

453

_ <- cache.store(s"user:$userId", user)

454

} yield user

455

```

456

457

### Chunk Data Structures

458

459

High-performance immutable arrays optimized for ZIO operations with excellent memory efficiency and fast operations.

460

461

```scala { .api }

462

/**

463

* A Chunk represents an immutable, high-performance array-like collection

464

*/

465

sealed trait Chunk[+A] extends Iterable[A] {

466

/** Get element at index */

467

def apply(n: Int): A

468

469

/** Get the length of the chunk */

470

def length: Int

471

def size: Int = length

472

473

/** Check if chunk is empty */

474

def isEmpty: Boolean

475

def nonEmpty: Boolean = !isEmpty

476

477

/** Get first element if exists */

478

def headOption: Option[A]

479

480

/** Get last element if exists */

481

def lastOption: Option[A]

482

483

/** Transform each element */

484

def map[B](f: A => B): Chunk[B]

485

486

/** Filter elements */

487

def filter(f: A => Boolean): Chunk[A]

488

489

/** Fold/reduce elements */

490

def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1

491

def foldLeft[B](z: B)(op: (B, A) => B): B

492

493

/** Concatenate with another chunk */

494

def ++[A1 >: A](that: Chunk[A1]): Chunk[A1]

495

496

/** Prepend element */

497

def +:[A1 >: A](elem: A1): Chunk[A1]

498

499

/** Append element */

500

def :+[A1 >: A](elem: A1): Chunk[A1]

501

502

/** Take first n elements */

503

def take(n: Int): Chunk[A]

504

505

/** Drop first n elements */

506

def drop(n: Int): Chunk[A]

507

508

/** Slice chunk */

509

def slice(from: Int, until: Int): Chunk[A]

510

511

/** Split at index */

512

def splitAt(n: Int): (Chunk[A], Chunk[A])

513

514

/** Convert to Array */

515

def toArray[A1 >: A: ClassTag]: Array[A1]

516

517

/** Convert to List */

518

def toList: List[A]

519

520

/** Convert to Vector */

521

def toVector: Vector[A]

522

}

523

524

/**

525

* Non-empty chunk with additional guarantees

526

*/

527

sealed trait NonEmptyChunk[+A] extends Chunk[A] {

528

/** Get first element (guaranteed to exist) */

529

def head: A

530

531

/** Get last element (guaranteed to exist) */

532

def last: A

533

534

/** Get tail (may be empty) */

535

def tail: Chunk[A]

536

537

/** Get init (may be empty) */

538

def init: Chunk[A]

539

540

/** Reduce without seed value */

541

def reduce[A1 >: A](op: (A1, A1) => A1): A1

542

}

543

544

/**

545

* Chunk construction methods

546

*/

547

object Chunk {

548

/** Empty chunk */

549

val empty: Chunk[Nothing]

550

551

/** Single element chunk */

552

def single[A](a: A): Chunk[A]

553

554

/** Create from varargs */

555

def apply[A](as: A*): Chunk[A]

556

557

/** Create from iterable */

558

def fromIterable[A](it: Iterable[A]): Chunk[A]

559

560

/** Create from array */

561

def fromArray[A](array: Array[A]): Chunk[A]

562

563

/** Create from ByteBuffer */

564

def fromByteBuffer(buffer: ByteBuffer): Chunk[Byte]

565

566

/** Fill with repeated value */

567

def fill[A](n: Int)(a: A): Chunk[A]

568

569

/** Generate using function */

570

def tabulate[A](n: Int)(f: Int => A): Chunk[A]

571

572

/** Create range of integers */

573

def range(start: Int, end: Int): Chunk[Int]

574

575

/** Unfold from seed value */

576

def unfold[S, A](s: S)(f: S => Option[(A, S)]): Chunk[A]

577

578

/** Iterate function */

579

def iterate[A](start: A, len: Int)(f: A => A): Chunk[A]

580

}

581

582

/**

583

* Non-empty chunk construction

584

*/

585

object NonEmptyChunk {

586

/** Create from first element and rest */

587

def apply[A](head: A, tail: A*): NonEmptyChunk[A]

588

589

/** Create from non-empty iterable */

590

def fromIterable[A](it: Iterable[A]): Option[NonEmptyChunk[A]]

591

592

/** Create single element */

593

def single[A](a: A): NonEmptyChunk[A]

594

}

595

```

596

597

**Usage Examples:**

598

599

```scala

600

import zio._

601

602

// Create chunks

603

val numbers = Chunk(1, 2, 3, 4, 5)

604

val fromList = Chunk.fromIterable(List("a", "b", "c"))

605

val repeated = Chunk.fill(5)("hello")

606

607

// Transform chunks

608

val doubled = numbers.map(_ * 2)

609

val evens = numbers.filter(_ % 2 == 0)

610

val sum = numbers.foldLeft(0)(_ + _)

611

612

// Combine chunks

613

val combined = Chunk(1, 2) ++ Chunk(3, 4)

614

val withExtra = 0 +: numbers :+ 6

615

616

// Work with non-empty chunks

617

val nonEmpty = NonEmptyChunk(1, 2, 3, 4)

618

val first = nonEmpty.head // guaranteed to exist

619

val reduced = nonEmpty.reduce(_ + _) // no seed needed

620

621

// High-performance operations

622

val large = Chunk.range(0, 1000000)

623

val sliced = large.slice(1000, 2000) // efficient slicing

624

val array = large.toArray // zero-copy when possible

625

626

// Integration with ZIO effects

627

val processChunk = ZIO.foreach(numbers) { n =>

628

Console.printLine(s"Processing: $n")

629

}

630

631

// Stream integration

632

val chunkStream = ZStream.fromChunk(numbers)

633

val collectedChunk = ZStream.range(1, 100).runCollect

634

```