or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

collections.mderror-handling.mdfunctional-utilities.mdinclusive-or.mdindex.mdoptional-values.mdraise-dsl.md

error-handling.mddocs/

0

# Error Handling with Either

1

2

Type-safe error handling that makes failure cases explicit and composable. Either is right-biased, treating success (Right) as the default path while providing extensive combinators for error handling and composition.

3

4

## Capabilities

5

6

### Either Construction

7

8

Create Either instances representing success or failure states.

9

10

```kotlin { .api }

11

/**

12

* Create a successful Either containing the given value

13

*/

14

fun <B> Either.Companion.Right(value: B): Either<Nothing, B>

15

16

/**

17

* Create a failed Either containing the given error

18

*/

19

fun <A> Either.Companion.Left(value: A): Either<A, Nothing>

20

21

/**

22

* Execute a function and catch any thrown exceptions

23

*/

24

fun <R> Either.Companion.catch(f: () -> R): Either<Throwable, R>

25

26

/**

27

* Execute a function and catch specific exception types

28

*/

29

inline fun <reified T : Throwable, R> Either.Companion.catchOrThrow(

30

f: () -> R

31

): Either<T, R>

32

```

33

34

**Usage Examples:**

35

36

```kotlin

37

// Direct construction

38

val success: Either<String, Int> = Either.Right(42)

39

val failure: Either<String, Int> = Either.Left("Error occurred")

40

41

// Exception handling

42

val result = Either.catch { "123".toInt() } // Either<Throwable, Int>

43

val parsed = Either.catchOrThrow<NumberFormatException, Int> {

44

"abc".toInt()

45

} // Either<NumberFormatException, Int>

46

```

47

48

### Either Extension Functions

49

50

Convenience functions for creating Either instances from values.

51

52

```kotlin { .api }

53

/**

54

* Wrap any value in Either.Right

55

*/

56

fun <A> A.right(): Either<Nothing, A>

57

58

/**

59

* Wrap any value in Either.Left

60

*/

61

fun <A> A.left(): Either<A, Nothing>

62

63

/**

64

* Create an EitherNel with a single error in NonEmptyList

65

*/

66

fun <E> E.leftNel(): EitherNel<E, Nothing>

67

```

68

69

### Either Type Guards

70

71

Check the state of Either instances with type-safe guards.

72

73

```kotlin { .api }

74

/**

75

* Check if Either is Left (error case)

76

* @return true if Left, false if Right

77

*/

78

fun <A, B> Either<A, B>.isLeft(): Boolean

79

80

/**

81

* Check if Either is Right (success case)

82

* @return true if Right, false if Left

83

*/

84

fun <A, B> Either<A, B>.isRight(): Boolean

85

86

/**

87

* Check if Either is Left and matches predicate

88

*/

89

fun <A, B> Either<A, B>.isLeft(predicate: (A) -> Boolean): Boolean

90

91

/**

92

* Check if Either is Right and matches predicate

93

*/

94

fun <A, B> Either<A, B>.isRight(predicate: (B) -> Boolean): Boolean

95

```

96

97

### Either Pattern Matching

98

99

Safely extract values or perform operations based on Either state.

100

101

```kotlin { .api }

102

/**

103

* Pattern match on Either, providing handlers for both cases

104

*/

105

fun <A, B, C> Either<A, B>.fold(

106

ifLeft: (A) -> C,

107

ifRight: (B) -> C

108

): C

109

110

/**

111

* Extract the Right value or compute a default from Left

112

*/

113

fun <A, B> Either<A, B>.getOrElse(default: (A) -> B): B

114

115

/**

116

* Extract the Right value or return null

117

*/

118

fun <A, B> Either<A, B>.getOrNull(): B?

119

120

/**

121

* Extract the Left value or return null

122

*/

123

fun <A, B> Either<A, B>.leftOrNull(): A?

124

125

/**

126

* Convert Either to Option, keeping only Right values

127

*/

128

fun <A, B> Either<A, B>.getOrNone(): Option<B>

129

```

130

131

### Either Transformations

132

133

Transform Either values while preserving the container structure.

134

135

```kotlin { .api }

136

/**

137

* Transform the Right value if present

138

*/

139

fun <A, B, C> Either<A, B>.map(f: (B) -> C): Either<A, C>

140

141

/**

142

* Transform the Left value if present

143

*/

144

fun <A, B, C> Either<A, B>.mapLeft(f: (A) -> C): Either<C, B>

145

146

/**

147

* Monadic bind - chain operations that can fail

148

*/

149

fun <A, B, C> Either<A, B>.flatMap(f: (B) -> Either<A, C>): Either<A, C>

150

151

/**

152

* Swap Left and Right positions

153

*/

154

fun <A, B> Either<A, B>.swap(): Either<B, A>

155

156

/**

157

* Flatten nested Either (for Either<A, Either<A, B>>)

158

*/

159

fun <A, B> Either<A, Either<A, B>>.flatten(): Either<A, B>

160

161

/**

162

* Merge Either<A, A> into A

163

*/

164

fun <A> Either<A, A>.merge(): A

165

```

166

167

### Either Side Effects

168

169

Perform side effects based on Either state without changing the value.

170

171

```kotlin { .api }

172

/**

173

* Execute action if Either is Right, return original Either

174

*/

175

fun <A, B> Either<A, B>.onRight(action: (B) -> Unit): Either<A, B>

176

177

/**

178

* Execute action if Either is Left, return original Either

179

*/

180

fun <A, B> Either<A, B>.onLeft(action: (A) -> Unit): Either<A, B>

181

```

182

183

### Either Recovery

184

185

Recover from errors or handle specific exception types.

186

187

```kotlin { .api }

188

/**

189

* Recover from Left values using Raise DSL

190

*/

191

fun <A, B, EE> Either<A, B>.recover(

192

recover: Raise<EE>.(A) -> B

193

): Either<EE, B>

194

195

/**

196

* Catch and handle specific exception types

197

*/

198

inline fun <E, reified T : Throwable, A> Either<E, A>.catch(

199

catch: Raise<E>.(T) -> A

200

): Either<E, A>

201

```

202

203

### Either Accumulation

204

205

Combine multiple Either values, accumulating errors instead of short-circuiting.

206

207

```kotlin { .api }

208

/**

209

* Combine 2 Either values, accumulating errors with custom combiner

210

*/

211

fun <E, A, B, Z> Either.Companion.zipOrAccumulate(

212

combine: (E, E) -> E,

213

a: Either<E, A>,

214

b: Either<E, B>,

215

transform: (A, B) -> Z

216

): Either<E, Z>

217

218

/**

219

* Combine 2 Either values, accumulating errors in NonEmptyList

220

*/

221

fun <E, A, B, Z> Either.Companion.zipOrAccumulate(

222

a: Either<E, A>,

223

b: Either<E, B>,

224

transform: (A, B) -> Z

225

): Either<NonEmptyList<E>, Z>

226

227

// Similar functions exist for 3-10 parameters

228

```

229

230

**Usage Example:**

231

232

```kotlin

233

data class User(val name: String, val email: String, val age: Int)

234

235

fun validateName(name: String): Either<String, String> =

236

if (name.isNotBlank()) name.right() else "Name cannot be blank".left()

237

238

fun validateEmail(email: String): Either<String, String> =

239

if (email.contains("@")) email.right() else "Invalid email".left()

240

241

fun validateAge(age: Int): Either<String, Int> =

242

if (age >= 0) age.right() else "Age cannot be negative".left()

243

244

// Accumulate all validation errors

245

val userResult = Either.zipOrAccumulate(

246

validateName(""),

247

validateEmail("invalid-email"),

248

validateAge(-5)

249

) { name, email, age -> User(name, email, age) }

250

// Result: Either.Left(NonEmptyList("Name cannot be blank", "Invalid email", "Age cannot be negative"))

251

```

252

253

### Either Conversions

254

255

Convert Either to other Arrow types.

256

257

```kotlin { .api }

258

/**

259

* Convert Either to EitherNel

260

*/

261

fun <A, B> Either<A, B>.toEitherNel(): EitherNel<A, B>

262

263

/**

264

* Convert Either to Ior

265

*/

266

fun <A, B> Either<A, B>.toIor(): Ior<A, B>

267

```

268

269

### zipOrAccumulate - Error Accumulation

270

271

Combine multiple Either values, accumulating errors instead of short-circuiting on the first failure.

272

273

```kotlin { .api }

274

/**

275

* Combine 2 Either values with custom error combination

276

*/

277

fun <E, A, B, Z> Either.Companion.zipOrAccumulate(

278

combine: (E, E) -> E,

279

a: Either<E, A>,

280

b: Either<E, B>,

281

transform: (A, B) -> Z

282

): Either<E, Z>

283

284

/**

285

* Combine 2 Either values accumulating errors in NonEmptyList

286

*/

287

fun <E, A, B, Z> Either.Companion.zipOrAccumulate(

288

a: Either<E, A>,

289

b: Either<E, B>,

290

transform: (A, B) -> Z

291

): Either<NonEmptyList<E>, Z>

292

293

/**

294

* Combine 3 Either values with custom error combination

295

*/

296

fun <E, A, B, C, Z> Either.Companion.zipOrAccumulate(

297

combine: (E, E) -> E,

298

a: Either<E, A>,

299

b: Either<E, B>,

300

c: Either<E, C>,

301

transform: (A, B, C) -> Z

302

): Either<E, Z>

303

304

/**

305

* Combine 3 Either values accumulating errors in NonEmptyList

306

*/

307

fun <E, A, B, C, Z> Either.Companion.zipOrAccumulate(

308

a: Either<E, A>,

309

b: Either<E, B>,

310

c: Either<E, C>,

311

transform: (A, B, C) -> Z

312

): Either<NonEmptyList<E>, Z>

313

314

// Additional overloads available for 4-10 parameters with both custom combine and NonEmptyList accumulation

315

316

/**

317

* Combine 2 EitherNel values accumulating errors

318

*/

319

fun <E, A, B, Z> Either.Companion.zipOrAccumulate(

320

a: EitherNel<E, A>,

321

b: EitherNel<E, B>,

322

transform: (A, B) -> Z

323

): EitherNel<E, Z>

324

325

// Additional EitherNel overloads available for 3-10 parameters

326

```

327

328

**Usage Examples:**

329

330

```kotlin

331

// Custom error combination

332

val result1 = Either.zipOrAccumulate(

333

{ e1, e2 -> "$e1; $e2" },

334

parseAge("invalid"),

335

parseName(""),

336

::User

337

) // Either.Left("Invalid age; Name required")

338

339

// Error accumulation with NonEmptyList

340

val result2 = Either.zipOrAccumulate(

341

validateEmail("invalid-email"),

342

validateAge("-5"),

343

validateName("")

344

) { email, age, name -> User(email, age, name) }

345

// Either.Left(NonEmptyList("Invalid email", "Age must be positive", "Name required"))

346

```

347

348

## Types

349

350

### EitherNel Type Alias

351

352

```kotlin { .api }

353

/**

354

* Either with NonEmptyList for error accumulation

355

*/

356

typealias EitherNel<E, A> = Either<NonEmptyList<E>, A>

357

```