Cross-Platform Development with Scala: JVM, JavaScript, and Native

Scala's cross-platform capabilities allow developers to write code once and deploy it across multiple platforms: JVM, JavaScript environments, and native platforms. This comprehensive lesson explores how to leverage Scala.js and Scala Native for cross-platform development while maximizing code reuse and maintaining platform-specific optimizations.

Understanding Cross-Platform Architecture

Platform Targets Overview

// Shared code that works across all platforms
// This code can be compiled to JVM bytecode, JavaScript, or native binaries

// Common data structures and business logic
case class User(id: String, name: String, email: String, createdAt: Long)

case class ApiResponse[T](
  data: Option[T],
  error: Option[String],
  timestamp: Long = System.currentTimeMillis()
)

// Shared utilities that work across platforms
object CommonUtils {
  def validateEmail(email: String): Boolean = {
    email.contains("@") && email.contains(".")
  }

  def formatTimestamp(timestamp: Long): String = {
    // Use Java time API which is available on all platforms
    java.time.Instant.ofEpochMilli(timestamp).toString
  }

  def parseJson[T](json: String)(implicit decoder: JsonDecoder[T]): Either[String, T] = {
    try {
      Right(decoder.decode(json))
    } catch {
      case e: Exception => Left(s"JSON parsing failed: ${e.getMessage}")
    }
  }

  def encodeJson[T](value: T)(implicit encoder: JsonEncoder[T]): String = {
    encoder.encode(value)
  }
}

// Abstract platform interface
trait Platform {
  def name: String
  def currentTimeMillis(): Long
  def randomUUID(): String
  def readFile(path: String): Either[String, String]
  def writeFile(path: String, content: String): Either[String, Unit]
  def httpGet(url: String): Either[String, String]
  def httpPost(url: String, body: String): Either[String, String]
}

// Shared business logic
class UserService(platform: Platform) {
  private var users = Map.empty[String, User]

  def createUser(name: String, email: String): Either[String, User] = {
    if (!CommonUtils.validateEmail(email)) {
      Left("Invalid email format")
    } else {
      val userId = platform.randomUUID()
      val user = User(userId, name, email, platform.currentTimeMillis())
      users = users + (userId -> user)
      Right(user)
    }
  }

  def getUser(id: String): Option[User] = users.get(id)

  def updateUser(id: String, name: Option[String], email: Option[String]): Either[String, User] = {
    users.get(id) match {
      case None => Left("User not found")
      case Some(user) =>
        val updatedUser = user.copy(
          name = name.getOrElse(user.name),
          email = email.getOrElse(user.email)
        )

        if (!CommonUtils.validateEmail(updatedUser.email)) {
          Left("Invalid email format")
        } else {
          users = users + (id -> updatedUser)
          Right(updatedUser)
        }
    }
  }

  def listUsers(): List[User] = users.values.toList.sortBy(_.createdAt)

  def saveToFile(path: String): Either[String, Unit] = {
    val json = users.values.map(encodeUser).mkString("[", ",", "]")
    platform.writeFile(path, json)
  }

  def loadFromFile(path: String): Either[String, Unit] = {
    platform.readFile(path).flatMap { content =>
      // Parse JSON and load users
      // Implementation would depend on JSON library
      Right(())
    }
  }

  private def encodeUser(user: User): String = {
    s"""{"id":"${user.id}","name":"${user.name}","email":"${user.email}","createdAt":${user.createdAt}}"""
  }
}

// Cross-platform JSON encoding/decoding
trait JsonEncoder[T] {
  def encode(value: T): String
}

trait JsonDecoder[T] {
  def decode(json: String): T
}

object JsonCodecs {
  implicit val userEncoder: JsonEncoder[User] = (user: User) =>
    s"""{"id":"${user.id}","name":"${user.name}","email":"${user.email}","createdAt":${user.createdAt}}"""

  implicit val userDecoder: JsonDecoder[User] = (json: String) => {
    // Simplified JSON parsing - in practice, use a cross-platform JSON library
    val trimmed = json.trim.stripPrefix("{").stripSuffix("}")
    val fields = trimmed.split(",").map(_.split(":")).map { arr =>
      arr(0).trim.stripPrefix("\"").stripSuffix("\"") -> arr(1).trim.stripPrefix("\"").stripSuffix("\"")
    }.toMap

    User(
      id = fields("id"),
      name = fields("name"),
      email = fields("email"),
      createdAt = fields("createdAt").toLong
    )
  }

  implicit def apiResponseEncoder[T](implicit enc: JsonEncoder[T]): JsonEncoder[ApiResponse[T]] = {
    (response: ApiResponse[T]) =>
      val dataJson = response.data.map(enc.encode).getOrElse("null")
      val errorJson = response.error.map(e => s""""$e"""").getOrElse("null")
      s"""{"data":$dataJson,"error":$errorJson,"timestamp":${response.timestamp}}"""
  }
}

Scala.js: JavaScript Target

Setting Up Scala.js Projects

// build.sbt for Scala.js project
ThisBuild / scalaVersion := "3.3.0"

lazy val commonSettings = Seq(
  organization := "com.example",
  version := "1.0.0"
)

// Shared code module
lazy val shared = crossProject(JSPlatform, JVMPlatform, NativePlatform)
  .crossType(CrossType.Pure)
  .in(file("shared"))
  .settings(commonSettings)
  .settings(
    libraryDependencies ++= Seq(
      "org.typelevel" %%% "cats-core" % "2.9.0",
      "io.circe" %%% "circe-core" % "0.14.5",
      "io.circe" %%% "circe-generic" % "0.14.5",
      "io.circe" %%% "circe-parser" % "0.14.5"
    )
  )

lazy val sharedJvm = shared.jvm
lazy val sharedJs = shared.js
lazy val sharedNative = shared.native

// Scala.js specific module
lazy val client = project
  .in(file("client"))
  .enablePlugins(ScalaJSPlugin)
  .settings(commonSettings)
  .settings(
    libraryDependencies ++= Seq(
      "org.scala-js" %%% "scalajs-dom" % "2.4.0",
      "com.raquo" %%% "laminar" % "15.0.1", // Frontend framework
      "com.lihaoyi" %%% "upickle" % "3.1.0"
    ),
    scalaJSUseMainModuleInitializer := true,
    scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.ESModule) }
  )
  .dependsOn(sharedJs)

// JVM server module  
lazy val server = project
  .in(file("server"))
  .settings(commonSettings)
  .settings(
    libraryDependencies ++= Seq(
      "com.typesafe.akka" %% "akka-http" % "10.5.0",
      "com.typesafe.akka" %% "akka-stream" % "2.8.0",
      "ch.qos.logback" % "logback-classic" % "1.4.7"
    )
  )
  .dependsOn(sharedJvm)

DOM Manipulation and Frontend Development

// Platform-specific implementation for JavaScript
import org.scalajs.dom
import org.scalajs.dom.{document, window, console}
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.scalajs.js
import scala.scalajs.js.annotation._

// Scala.js platform implementation
object JSPlatform extends Platform {
  val name = "JavaScript"

  def currentTimeMillis(): Long = js.Date.now().toLong

  def randomUUID(): String = java.util.UUID.randomUUID().toString

  def readFile(path: String): Either[String, String] = {
    // In browser environment, reading files requires user interaction
    Left("File reading not supported in browser environment")
  }

  def writeFile(path: String, content: String): Either[String, Unit] = {
    // Trigger download in browser
    val blob = new dom.Blob(js.Array(content), js.Dynamic.literal(`type` = "text/plain"))
    val url = dom.URL.createObjectURL(blob)

    val link = document.createElement("a").asInstanceOf[dom.html.Anchor]
    link.href = url
    link.download = path
    link.click()

    dom.URL.revokeObjectURL(url)
    Right(())
  }

  def httpGet(url: String): Either[String, String] = {
    // Synchronous version for simplicity - in practice, use async
    try {
      val xhr = new dom.XMLHttpRequest()
      xhr.open("GET", url, async = false)
      xhr.send()

      if (xhr.status == 200) {
        Right(xhr.responseText)
      } else {
        Left(s"HTTP error: ${xhr.status}")
      }
    } catch {
      case e: Exception => Left(s"Request failed: ${e.getMessage}")
    }
  }

  def httpPost(url: String, body: String): Either[String, String] = {
    try {
      val xhr = new dom.XMLHttpRequest()
      xhr.open("POST", url, async = false)
      xhr.setRequestHeader("Content-Type", "application/json")
      xhr.send(body)

      if (xhr.status == 200) {
        Right(xhr.responseText)
      } else {
        Left(s"HTTP error: ${xhr.status}")
      }
    } catch {
      case e: Exception => Left(s"Request failed: ${e.getMessage}")
    }
  }
}

// Async versions using Future
object AsyncJSPlatform {

  def httpGetAsync(url: String): Future[Either[String, String]] = {
    val promise = scala.concurrent.Promise[Either[String, String]]()

    val xhr = new dom.XMLHttpRequest()
    xhr.onload = { (_: dom.Event) =>
      if (xhr.status == 200) {
        promise.success(Right(xhr.responseText))
      } else {
        promise.success(Left(s"HTTP error: ${xhr.status}"))
      }
    }
    xhr.onerror = { (_: dom.Event) =>
      promise.success(Left("Network error"))
    }

    xhr.open("GET", url)
    xhr.send()
    promise.future
  }

  def httpPostAsync(url: String, body: String): Future[Either[String, String]] = {
    val promise = scala.concurrent.Promise[Either[String, String]]()

    val xhr = new dom.XMLHttpRequest()
    xhr.onload = { (_: dom.Event) =>
      if (xhr.status == 200) {
        promise.success(Right(xhr.responseText))
      } else {
        promise.success(Left(s"HTTP error: ${xhr.status}"))
      }
    }
    xhr.onerror = { (_: dom.Event) =>
      promise.success(Left("Network error"))
    }

    xhr.open("POST", url)
    xhr.setRequestHeader("Content-Type", "application/json")
    xhr.send(body)
    promise.future
  }
}

// Frontend application using Laminar
import com.raquo.laminar.api.L._
import com.raquo.laminar.nodes.ReactiveHtmlElement
import org.scalajs.dom.html

object UserManagementApp {

  case class AppState(
    users: List[User] = List.empty,
    selectedUser: Option[User] = None,
    isLoading: Boolean = false,
    error: Option[String] = None
  )

  sealed trait AppAction
  case object LoadUsers extends AppAction
  case class CreateUser(name: String, email: String) extends AppAction
  case class SelectUser(user: User) extends AppAction
  case class UpdateUser(id: String, name: String, email: String) extends AppAction
  case class DeleteUser(id: String) extends AppAction
  case class SetError(error: String) extends AppAction
  case object ClearError extends AppAction

  class UserStore {
    private val userService = new UserService(JSPlatform)
    private val stateVar = Var(AppState())

    val state: Signal[AppState] = stateVar.signal

    def dispatch(action: AppAction): Unit = action match {
      case LoadUsers =>
        stateVar.update(_.copy(isLoading = true, error = None))
        // In a real app, load from server
        val users = userService.listUsers()
        stateVar.update(_.copy(users = users, isLoading = false))

      case CreateUser(name, email) =>
        userService.createUser(name, email) match {
          case Right(user) =>
            stateVar.update(state => state.copy(users = user :: state.users))
          case Left(error) =>
            stateVar.update(_.copy(error = Some(error)))
        }

      case SelectUser(user) =>
        stateVar.update(_.copy(selectedUser = Some(user)))

      case UpdateUser(id, name, email) =>
        userService.updateUser(id, Some(name), Some(email)) match {
          case Right(updatedUser) =>
            stateVar.update(state => state.copy(
              users = state.users.map(u => if (u.id == id) updatedUser else u),
              selectedUser = Some(updatedUser)
            ))
          case Left(error) =>
            stateVar.update(_.copy(error = Some(error)))
        }

      case DeleteUser(id) =>
        stateVar.update(state => state.copy(
          users = state.users.filterNot(_.id == id),
          selectedUser = state.selectedUser.filter(_.id != id)
        ))

      case SetError(error) =>
        stateVar.update(_.copy(error = Some(error)))

      case ClearError =>
        stateVar.update(_.copy(error = None))
    }
  }

  def createApp(): ReactiveHtmlElement[html.Div] = {
    val store = new UserStore()

    div(
      cls := "user-management-app",

      // Header
      h1("User Management"),

      // Error display
      store.state.map(_.error).split(
        _ => div(),
        error => div(
          cls := "error",
          s"Error: $error",
          button(
            "Clear",
            onClick --> (_ => store.dispatch(ClearError))
          )
        )
      ),

      // User form
      createUserForm(store),

      // User list
      div(
        cls := "user-list",
        h2("Users"),
        children <-- store.state.map(_.users).split(_.id)(renderUser(store))
      ),

      // User details
      store.state.map(_.selectedUser).split(
        _ => div("Select a user to view details"),
        user => renderUserDetails(store, user)
      )
    )
  }

  private def createUserForm(store: UserStore): ReactiveHtmlElement[html.Form] = {
    val nameVar = Var("")
    val emailVar = Var("")

    form(
      cls := "user-form",
      h3("Create New User"),

      div(
        label("Name:"),
        input(
          tpe := "text",
          placeholder := "Enter name",
          controlled(
            value <-- nameVar,
            onInput.mapToValue --> nameVar
          )
        )
      ),

      div(
        label("Email:"),
        input(
          tpe := "email",
          placeholder := "Enter email",
          controlled(
            value <-- emailVar,
            onInput.mapToValue --> emailVar
          )
        )
      ),

      button(
        tpe := "button",
        "Create User",
        onClick --> { _ =>
          store.dispatch(CreateUser(nameVar.now(), emailVar.now()))
          nameVar.set("")
          emailVar.set("")
        }
      )
    )
  }

  private def renderUser(store: UserStore)(id: String, initial: User, userSignal: Signal[User]): ReactiveHtmlElement[html.Div] = {
    div(
      cls := "user-item",
      child <-- userSignal.map { user =>
        div(
          onClick --> (_ => store.dispatch(SelectUser(user))),
          div(s"Name: ${user.name}"),
          div(s"Email: ${user.email}"),
          div(s"Created: ${CommonUtils.formatTimestamp(user.createdAt)}")
        )
      }
    )
  }

  private def renderUserDetails(store: UserStore, user: User): ReactiveHtmlElement[html.Div] = {
    val nameVar = Var(user.name)
    val emailVar = Var(user.email)

    div(
      cls := "user-details",
      h3("User Details"),

      div(
        label("Name:"),
        input(
          tpe := "text",
          controlled(
            value <-- nameVar,
            onInput.mapToValue --> nameVar
          )
        )
      ),

      div(
        label("Email:"),
        input(
          tpe := "email",
          controlled(
            value <-- emailVar,
            onInput.mapToValue --> emailVar
          )
        )
      ),

      div(
        button(
          "Update",
          onClick --> { _ =>
            store.dispatch(UpdateUser(user.id, nameVar.now(), emailVar.now()))
          }
        ),
        button(
          "Delete",
          onClick --> { _ =>
            store.dispatch(DeleteUser(user.id))
          }
        )
      )
    )
  }
}

// Main application entry point
@JSExportTopLevel("main")
def main(): Unit = {
  val appContainer = document.getElementById("app")
  val app = UserManagementApp.createApp()
  render(appContainer, app)
}

// JavaScript interop
@js.native
@JSGlobal
object ExternalLibrary extends js.Object {
  def someFunction(param: String): String = js.native
}

// Calling JavaScript from Scala.js
object JSInterop {
  def callExternalFunction(input: String): String = {
    ExternalLibrary.someFunction(input)
  }

  // Exposing Scala functions to JavaScript
  @JSExport
  def processData(data: String): String = {
    // Process data using Scala logic
    data.toUpperCase.reverse
  }

  // Working with JavaScript promises
  def handlePromise(): Future[String] = {
    val jsPromise = js.Promise.resolve("Hello from JS")
    jsPromise.toFuture
  }
}

Advanced Scala.js Features

// Custom JavaScript types
@js.native
trait CustomJSObject extends js.Object {
  val name: String = js.native
  val value: Double = js.native
  def process(): String = js.native
}

// Union types for JavaScript
type StringOrNumber = String | Double

// Working with JavaScript arrays
import scala.scalajs.js.Array as JSArray

object ArrayOperations {
  def processJSArray(arr: JSArray[String]): JSArray[String] = {
    arr.filter(_.nonEmpty).map(_.toUpperCase)
  }

  def convertToScala(jsArr: JSArray[String]): List[String] = {
    jsArr.toList
  }

  def convertToJS(scalaList: List[String]): JSArray[String] = {
    JSArray(scalaList: _*)
  }
}

// Facade for external JavaScript library
@js.native
@JSGlobal("Chart")
class Chart(canvas: dom.html.Canvas, config: ChartConfig) extends js.Object {
  def update(): Unit = js.native
  def destroy(): Unit = js.native
}

@js.native
trait ChartConfig extends js.Object {
  val `type`: String = js.native
  val data: ChartData = js.native
  val options: js.UndefOr[ChartOptions] = js.native
}

@js.native
trait ChartData extends js.Object {
  val labels: JSArray[String] = js.native
  val datasets: JSArray[Dataset] = js.native
}

@js.native
trait Dataset extends js.Object {
  val label: String = js.native
  val data: JSArray[Double] = js.native
  val backgroundColor: js.UndefOr[String] = js.native
}

@js.native
trait ChartOptions extends js.Object {
  val responsive: js.UndefOr[Boolean] = js.native
  val plugins: js.UndefOr[js.Object] = js.native
}

// Using the Chart.js facade
object ChartExample {
  def createChart(canvas: dom.html.Canvas): Chart = {
    val config = js.Dynamic.literal(
      `type` = "bar",
      data = js.Dynamic.literal(
        labels = JSArray("Jan", "Feb", "Mar", "Apr"),
        datasets = JSArray(js.Dynamic.literal(
          label = "Sales",
          data = JSArray(12, 19, 3, 17),
          backgroundColor = "rgba(54, 162, 235, 0.2)"
        ))
      ),
      options = js.Dynamic.literal(
        responsive = true
      )
    ).asInstanceOf[ChartConfig]

    new Chart(canvas, config)
  }
}

// Web Workers with Scala.js
import org.scalajs.dom.Worker
import scala.concurrent.Promise

object WebWorkerExample {

  def createWorker(): Worker = {
    val workerCode = """
      self.addEventListener('message', function(e) {
        const data = e.data;
        // Perform heavy computation
        const result = heavyComputation(data);
        self.postMessage(result);
      });

      function heavyComputation(data) {
        // Simulate heavy work
        let sum = 0;
        for (let i = 0; i < data.iterations; i++) {
          sum += Math.sqrt(i);
        }
        return { result: sum, processed: data.iterations };
      }
    """

    val blob = new dom.Blob(js.Array(workerCode), js.Dynamic.literal(`type` = "application/javascript"))
    val workerUrl = dom.URL.createObjectURL(blob)
    new Worker(workerUrl)
  }

  def runHeavyComputation(iterations: Int): Future[js.Dynamic] = {
    val promise = Promise[js.Dynamic]()
    val worker = createWorker()

    worker.onmessage = { (e: dom.MessageEvent) =>
      promise.success(e.data.asInstanceOf[js.Dynamic])
      worker.terminate()
    }

    worker.onerror = { (e: dom.ErrorEvent) =>
      promise.failure(new Exception(e.message))
      worker.terminate()
    }

    val input = js.Dynamic.literal(iterations = iterations)
    worker.postMessage(input)
    promise.future
  }
}

// Service Worker registration
object ServiceWorkerExample {
  def registerServiceWorker(): Unit = {
    if (js.typeOf(dom.window.navigator.serviceWorker) != "undefined") {
      dom.window.navigator.serviceWorker.register("/sw.js").toFuture.foreach { registration =>
        console.log("Service Worker registered successfully")
      }
    }
  }
}

Scala Native: Native Platform Target

Setting Up Scala Native Projects

// build.sbt for Scala Native project
ThisBuild / scalaVersion := "3.3.0"

lazy val nativeApp = project
  .in(file("native"))
  .enablePlugins(ScalaNativePlugin)
  .settings(
    libraryDependencies ++= Seq(
      "com.lihaoyi" %%% "upickle" % "3.1.0",
      "com.lihaoyi" %%% "os-lib" % "0.9.1"
    ),
    nativeConfig ~= {
      _.withLTO(LTO.thin)
       .withMode(Mode.releaseFast)
       .withGC(GC.commix)
    }
  )
  .dependsOn(sharedNative)

Native Platform Implementation

// Platform implementation for Scala Native
import scala.scalanative.unsafe._
import scala.scalanative.unsigned._
import scala.scalanative.libc._
import scala.scalanative.posix.unistd
import java.io.{File, FileWriter, FileReader, BufferedReader}
import java.net.{URL, HttpURLConnection}
import scala.io.Source
import scala.util.{Try, Using}

object NativePlatform extends Platform {
  val name = "Native"

  def currentTimeMillis(): Long = System.currentTimeMillis()

  def randomUUID(): String = java.util.UUID.randomUUID().toString

  def readFile(path: String): Either[String, String] = {
    Try {
      Using(Source.fromFile(path))(_.mkString).get
    }.toEither.left.map(_.getMessage)
  }

  def writeFile(path: String, content: String): Either[String, Unit] = {
    Try {
      Using(new FileWriter(path)) { writer =>
        writer.write(content)
      }.get
    }.toEither.left.map(_.getMessage)
  }

  def httpGet(url: String): Either[String, String] = {
    Try {
      val connection = new URL(url).openConnection().asInstanceOf[HttpURLConnection]
      connection.setRequestMethod("GET")
      connection.setConnectTimeout(5000)
      connection.setReadTimeout(5000)

      val responseCode = connection.getResponseCode
      if (responseCode == 200) {
        Using(Source.fromInputStream(connection.getInputStream))(_.mkString).get
      } else {
        throw new RuntimeException(s"HTTP error: $responseCode")
      }
    }.toEither.left.map(_.getMessage)
  }

  def httpPost(url: String, body: String): Either[String, String] = {
    Try {
      val connection = new URL(url).openConnection().asInstanceOf[HttpURLConnection]
      connection.setRequestMethod("POST")
      connection.setDoOutput(true)
      connection.setRequestProperty("Content-Type", "application/json")
      connection.setConnectTimeout(5000)
      connection.setReadTimeout(5000)

      Using(connection.getOutputStream) { outputStream =>
        outputStream.write(body.getBytes("UTF-8"))
      }.get

      val responseCode = connection.getResponseCode
      if (responseCode == 200) {
        Using(Source.fromInputStream(connection.getInputStream))(_.mkString).get
      } else {
        throw new RuntimeException(s"HTTP error: $responseCode")
      }
    }.toEither.left.map(_.getMessage)
  }
}

// Native-specific utilities
object NativeUtils {

  // Direct memory management
  def allocateMemory(size: Int): Ptr[Byte] = {
    stdlib.malloc(size.toULong)
  }

  def freeMemory(ptr: Ptr[Byte]): Unit = {
    stdlib.free(ptr)
  }

  // C library interop
  @extern
  object LibC {
    def getpid(): CInt = extern
    def getppid(): CInt = extern
    def gethostname(name: Ptr[CChar], len: CSize): CInt = extern
  }

  def getCurrentProcessId(): Int = LibC.getpid()

  def getParentProcessId(): Int = LibC.getppid()

  def getHostname(): String = {
    val buffer = stackalloc[CChar](256)
    LibC.gethostname(buffer, 256.toULong)
    fromCString(buffer)
  }

  // File system operations
  def listDirectory(path: String): Either[String, List[String]] = {
    Try {
      val dir = new File(path)
      if (dir.exists() && dir.isDirectory) {
        dir.listFiles().map(_.getName).toList
      } else {
        throw new RuntimeException(s"Directory does not exist: $path")
      }
    }.toEither.left.map(_.getMessage)
  }

  def createDirectory(path: String): Either[String, Unit] = {
    Try {
      val dir = new File(path)
      if (!dir.mkdirs() && !dir.exists()) {
        throw new RuntimeException(s"Failed to create directory: $path")
      }
    }.toEither.left.map(_.getMessage)
  }

  def deleteFile(path: String): Either[String, Unit] = {
    Try {
      val file = new File(path)
      if (!file.delete()) {
        throw new RuntimeException(s"Failed to delete file: $path")
      }
    }.toEither.left.map(_.getMessage)
  }

  // Process execution
  def executeCommand(command: String, args: String*): Either[String, String] = {
    Try {
      val processBuilder = new ProcessBuilder((command +: args): _*)
      val process = processBuilder.start()

      val output = Using(Source.fromInputStream(process.getInputStream))(_.mkString).get
      val exitCode = process.waitFor()

      if (exitCode == 0) {
        output
      } else {
        val error = Using(Source.fromInputStream(process.getErrorStream))(_.mkString).get
        throw new RuntimeException(s"Command failed with exit code $exitCode: $error")
      }
    }.toEither.left.map(_.getMessage)
  }

  // Performance monitoring
  def getMemoryUsage(): Long = {
    Runtime.getRuntime.totalMemory() - Runtime.getRuntime.freeMemory()
  }

  def getCpuTime(): Long = {
    // Implementation would use native system calls
    System.nanoTime() // Simplified
  }
}

// Command-line application
object NativeApp {

  case class Config(
    action: String = "",
    inputFile: Option[String] = None,
    outputFile: Option[String] = None,
    verbose: Boolean = false
  )

  def parseArgs(args: Array[String]): Either[String, Config] = {
    args.toList match {
      case Nil => Left("No arguments provided")
      case action :: rest =>
        val config = rest.foldLeft(Config(action = action)) { (cfg, arg) =>
          arg match {
            case s if s.startsWith("--input=") => cfg.copy(inputFile = Some(s.drop(8)))
            case s if s.startsWith("--output=") => cfg.copy(outputFile = Some(s.drop(9)))
            case "--verbose" => cfg.copy(verbose = true)
            case _ => cfg
          }
        }
        Right(config)
    }
  }

  def processUsers(config: Config): Either[String, Unit] = {
    val userService = new UserService(NativePlatform)

    config.action match {
      case "create" =>
        val user = userService.createUser("John Doe", "john@example.com")
        user.map { u =>
          if (config.verbose) {
            println(s"Created user: ${u.name} (${u.id})")
          }
        }

      case "list" =>
        val users = userService.listUsers()
        users.foreach { user =>
          println(s"${user.id}: ${user.name} <${user.email}>")
        }
        Right(())

      case "export" =>
        config.outputFile match {
          case Some(file) =>
            userService.saveToFile(file).map { _ =>
              if (config.verbose) {
                println(s"Users exported to $file")
              }
            }
          case None => Left("Output file required for export")
        }

      case "import" =>
        config.inputFile match {
          case Some(file) =>
            userService.loadFromFile(file).map { _ =>
              if (config.verbose) {
                println(s"Users imported from $file")
              }
            }
          case None => Left("Input file required for import")
        }

      case unknown => Left(s"Unknown action: $unknown")
    }
  }

  def main(args: Array[String]): Unit = {
    parseArgs(args) match {
      case Left(error) =>
        System.err.println(s"Error: $error")
        println("Usage: app <action> [options]")
        println("Actions: create, list, export, import")
        println("Options: --input=file, --output=file, --verbose")
        System.exit(1)

      case Right(config) =>
        processUsers(config) match {
          case Left(error) =>
            System.err.println(s"Error: $error")
            System.exit(1)
          case Right(_) =>
            if (config.verbose) {
              println("Operation completed successfully")
            }
        }
    }
  }
}

// Native library integration
@link("sqlite3")
@extern
object SQLite {
  type Sqlite3 = Ptr[Byte]
  type Sqlite3Stmt = Ptr[Byte]

  def sqlite3_open(filename: CString, ppDb: Ptr[Sqlite3]): CInt = extern
  def sqlite3_close(db: Sqlite3): CInt = extern
  def sqlite3_prepare_v2(db: Sqlite3, zSql: CString, nByte: CInt, ppStmt: Ptr[Sqlite3Stmt], pzTail: Ptr[CString]): CInt = extern
  def sqlite3_step(stmt: Sqlite3Stmt): CInt = extern
  def sqlite3_finalize(stmt: Sqlite3Stmt): CInt = extern
  def sqlite3_column_text(stmt: Sqlite3Stmt, iCol: CInt): CString = extern
  def sqlite3_column_int(stmt: Sqlite3Stmt, iCol: CInt): CInt = extern
}

// SQLite database implementation
class NativeDatabase {
  import SQLite._

  private var db: Sqlite3 = _

  def open(filename: String): Either[String, Unit] = {
    Zone { implicit z =>
      val dbPtr = stackalloc[Sqlite3]()
      val result = sqlite3_open(toCString(filename), dbPtr)

      if (result == 0) {
        db = !dbPtr
        Right(())
      } else {
        Left(s"Failed to open database: $result")
      }
    }
  }

  def close(): Unit = {
    if (db != null) {
      sqlite3_close(db)
      db = null
    }
  }

  def execute(sql: String): Either[String, Unit] = {
    Zone { implicit z =>
      val stmtPtr = stackalloc[Sqlite3Stmt]()
      val result = sqlite3_prepare_v2(db, toCString(sql), -1, stmtPtr, null)

      if (result == 0) {
        val stmt = !stmtPtr
        val stepResult = sqlite3_step(stmt)
        sqlite3_finalize(stmt)

        if (stepResult == 101) { // SQLITE_DONE
          Right(())
        } else {
          Left(s"SQL execution failed: $stepResult")
        }
      } else {
        Left(s"SQL preparation failed: $result")
      }
    }
  }

  def query(sql: String): Either[String, List[Map[String, String]]] = {
    // Implementation for querying data
    Right(List.empty) // Simplified
  }
}

Code Sharing Strategies

Cross-Platform Architecture Patterns

// Abstract factory pattern for platform-specific implementations
trait PlatformFactory {
  def createFileSystem(): FileSystemOps
  def createNetworking(): NetworkOps  
  def createCrypto(): CryptoOps
  def createLogger(): Logger
}

object JVMFactory extends PlatformFactory {
  def createFileSystem(): FileSystemOps = new JVMFileSystem()
  def createNetworking(): NetworkOps = new JVMNetworking()
  def createCrypto(): CryptoOps = new JVMCrypto()
  def createLogger(): Logger = new JVMLogger()
}

object JSFactory extends PlatformFactory {
  def createFileSystem(): FileSystemOps = new JSFileSystem()
  def createNetworking(): NetworkOps = new JSNetworking()
  def createCrypto(): CryptoOps = new JSCrypto()
  def createLogger(): Logger = new JSLogger()
}

object NativeFactory extends PlatformFactory {
  def createFileSystem(): FileSystemOps = new NativeFileSystem()
  def createNetworking(): NetworkOps = new NativeNetworking()
  def createCrypto(): CryptoOps = new NativeCrypto()
  def createLogger(): Logger = new NativeLogger()
}

// Platform abstraction interfaces
trait FileSystemOps {
  def readText(path: String): Either[String, String]
  def writeText(path: String, content: String): Either[String, Unit]
  def exists(path: String): Boolean
  def listFiles(directory: String): Either[String, List[String]]
  def createDirectory(path: String): Either[String, Unit]
  def delete(path: String): Either[String, Unit]
}

trait NetworkOps {
  def httpGet(url: String, headers: Map[String, String] = Map.empty): Either[String, HttpResponse]
  def httpPost(url: String, body: String, headers: Map[String, String] = Map.empty): Either[String, HttpResponse]
  def httpPut(url: String, body: String, headers: Map[String, String] = Map.empty): Either[String, HttpResponse]
  def httpDelete(url: String, headers: Map[String, String] = Map.empty): Either[String, HttpResponse]
}

trait CryptoOps {
  def hash(data: String, algorithm: String = "SHA-256"): String
  def encrypt(data: String, key: String): Either[String, String]
  def decrypt(encryptedData: String, key: String): Either[String, String]
  def generateKey(): String
}

trait Logger {
  def debug(message: String): Unit
  def info(message: String): Unit
  def warn(message: String): Unit
  def error(message: String): Unit
  def error(message: String, throwable: Throwable): Unit
}

case class HttpResponse(
  status: Int,
  body: String,
  headers: Map[String, String]
)

// Cross-platform application framework
abstract class CrossPlatformApp {

  protected def platformFactory: PlatformFactory

  lazy val fileSystem: FileSystemOps = platformFactory.createFileSystem()
  lazy val networking: NetworkOps = platformFactory.createNetworking()
  lazy val crypto: CryptoOps = platformFactory.createCrypto()
  lazy val logger: Logger = platformFactory.createLogger()

  def initialize(): Either[String, Unit]
  def run(args: List[String]): Either[String, Unit]
  def shutdown(): Unit

  final def main(args: Array[String]): Unit = {
    logger.info("Application starting...")

    val result = for {
      _ <- initialize()
      _ <- run(args.toList)
    } yield ()

    result match {
      case Left(error) =>
        logger.error(s"Application failed: $error")
        System.exit(1)
      case Right(_) =>
        logger.info("Application completed successfully")
    }

    shutdown()
  }
}

// Shared business logic implementation
class UserManagementApp(val platformFactory: PlatformFactory) extends CrossPlatformApp {

  private val userService = new UserService(new PlatformAdapter(platformFactory))

  def initialize(): Either[String, Unit] = {
    logger.info("Initializing user management application")

    // Create necessary directories
    fileSystem.createDirectory("data").flatMap { _ =>
      fileSystem.createDirectory("logs")
    }
  }

  def run(args: List[String]): Either[String, Unit] = {
    args match {
      case "server" :: port :: Nil =>
        startServer(port.toInt)

      case "cli" :: command :: rest =>
        runCliCommand(command, rest)

      case "import" :: file :: Nil =>
        importUsers(file)

      case "export" :: file :: Nil =>
        exportUsers(file)

      case _ =>
        Left("Usage: app <server|cli|import|export> [args...]")
    }
  }

  def shutdown(): Unit = {
    logger.info("Shutting down application")
  }

  private def startServer(port: Int): Either[String, Unit] = {
    logger.info(s"Starting server on port $port")
    // Platform-specific server implementation would go here
    Right(())
  }

  private def runCliCommand(command: String, args: List[String]): Either[String, Unit] = {
    command match {
      case "create" if args.length >= 2 =>
        val name = args(0)
        val email = args(1)
        userService.createUser(name, email).map { user =>
          logger.info(s"Created user: ${user.name}")
        }

      case "list" =>
        val users = userService.listUsers()
        users.foreach { user =>
          println(s"${user.id}: ${user.name} <${user.email}>")
        }
        Right(())

      case "update" if args.length >= 3 =>
        val id = args(0)
        val name = args(1)
        val email = args(2)
        userService.updateUser(id, Some(name), Some(email)).map { user =>
          logger.info(s"Updated user: ${user.name}")
        }

      case _ =>
        Left("Invalid CLI command")
    }
  }

  private def importUsers(file: String): Either[String, Unit] = {
    userService.loadFromFile(file)
  }

  private def exportUsers(file: String): Either[String, Unit] = {
    userService.saveToFile(file)
  }
}

// Platform adapter
class PlatformAdapter(factory: PlatformFactory) extends Platform {
  private val fs = factory.createFileSystem()
  private val net = factory.createNetworking()
  private val crypto = factory.createCrypto()

  val name: String = "Cross-Platform"

  def currentTimeMillis(): Long = System.currentTimeMillis()

  def randomUUID(): String = java.util.UUID.randomUUID().toString

  def readFile(path: String): Either[String, String] = fs.readText(path)

  def writeFile(path: String, content: String): Either[String, Unit] = fs.writeText(path, content)

  def httpGet(url: String): Either[String, String] = 
    net.httpGet(url).map(_.body)

  def httpPost(url: String, body: String): Either[String, String] = 
    net.httpPost(url, body).map(_.body)
}

Build Configuration and Automation


// Multi-platform build configuration
// build.sbt
ThisBuild / scalaVersion := "3.3.0"
ThisBuild / organization := "com.example"
ThisBuild / version := "1.0.0"

lazy val commonSettings = Seq(
  scalacOptions ++= Seq(
    "-deprecation",
    "-feature",
    "-unchecked",
    "-Xlint",
    "-Ywarn-dead-code",
    "-Ywarn-numeric-widen"
  )
)

// Shared modules
lazy val shared = crossProject(JSPlatform, JVMPlatform, NativePlatform)
  .crossType(CrossType.Pure)
  .in(file("modules/shared"))
  .settings(commonSettings)
  .settings(
    libraryDependencies ++= Seq(
      "org.typelevel" %%% "cats-core" % "2.9.0",
      "org.typelevel" %%% "cats-effect" % "3.5.0",
      "io.circe" %%% "circe-core" % "0.14.5",
      "io.circe" %%% "circe-generic" % "0.14.5",
      "io.circe" %%% "circe-parser" % "0.14.5"
    )
  )
  .jvmSettings(
    libraryDependencies ++= Seq(
      "org.scalatest" %% "scalatest" % "3.2.15" % Test
    )
  )
  .jsSettings(
    libraryDependencies ++= Seq(
      "org.scala-js" %%% "scalajs-dom" % "2.4.0"
    )
  )
  .nativeSettings(
    libraryDependencies ++= Seq(
      "com.lihaoyi" %%% "os-lib" % "0.9.1"
    )
  )

lazy val sharedJvm = shared.jvm
lazy val sharedJs = shared.js  
lazy val sharedNative = shared.native

// JVM server application
lazy val server = project
  .in(file("modules/server"))
  .settings(commonSettings)
  .settings(
    libraryDependencies ++= Seq(
      "com.typesafe.akka" %% "akka-http" % "10.5.0",
      "com.typesafe.akka" %% "akka-stream" % "2.8.0",
      "com.typesafe.akka" %% "akka-actor-typed" % "2.8.0",
      "ch.qos.logback" % "logback-classic" % "1.4.7",
      "com.h2database" % "h2" % "2.1.214"
    ),
    Docker / packageName := "user-management-server",
    dockerBaseImage := "openjdk:17-jre-slim"
  )
  .enablePlugins(JavaAppPackaging, DockerPlugin)
  .dependsOn(sharedJvm)

// JavaScript client application
lazy val client = project
  .in(file("modules/client"))
  .enablePlugins(ScalaJSPlugin)
  .settings(commonSettings)
  .settings(
    libraryDependencies ++= Seq(
      "org.scala-js" %%% "scalajs-dom" % "2.4.0",
      "com.raquo" %%% "laminar" % "15.0.1"
    ),
    scalaJSUseMainModuleInitializer := true,
    scalaJSLinkerConfig ~= {
      _.withModuleKind(ModuleKind.ESModule)
       .withOptimizer(true)
    },
    Assets / pipelineStages := Seq(scalaJSPipeline)
  )
  .dependsOn(sharedJs)

// Native CLI application
lazy val cli = project
  .in(file("modules/cli"))
  .enablePlugins(ScalaNativePlugin)
  .settings(commonSettings)
  .settings(
    nativeConfig ~= {
      _.withLTO(LTO.thin)
       .withMode(Mode.releaseFast)
       .withGC(GC.commix)
    },
    nativeLinkStubs := true
  )
  .dependsOn(sharedNative)

// Testing across platforms
lazy val tests = crossProject(JSPlatform, JVMPlatform, NativePlatform)
  .crossType(CrossType.Pure)
  .in(file("modules/tests"))
  .settings(commonSettings)
  .settings(
    libraryDependencies ++= Seq(
      "org.scalatest" %%% "scalatest" % "3.2.15" % Test,
      "org.scalatestplus" %%% "scalacheck-1-17" % "3.2.15.0" % Test
    )
  )
  .dependsOn(shared)

lazy val testsJvm = tests.jvm
lazy val testsJs = tests.js
lazy val testsNative = tests.native

// Custom SBT tasks for multi-platform operations
lazy val buildAll = taskKey[Unit]("Build all platform targets")
lazy val testAll = taskKey[Unit]("Test all platform targets")
lazy val packageAll = taskKey[Unit]("Package all platform targets")

buildAll := {
  (sharedJvm / compile).value
  (sharedJs / compile).value
  (sharedNative / compile).value
  (server / compile).value
  (client / compile).value
  (cli / compile).value
}

testAll := {
  (testsJvm / test).value
  (testsJs / test).value
  (testsNative / test).value
}

packageAll := {
  (server / Docker / publishLocal).value
  (client / fastOptJS).value
  (cli / nativeLink).value
}

// CI/CD configuration
// .github/workflows/ci.yml
/*
name: CI

on: [push, pull_request]