Scala

#26
TIOBE#31
PYPL#22
GitHub#70
RedMonk#14
IEEESpectrum#22
JetBrains#19
programming languagefunctional programmingobject-orientedJVMbig dataconcurrent processing

Programming Language

Scala

Overview

Scala is a multi-paradigm programming language that runs on the JVM, combining functional programming and object-oriented programming.

Details

Scala (Scalable Language) is a programming language developed by Martin Odersky in 2003 that integrates both functional and object-oriented programming paradigms and runs on the Java Virtual Machine (JVM). It features static typing with type inference for concise code, emphasizes immutability, and provides higher-order functions, pattern matching, and flexible inheritance through traits. It is widely adopted in large-scale distributed systems and big data processing frameworks such as Apache Spark, Apache Kafka, and Akka, particularly providing powerful capabilities in concurrent processing and reactive programming. High compatibility with Java allows leveraging existing Java libraries while enabling practical application development with the benefits of functional programming.

Code Examples

Hello World

// Basic output
object HelloWorld extends App {
    println("Hello, World!")
    
    // Output using variables
    val message = "Hello, Scala!"
    println(message)
    
    // String interpolation
    val name = "John"
    val age = 25
    println(s"My name is $name and I am $age years old.")
    
    // Format strings
    printf("Number: %d, Float: %.2f%n", 42, 3.14159)
}

// Using main function
object HelloWorldMain {
    def main(args: Array[String]): Unit = {
        println("Hello, World!")
    }
}

Variables and Data Types

object VariablesAndTypes extends App {
    // Immutable variables (val)
    val immutableInt: Int = 42
    val immutableString: String = "string"
    val immutableDouble: Double = 3.14159
    val immutableBoolean: Boolean = true
    
    // Mutable variables (var)
    var mutableInt: Int = 100
    var mutableString: String = "mutable"
    
    // Type inference
    val inferredInt = 42        // Inferred as Int
    val inferredString = "text" // Inferred as String
    
    // Collection types
    val list: List[Int] = List(1, 2, 3, 4, 5)
    val array: Array[String] = Array("a", "b", "c")
    val map: Map[String, Int] = Map("one" -> 1, "two" -> 2, "three" -> 3)
    val set: Set[Int] = Set(1, 2, 3, 2, 1) // Duplicates removed
    
    // Tuples
    val tuple2: (String, Int) = ("John", 25)
    val tuple3: (String, Int, Boolean) = ("Jane", 30, true)
    
    // Option type (alternative to null)
    val someValue: Option[String] = Some("has value")
    val noneValue: Option[String] = None
    
    // Output examples
    println(s"Integer: $immutableInt")
    println(s"List length: ${list.length}")
    println(s"Map value: ${map("one")}")
    println(s"Tuple first element: ${tuple2._1}")
    
    // Variable modification
    mutableInt = 200
    println(s"Modified value: $mutableInt")
}

Conditional Statements

object ConditionalStatements extends App {
    val score = 85
    
    // Basic if expression
    val grade = if (score >= 90) {
        "A"
    } else if (score >= 80) {
        "B"
    } else if (score >= 70) {
        "C"
    } else {
        "D"
    }
    
    println(s"Score: $score, Grade: $grade")
    
    // Multiple condition combinations
    val age = 20
    val hasLicense = true
    
    val canDrive = if (age >= 18 && hasLicense) {
        "You can drive"
    } else if (age >= 18) {
        "Please get a license"
    } else {
        "Please get a license after turning 18"
    }
    
    println(canDrive)
    
    // Pattern matching
    val day = "Wednesday"
    val dayType = day match {
        case "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" => "Weekday"
        case "Saturday" | "Sunday" => "Weekend"
        case _ => "Unknown"
    }
    
    println(s"$day is a $dayType")
    
    // Pattern matching with values
    val number = 42
    val numberDescription = number match {
        case 0 => "Zero"
        case n if n > 0 && n <= 10 => "Number between 1 and 10"
        case n if n > 10 && n <= 100 => "Number between 11 and 100"
        case _ => "Other number"
    }
    
    println(s"$number is $numberDescription")
    
    // Option pattern matching
    val optionalValue: Option[String] = Some("value")
    val result = optionalValue match {
        case Some(value) => s"Has value: $value"
        case None => "No value"
    }
    
    println(result)
}

Collections and Higher-Order Functions

object CollectionsAndHigherOrderFunctions extends App {
    // List operations
    val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    
    // map function (transformation)
    val squares = numbers.map(x => x * x)
    val squaresShort = numbers.map(_ * _) // More concise syntax
    println(s"Squares: $squares")
    
    // filter function (filtering)
    val evenNumbers = numbers.filter(x => x % 2 == 0)
    val evenNumbersShort = numbers.filter(_ % 2 == 0)
    println(s"Even numbers: $evenNumbers")
    
    // reduce function (folding)
    val sum = numbers.reduce((a, b) => a + b)
    val sumShort = numbers.reduce(_ + _)
    println(s"Sum: $sum")
    
    // fold function (folding with initial value)
    val product = numbers.fold(1)((a, b) => a * b)
    println(s"Product: $product")
    
    // Function chaining
    val result = numbers
        .filter(_ % 2 == 0)      // Even numbers only
        .map(_ * 3)              // Multiply by 3
        .filter(_ > 10)          // Greater than 10
        .sum                     // Sum
    
    println(s"Chain processing result: $result")
    
    // for expression (comprehension)
    val combinations = for {
        x <- List(1, 2, 3)
        y <- List('a', 'b', 'c')
        if x > 1  // Guard condition
    } yield (x, y)
    
    println(s"Combinations: $combinations")
    
    // Nested for expression
    val matrix = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))
    val flattenedDoubled = for {
        row <- matrix
        element <- row
        if element % 2 == 0
    } yield element * 2
    
    println(s"Flattened and doubled: $flattenedDoubled")
    
    // Map operations
    val grades = Map("John" -> 85, "Jane" -> 92, "Bob" -> 78)
    
    // Map transformation
    val adjustedGrades = grades.map { case (name, grade) => 
        name -> (grade + 5) 
    }
    println(s"Adjusted grades: $adjustedGrades")
    
    // Map filtering
    val highGrades = grades.filter { case (_, grade) => grade >= 80 }
    println(s"High grades: $highGrades")
}

Function Definition and Higher-Order Functions

object FunctionsAndHigherOrder extends App {
    // Basic function definition
    def greet(name: String): String = {
        s"Hello, $name!"
    }
    
    // Single expression function (omit braces)
    def square(x: Int): Int = x * x
    
    // Default arguments
    def calculateArea(width: Double, height: Double = 10.0): Double = {
        width * height
    }
    
    // Variable arguments
    def sum(numbers: Int*): Int = {
        numbers.sum
    }
    
    // Higher-order function (takes function as argument)
    def applyOperation(x: Int, y: Int, operation: (Int, Int) => Int): Int = {
        operation(x, y)
    }
    
    // Function returning function
    def createMultiplier(factor: Int): Int => Int = {
        (x: Int) => x * factor
    }
    
    // Anonymous functions (lambda functions)
    val add = (x: Int, y: Int) => x + y
    val multiply = (x: Int, y: Int) => x * y
    
    // Partial application
    def addThreeNumbers(x: Int, y: Int, z: Int): Int = x + y + z
    val addFive = addThreeNumbers(5, _, _) // Fix first argument to 5
    
    // Currying
    def curriedAdd(x: Int)(y: Int)(z: Int): Int = x + y + z
    val addTen = curriedAdd(10) _
    val addTenAndFive = addTen(5)
    
    // Function usage examples
    println(greet("Alice"))
    println(s"Area: ${calculateArea(5.0)}")
    println(s"Sum: ${sum(1, 2, 3, 4, 5)}")
    
    println(s"Operation result: ${applyOperation(10, 20, add)}")
    println(s"Operation result: ${applyOperation(10, 20, multiply)}")
    
    val doubler = createMultiplier(2)
    println(s"Double: ${doubler(15)}")
    
    println(s"Partial application: ${addFive(10, 15)}")
    println(s"Currying: ${addTenAndFive(7)}")
    
    // Recursive function
    def factorial(n: Int): Int = {
        if (n <= 1) 1
        else n * factorial(n - 1)
    }
    
    // Tail recursion optimization
    @scala.annotation.tailrec
    def factorialTailRec(n: Int, acc: Int = 1): Int = {
        if (n <= 1) acc
        else factorialTailRec(n - 1, n * acc)
    }
    
    println(s"Factorial: ${factorial(5)}")
    println(s"Tail recursive factorial: ${factorialTailRec(5)}")
}

Classes and Object-Oriented Programming

// Basic class definition
class Person(val name: String, var age: Int) {
    // Private field
    private var _id: String = ""
    
    // Secondary constructor
    def this(name: String, age: Int, id: String) = {
        this(name, age)
        this._id = id
    }
    
    // Method
    def greet(): String = s"Hello, I'm $name."
    
    def haveBirthday(): Unit = {
        age += 1
        println(s"$name is now $age years old.")
    }
    
    // getter/setter
    def id: String = _id
    def id_=(newId: String): Unit = {
        if (newId.nonEmpty) _id = newId
    }
    
    override def toString: String = s"Person($name, $age)"
}

// Inheritance
abstract class Animal(val name: String) {
    def makeSound(): String // Abstract method
    
    def introduce(): String = s"I'm an animal named $name."
}

class Dog(name: String, val breed: String) extends Animal(name) {
    override def makeSound(): String = "Woof"
    
    def fetch(): String = s"$name fetched the ball."
}

class Cat(name: String, val color: String) extends Animal(name) {
    override def makeSound(): String = "Meow"
    
    def purr(): String = s"$name is purring."
}

// Trait
trait Flyable {
    def fly(): String = "Flying in the sky"
    def altitude: Double // Abstract field
}

trait Swimmable {
    def swim(): String = "Swimming in water"
}

// Multiple trait mixin
class Duck(name: String) extends Animal(name) with Flyable with Swimmable {
    override def makeSound(): String = "Quack"
    override val altitude: Double = 100.0
    
    override def fly(): String = s"$name is flying at ${altitude}m altitude"
    override def swim(): String = s"$name is swimming in the pond"
}

// Case class
case class Point(x: Double, y: Double) {
    def distance(other: Point): Double = {
        math.sqrt(math.pow(x - other.x, 2) + math.pow(y - other.y, 2))
    }
}

// Singleton object
object MathUtils {
    val PI: Double = 3.14159
    
    def circleArea(radius: Double): Double = PI * radius * radius
    
    def max(a: Int, b: Int): Int = if (a > b) a else b
}

// Usage example
object ObjectOrientedExample extends App {
    // Class instantiation
    val person1 = new Person("John Doe", 30)
    val person2 = new Person("Jane Smith", 25, "ID001")
    
    println(person1.greet())
    person1.haveBirthday()
    
    // Inheritance and polymorphism
    val animals: List[Animal] = List(
        new Dog("Buddy", "Golden Retriever"),
        new Cat("Whiskers", "Tabby"),
        new Duck("Donald")
    )
    
    animals.foreach { animal =>
        println(s"${animal.introduce()} Sound: ${animal.makeSound()}")
    }
    
    // Trait usage
    val duck = new Duck("Daffy")
    println(duck.fly())
    println(duck.swim())
    
    // Case class usage
    val point1 = Point(0, 0)
    val point2 = Point(3, 4)
    println(s"Distance: ${point1.distance(point2)}")
    
    // Pattern matching with case class decomposition
    point1 match {
        case Point(0, 0) => println("Origin point")
        case Point(x, 0) => println(s"Point on x-axis ($x, 0)")
        case Point(0, y) => println(s"Point on y-axis (0, $y)")
        case Point(x, y) => println(s"General point ($x, $y)")
    }
    
    // Singleton object usage
    println(s"Circle area: ${MathUtils.circleArea(5.0)}")
    println(s"Maximum: ${MathUtils.max(10, 20)}")
}

Concurrency and Future

import scala.concurrent.{Future, ExecutionContext}
import scala.util.{Success, Failure}
import scala.concurrent.duration._

object ConcurrencyExample extends App {
    // Implicit ExecutionContext
    implicit val ec: ExecutionContext = ExecutionContext.global
    
    // Basic Future
    val future1: Future[Int] = Future {
        Thread.sleep(1000)
        42
    }
    
    val future2: Future[String] = Future {
        Thread.sleep(500)
        "Hello, Future!"
    }
    
    // Transform Future result
    val doubledFuture: Future[Int] = future1.map(_ * 2)
    
    // Combine Futures
    val combinedFuture: Future[String] = for {
        number <- future1
        text <- future2
    } yield s"$text Number: $number"
    
    // Handle Future completion
    future1.onComplete {
        case Success(value) => println(s"Success: $value")
        case Failure(exception) => println(s"Failure: ${exception.getMessage}")
    }
    
    // Execute multiple Futures in parallel
    val futures = List(
        Future { Thread.sleep(100); 1 },
        Future { Thread.sleep(200); 2 },
        Future { Thread.sleep(150); 3 }
    )
    
    val allResults: Future[List[Int]] = Future.sequence(futures)
    
    // Error handling
    val riskyFuture: Future[Int] = Future {
        if (scala.util.Random.nextBoolean()) {
            throw new RuntimeException("An error occurred")
        }
        100
    }
    
    val safeFuture: Future[Int] = riskyFuture.recover {
        case _: RuntimeException => 0
    }
    
    // Wait for Future result (not recommended in actual applications)
    import scala.concurrent.Await
    
    try {
        val result = Await.result(combinedFuture, 2.seconds)
        println(s"Result: $result")
    } catch {
        case _: java.util.concurrent.TimeoutException =>
            println("Timeout occurred")
    }
    
    // Wait for application termination
    Thread.sleep(2000)
}

Special Features

Advanced Pattern Matching

object AdvancedPatternMatching extends App {
    // Sealed classes and pattern matching
    sealed trait Expression
    case class Number(value: Double) extends Expression
    case class Variable(name: String) extends Expression
    case class Add(left: Expression, right: Expression) extends Expression
    case class Multiply(left: Expression, right: Expression) extends Expression
    
    def evaluate(expr: Expression, variables: Map[String, Double]): Double = expr match {
        case Number(value) => value
        case Variable(name) => variables.getOrElse(name, 0.0)
        case Add(left, right) => evaluate(left, variables) + evaluate(right, variables)
        case Multiply(left, right) => evaluate(left, variables) * evaluate(right, variables)
    }
    
    // List pattern matching
    def listPattern(list: List[Int]): String = list match {
        case Nil => "Empty list"
        case head :: Nil => s"Single element: $head"
        case head :: tail => s"Head: $head, Tail: $tail"
    }
    
    // Pattern matching with guard conditions
    def classifyNumber(x: Int): String = x match {
        case n if n < 0 => "Negative number"
        case 0 => "Zero"
        case n if n > 0 && n <= 10 => "1 to 10"
        case n if n > 10 => "Greater than 10"
    }
    
    // Usage examples
    val expr = Add(Number(10), Multiply(Variable("x"), Number(5)))
    val vars = Map("x" -> 3.0)
    println(s"Calculation result: ${evaluate(expr, vars)}")
    
    println(listPattern(List(1, 2, 3)))
    println(classifyNumber(5))
}

Implicit Conversions and Type Classes

object ImplicitsExample extends App {
    // Implicit conversions
    implicit class StringOps(s: String) {
        def isPalindrome: Boolean = s == s.reverse
        def toSnakeCase: String = s.replaceAll("([A-Z])", "_$1").toLowerCase.dropWhile(_ == '_')
    }
    
    // Implicit parameters
    implicit val defaultTimeout: Int = 5000
    
    def connectToServer(host: String)(implicit timeout: Int): String = {
        s"Connecting to $host within ${timeout}ms"
    }
    
    // Type class pattern
    trait Printable[T] {
        def format(value: T): String
    }
    
    implicit val intPrintable: Printable[Int] = new Printable[Int] {
        def format(value: Int): String = s"Integer: $value"
    }
    
    implicit val stringPrintable: Printable[String] = new Printable[String] {
        def format(value: String): String = s"String: '$value'"
    }
    
    def print[T](value: T)(implicit printer: Printable[T]): Unit = {
        println(printer.format(value))
    }
    
    // Usage examples
    println("racecar".isPalindrome)
    println("CamelCase".toSnakeCase)
    
    println(connectToServer("localhost"))
    
    print(42)
    print("Hello")
}

Monads and for-expressions

object MonadExample extends App {
    // Option monad
    def safeDivide(x: Double, y: Double): Option[Double] = {
        if (y != 0) Some(x / y) else None
    }
    
    def safeSquareRoot(x: Double): Option[Double] = {
        if (x >= 0) Some(math.sqrt(x)) else None
    }
    
    // Monadic operations
    val result1 = for {
        division <- safeDivide(10, 2)
        sqrt <- safeSquareRoot(division)
    } yield sqrt
    
    println(s"Safe calculation result: $result1")
    
    // Either monad (error handling)
    sealed trait ValidationError
    case object InvalidAge extends ValidationError
    case object InvalidEmail extends ValidationError
    
    def validateAge(age: Int): Either[ValidationError, Int] = {
        if (age >= 0 && age <= 150) Right(age) else Left(InvalidAge)
    }
    
    def validateEmail(email: String): Either[ValidationError, String] = {
        if (email.contains("@")) Right(email) else Left(InvalidEmail)
    }
    
    case class User(age: Int, email: String)
    
    def createUser(age: Int, email: String): Either[ValidationError, User] = {
        for {
            validAge <- validateAge(age)
            validEmail <- validateEmail(email)
        } yield User(validAge, validEmail)
    }
    
    println(createUser(25, "[email protected]"))
    println(createUser(-5, "invalid-email"))
}

Versions

Version Status Key Features Release Year
Scala 3 (Dotty) Latest New syntax, improved type system, macro overhaul 2021
Scala 2.13 Current Collection library overhaul, performance improvements 2019
Scala 2.12 Maintained Java 8 support, SAM types, lambda optimization 2016
Scala 2.11 Legacy Modularization, macro stabilization 2014

Reference Pages

Official Documentation

Learning Resources

Frameworks and Libraries