or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application.mdconcurrency.mdindex.mdio.mdresources.mdtype-classes.md

application.mddocs/

0

# Application Framework

1

2

Cats Effect provides IOApp, a complete application framework for building Scala applications with proper lifecycle management, threading, and shutdown handling using the IO monad.

3

4

## Capabilities

5

6

### IOApp Trait

7

8

The main application trait that provides infrastructure for IO-based applications.

9

10

```scala { .api }

11

/**

12

* Main application trait for IO-based applications

13

*/

14

trait IOApp {

15

/** Main application logic - implement this method */

16

def run(args: List[String]): IO[ExitCode]

17

18

/** Implicit ContextShift for thread management */

19

implicit def contextShift: ContextShift[IO]

20

21

/** Implicit Timer for time-based operations */

22

implicit def timer: Timer[IO]

23

24

/** JVM main method - provided automatically */

25

final def main(args: Array[String]): Unit

26

27

/** Called on JVM shutdown - override for custom cleanup */

28

protected def onShutdown(): Unit = ()

29

30

/** Called on uncaught exceptions - override for custom handling */

31

protected def reportFailure(err: Throwable): IO[Unit] =

32

IO(err.printStackTrace())

33

}

34

```

35

36

**Usage Examples:**

37

38

```scala

39

import cats.effect._

40

import scala.concurrent.duration._

41

42

// Simple application

43

object HelloWorldApp extends IOApp {

44

def run(args: List[String]): IO[ExitCode] =

45

IO(println("Hello, World!")).as(ExitCode.Success)

46

}

47

48

// Application with arguments and error handling

49

object FileProcessorApp extends IOApp {

50

def run(args: List[String]): IO[ExitCode] =

51

args.headOption match {

52

case Some(filename) => processFile(filename).as(ExitCode.Success)

53

case None =>

54

IO(Console.err.println("Usage: FileProcessor <filename>"))

55

.as(ExitCode.Error)

56

}

57

58

private def processFile(filename: String): IO[Unit] =

59

for {

60

content <- IO(scala.io.Source.fromFile(filename).mkString)

61

lines = content.split('\n').length

62

_ <- IO(println(s"File $filename has $lines lines"))

63

} yield ()

64

}

65

```

66

67

### IOApp.Simple

68

69

Simplified version of IOApp for applications that don't need to handle command line arguments or return custom exit codes.

70

71

```scala { .api }

72

/**

73

* Simplified IOApp for applications without arguments or custom exit codes

74

*/

75

trait IOApp.Simple extends IOApp {

76

/** Simplified run method without arguments */

77

def run: IO[Unit]

78

79

/** Final implementation that calls run and returns Success */

80

final def run(args: List[String]): IO[ExitCode] =

81

run.as(ExitCode.Success)

82

}

83

```

84

85

**Usage Examples:**

86

87

```scala

88

// Simple server application

89

object WebServerApp extends IOApp.Simple {

90

def run: IO[Unit] =

91

for {

92

_ <- IO(println("Starting web server..."))

93

server <- createServer()

94

_ <- server.serve.compile.drain

95

} yield ()

96

}

97

98

// Background service

99

object BackgroundServiceApp extends IOApp.Simple {

100

def run: IO[Unit] =

101

for {

102

_ <- IO(println("Starting background service..."))

103

_ <- backgroundProcessor().foreverM

104

} yield ()

105

106

private def backgroundProcessor(): IO[Unit] =

107

for {

108

_ <- IO(println("Processing..."))

109

_ <- IO.sleep(10.seconds)

110

} yield ()

111

}

112

```

113

114

### ExitCode

115

116

Type-safe representation of application exit codes.

117

118

```scala { .api }

119

/**

120

* Type-safe exit code representation

121

*/

122

final case class ExitCode(code: Int) {

123

/** Check if this is a success code */

124

def isSuccess: Boolean = code == 0

125

126

/** Check if this is an error code */

127

def isError: Boolean = code != 0

128

}

129

130

object ExitCode {

131

/** Success exit code (0) */

132

val Success: ExitCode = ExitCode(0)

133

134

/** Generic error exit code (1) */

135

val Error: ExitCode = ExitCode(1)

136

137

/** Create from integer (clamped to valid range) */

138

def apply(code: Int): ExitCode = new ExitCode(code & 255)

139

140

/** Create from boolean (false = Success, true = Error) */

141

def fromBoolean(success: Boolean): ExitCode =

142

if (success) Success else Error

143

}

144

```

145

146

**Usage Examples:**

147

148

```scala

149

// Conditional exit codes

150

object ValidationApp extends IOApp {

151

def run(args: List[String]): IO[ExitCode] =

152

for {

153

isValid <- validateData()

154

exitCode = if (isValid) ExitCode.Success else ExitCode(2) // Custom error code

155

} yield exitCode

156

}

157

158

// Exit code from computation result

159

object ComputationApp extends IOApp {

160

def run(args: List[String]): IO[ExitCode] =

161

performComputation().attempt.map {

162

case Right(_) => ExitCode.Success

163

case Left(_) => ExitCode.Error

164

}

165

}

166

```

167

168

### SyncIO

169

170

Synchronous IO monad for operations that don't require async capabilities.

171

172

```scala { .api }

173

/**

174

* Synchronous IO monad without async/concurrency capabilities

175

*/

176

abstract class SyncIO[+A] {

177

/** Transform the result */

178

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

179

180

/** Chain another SyncIO computation */

181

def flatMap[B](f: A => SyncIO[B]): SyncIO[B]

182

183

/** Handle errors */

184

def handleErrorWith[AA >: A](f: Throwable => SyncIO[AA]): SyncIO[AA]

185

186

/** Convert errors to Either */

187

def attempt: SyncIO[Either[Throwable, A]]

188

189

/** Execute synchronously (safe) */

190

def unsafeRunSync(): A

191

192

/** Convert to regular IO */

193

def toIO: IO[A]

194

}

195

196

object SyncIO {

197

/** Lift a pure value */

198

def pure[A](a: A): SyncIO[A]

199

200

/** Suspend a side effect */

201

def delay[A](thunk: => A): SyncIO[A]

202

203

/** Suspend a SyncIO computation */

204

def defer[A](thunk: => SyncIO[A]): SyncIO[A]

205

206

/** Create a failed SyncIO */

207

def raiseError[A](e: Throwable): SyncIO[A]

208

209

/** Unit SyncIO */

210

val unit: SyncIO[Unit]

211

}

212

```

213

214

### Timer and Clock

215

216

Time-based operations and scheduling.

217

218

```scala { .api }

219

/**

220

* Timer for scheduling operations

221

*/

222

trait Timer[F[_]] {

223

/** Access to clock operations */

224

def clock: Clock[F]

225

226

/** Sleep for specified duration */

227

def sleep(duration: FiniteDuration): F[Unit]

228

}

229

230

/**

231

* Clock for accessing time information

232

*/

233

trait Clock[F[_]] {

234

/** Current wall clock time */

235

def realTime(unit: TimeUnit): F[Long]

236

237

/** Monotonic time (unaffected by system clock adjustments) */

238

def monotonic(unit: TimeUnit): F[Long]

239

240

/** Current wall clock time in milliseconds */

241

def realTimeMillis: F[Long] = realTime(MILLISECONDS)

242

243

/** Monotonic time in nanoseconds */

244

def monotonicNanos: F[Long] = monotonic(NANOSECONDS)

245

}

246

247

object Timer {

248

/** Get implicit Timer instance */

249

def apply[F[_]](implicit timer: Timer[F]): Timer[F] = timer

250

251

/** Derive Timer from Clock and ContextShift */

252

def derive[F[_]: Clock: ContextShift: Sync]: Timer[F]

253

}

254

```

255

256

**Usage Examples:**

257

258

```scala

259

// Scheduled operations

260

object ScheduledApp extends IOApp {

261

def run(args: List[String]): IO[ExitCode] =

262

for {

263

start <- Timer[IO].clock.monotonic(MILLISECONDS)

264

_ <- performWork()

265

end <- Timer[IO].clock.monotonic(MILLISECONDS)

266

_ <- IO(println(s"Work completed in ${end - start} ms"))

267

} yield ExitCode.Success

268

269

private def performWork(): IO[Unit] =

270

IO(println("Working...")) *> Timer[IO].sleep(2.seconds)

271

}

272

273

// Timeout handling

274

object TimeoutApp extends IOApp {

275

def run(args: List[String]): IO[ExitCode] =

276

longRunningOperation()

277

.timeout(30.seconds)

278

.handleErrorWith {

279

case _: TimeoutException =>

280

IO(println("Operation timed out")).as(ExitCode.Error)

281

case error =>

282

IO(println(s"Operation failed: ${error.getMessage}")).as(ExitCode.Error)

283

}

284

.as(ExitCode.Success)

285

}

286

```

287

288

### ContextShift

289

290

Thread management and execution context control.

291

292

```scala { .api }

293

/**

294

* Context shifting for thread management

295

*/

296

trait ContextShift[F[_]] {

297

/** Introduce an async boundary */

298

def shift: F[Unit]

299

300

/** Execute on specific ExecutionContext */

301

def evalOn[A](ec: ExecutionContext)(fa: F[A]): F[A]

302

}

303

304

object ContextShift {

305

/** Get implicit ContextShift instance */

306

def apply[F[_]](implicit cs: ContextShift[F]): ContextShift[F] = cs

307

308

/** Create from ExecutionContext */

309

def fromExecutionContext[F[_]: Sync](ec: ExecutionContext): ContextShift[F]

310

311

/** Create global ContextShift for IO */

312

def global: ContextShift[IO]

313

}

314

```

315

316

## Types

317

318

```scala { .api }

319

/**

320

* Main application trait

321

*/

322

trait IOApp {

323

def run(args: List[String]): IO[ExitCode]

324

implicit def contextShift: ContextShift[IO]

325

implicit def timer: Timer[IO]

326

}

327

328

/**

329

* Simplified application trait

330

*/

331

trait IOApp.Simple extends IOApp {

332

def run: IO[Unit]

333

}

334

335

/**

336

* Type-safe exit code

337

*/

338

final case class ExitCode(code: Int)

339

340

/**

341

* Synchronous IO monad

342

*/

343

abstract class SyncIO[+A]

344

345

/**

346

* Timer for scheduling operations

347

*/

348

trait Timer[F[_]] {

349

def clock: Clock[F]

350

def sleep(duration: FiniteDuration): F[Unit]

351

}

352

353

/**

354

* Clock for time access

355

*/

356

trait Clock[F[_]] {

357

def realTime(unit: TimeUnit): F[Long]

358

def monotonic(unit: TimeUnit): F[Long]

359

}

360

361

/**

362

* Context shifting for thread management

363

*/

364

trait ContextShift[F[_]] {

365

def shift: F[Unit]

366

def evalOn[A](ec: ExecutionContext)(fa: F[A]): F[A]

367

}

368

```