System & Clock Effects

These effects provide access to system-level information and time management.

System Effect

The System effect provides type-safe access to system properties and environment variables.

Environment Variables

import in.rcard.yaes.System.*
import in.rcard.yaes.Raise.*

// With potential parsing errors
val port: (System, Raise[NumberFormatException]) ?=> Option[Int] = 
  System.env[Int]("PORT")

// With default value
val host: System ?=> String = 
  System.env[String]("HOST", "localhost")

System Properties

import in.rcard.yaes.System.*
import in.rcard.yaes.Raise.*

// With potential parsing errors  
val serverPort: (System, Raise[NumberFormatException]) ?=> Option[Int] = 
  System.property[Int]("server.port")

// With default value
val serverHost: System ?=> String = 
  System.property[String]("server.host", "localhost")

Supported Types

The System effect supports parsing for:

Configuration Example

import in.rcard.yaes.System.*
import in.rcard.yaes.Raise.*

case class DatabaseConfig(
  host: String,
  port: Int,
  database: String,
  ssl: Boolean
)

def loadDatabaseConfig(using System, Raise[String]): DatabaseConfig = {
  val host = System.env[String]("DB_HOST", "localhost")
  
  val port = System.env[Int]("DB_PORT").getOrElse {
    Raise.raise("DB_PORT environment variable is required")
  }
  
  val database = System.env[String]("DB_NAME").getOrElse {
    Raise.raise("DB_NAME environment variable is required") 
  }
  
  val ssl = System.env[Boolean]("DB_SSL", "false").toBoolean
  
  DatabaseConfig(host, port, database, ssl)
}

Clock Effect

The Clock effect provides time management operations.

Current Time

import in.rcard.yaes.Clock.*
import java.time.Instant

val currentTime: Clock ?=> Instant = Clock.now()

Monotonic Time

For measuring durations and intervals:

import in.rcard.yaes.Clock.*
import java.time.Duration

val monotonicTime: Clock ?=> Duration = Clock.nowMonotonic()

Time Measurement Example

import in.rcard.yaes.Clock.*
import in.rcard.yaes.Output.*

def measureOperation[A](operation: => A)(using Clock, Output): A = {
  val startTime = Clock.nowMonotonic()
  val result = operation
  val endTime = Clock.nowMonotonic()
  val duration = endTime.minus(startTime)
  
  Output.printLn(s"Operation took: ${duration.toMillis}ms")
  result
}

Timestamped Logging

import in.rcard.yaes.Clock.*
import in.rcard.yaes.Output.*

def logWithTimestamp(message: String)(using Clock, Output): Unit = {
  val timestamp = Clock.now()
  Output.printLn(s"[$timestamp] $message")
}

def timedProcess(using Clock, Output): Unit = {
  logWithTimestamp("Process started")
  
  // Simulate work
  Thread.sleep(1000)
  
  logWithTimestamp("Process completed")
}

Combined Usage

Application Bootstrap

import in.rcard.yaes.System.*
import in.rcard.yaes.Clock.*
import in.rcard.yaes.Output.*
import in.rcard.yaes.Raise.*

case class AppInfo(
  name: String,
  version: String,
  startTime: java.time.Instant,
  environment: String
)

def initializeApp(using System, Clock, Output, Raise[String]): AppInfo = {
  val startTime = Clock.now()
  
  val name = System.property[String]("app.name", "λÆS Application")
  val version = System.property[String]("app.version", "1.0.0")
  val environment = System.env[String]("ENVIRONMENT", "development")
  
  val info = AppInfo(name, version, startTime, environment)
  
  Output.printLn(s"Starting ${info.name} v${info.version}")
  Output.printLn(s"Environment: ${info.environment}")
  Output.printLn(s"Start time: ${info.startTime}")
  
  info
}

// Usage
val appInfo = Raise.either {
  Output.run {
    Clock.run {
      System.run {
        initializeApp
      }
    }
  }
}

Performance Monitoring

import in.rcard.yaes.System.*
import in.rcard.yaes.Clock.*
import in.rcard.yaes.Log.*

def monitoredOperation[A](name: String)(operation: => A)(using Clock, Log): A = {
  val logger = Log.getLogger("Performance")
  val debugEnabled = System.env[Boolean]("DEBUG", "false")
  
  if (debugEnabled) {
    logger.debug(s"Starting operation: $name")
  }
  
  val startTime = Clock.nowMonotonic()
  val result = operation
  val endTime = Clock.nowMonotonic()
  val duration = endTime.minus(startTime)
  
  logger.info(s"Operation '$name' completed in ${duration.toMillis}ms")
  result
}

Running Effects

import in.rcard.yaes.System.*
import in.rcard.yaes.Clock.*

// Individual effects
val systemResult = System.run { /* system operations */ }
val clockResult = Clock.run { /* time operations */ }

// Combined
val combinedResult = Clock.run {
  System.run {
    // operations using both effects
  }
}

Implementation Details

System Effect

Clock Effect

Best Practices