Scala

Scala

Top Interview Questions

About Scala

 

Scala: A Comprehensive Overview

Scala is a high-level programming language that combines the features of object-oriented and functional programming. Developed by Martin Odersky and first released in 2003, Scala has become a popular choice among developers for building scalable, efficient, and robust applications. The name "Scala" is derived from "scalable language," reflecting its ability to grow with the demands of software development, whether for small scripts or large enterprise systems.

Key Features of Scala

  1. Object-Oriented and Functional Programming:
    Scala seamlessly integrates object-oriented programming (OOP) with functional programming (FP). In OOP, everything is an object, and in FP, functions are first-class citizens. Scala allows developers to leverage both paradigms, enabling highly expressive and concise code. This dual nature makes Scala versatile and well-suited for a variety of programming tasks.

  2. Strong Static Typing with Type Inference:
    Scala has a strong static type system, meaning types are checked at compile time, reducing runtime errors. However, it also supports type inference, allowing the compiler to automatically deduce types, which reduces boilerplate code. For instance, a variable declaration in Scala can often omit explicit type information, making the code cleaner without losing safety.

    val name = "Yash"  // Compiler infers type as String
    
  3. Immutable Data Structures:
    Functional programming in Scala encourages immutability, meaning once a value is assigned, it cannot be changed. This leads to safer and more predictable code, which is especially beneficial in concurrent or multi-threaded environments. Scala’s standard library provides a rich set of immutable collections, such as List, Map, and Set.

  4. Concurrency Support:
    Scala offers robust concurrency support through the actor model, primarily using the Akka framework. Actors in Scala are lightweight, asynchronous entities that communicate via message passing, which simplifies the development of highly concurrent applications while avoiding the pitfalls of traditional thread-based concurrency.

  5. Interoperability with Java:
    One of Scala's most significant advantages is its seamless interoperability with Java. Scala runs on the Java Virtual Machine (JVM), allowing developers to use existing Java libraries and frameworks. This feature makes Scala a natural choice for Java developers seeking functional programming features without leaving the JVM ecosystem.

  6. Pattern Matching:
    Scala’s pattern matching is a powerful feature, often compared to switch statements in other languages but far more flexible. It allows developers to destructure objects, extract values, and handle complex conditions in a clean and readable manner.

    val number = 3
    number match {
      case 1 => println("One")
      case 2 => println("Two")
      case _ => println("Other")
    }
    
  7. Higher-Order Functions and Closures:
    Scala supports higher-order functions, which are functions that take other functions as parameters or return functions as results. This enables a functional style of programming and allows developers to write highly reusable and modular code. Closures, which capture the environment in which they were defined, further enhance the language’s expressiveness.

Scala Syntax and Example

Scala syntax is concise and expressive. Here’s a simple example demonstrating object-oriented and functional concepts:

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val numbers = List(1, 2, 3, 4, 5)
    val squares = numbers.map(x => x * x)  // Functional programming
    println(s"Squares: $squares")
  }
}

In this example:

  • List is an immutable collection.

  • map is a higher-order function that applies a function to each element.

  • val denotes an immutable variable.

Advantages of Scala

  1. Conciseness and Expressiveness:
    Scala reduces boilerplate code significantly compared to Java. Developers can achieve the same functionality with fewer lines of code, improving readability and maintainability.

  2. Scalability:
    True to its name, Scala is highly scalable. It can be used for small scripts as well as large, complex systems, making it ideal for startups and enterprises alike.

  3. Functional Programming Benefits:
    Functional programming reduces side effects and encourages immutability, leading to safer and more predictable code. This is particularly useful in building concurrent applications.

  4. Integration with Big Data Ecosystem:
    Scala has become the language of choice for many big data technologies, such as Apache Spark. Spark’s core APIs are written in Scala, providing seamless performance and interoperability.

  5. Rich Standard Library:
    Scala provides a powerful and expressive standard library that supports both functional and object-oriented programming paradigms. Its collections library, for instance, is highly functional and offers many utility methods.

Use Cases of Scala

  1. Big Data and Analytics:
    Scala is widely used in big data processing due to its compatibility with Apache Spark. Its functional programming paradigm is well-suited for distributed computing, data transformation, and streaming.

  2. Web Development:
    Frameworks like Play and Akka HTTP allow developers to build reactive and scalable web applications using Scala. These frameworks emphasize asynchronous, non-blocking architectures, enhancing performance.

  3. Concurrent and Distributed Systems:
    Scala’s actor-based concurrency model via Akka is ideal for building high-performance, fault-tolerant distributed systems. Applications can handle thousands of concurrent users efficiently.

  4. Machine Learning and AI:
    Libraries such as Breeze and Spark MLlib leverage Scala for numerical computing and machine learning tasks. Scala’s expressive syntax and performance on the JVM make it suitable for computationally intensive tasks.

  5. Financial and Enterprise Applications:
    Many financial institutions prefer Scala for building trading platforms, risk management systems, and enterprise applications due to its strong typing, immutability, and functional features that reduce runtime errors.

Scala vs. Other Languages

  • Scala vs. Java: Scala offers concise syntax, functional programming features, and immutability while maintaining Java interoperability. It is generally more expressive and reduces boilerplate code.

  • Scala vs. Python: Scala is statically typed and runs on the JVM, offering better performance than Python. While Python is dynamically typed and easier for beginners, Scala is preferred for large-scale systems requiring strong typing and concurrency.

  • Scala vs. Kotlin: Both run on the JVM, but Scala emphasizes functional programming and immutability more than Kotlin. Kotlin is often seen as more beginner-friendly with simpler syntax.

Challenges in Scala

Despite its strengths, Scala comes with some challenges:

  • Steep Learning Curve: Scala’s combination of OOP and FP can be intimidating for beginners.

  • Compilation Speed: Scala’s compilation can be slower compared to Java, especially in large projects.

  • Complexity: Highly expressive syntax can lead to complex code that is difficult to maintain if not carefully written.

  • Smaller Talent Pool: While growing, Scala developers are less abundant than Java or Python developers, which can impact hiring for enterprise projects.

 

Fresher Interview Questions

 

1. Basics of Scala

Q1. What is Scala?
Answer:
Scala is a high-level, general-purpose programming language that combines object-oriented and functional programming paradigms. It runs on the Java Virtual Machine (JVM), allowing seamless integration with Java. The name "Scala" comes from “scalable language”, meaning it can grow with application complexity.


Q2. What are the features of Scala?
Answer:

  • Object-Oriented: Everything in Scala is an object.

  • Functional Programming: Functions are first-class citizens.

  • Type Inference: Compiler can automatically deduce variable types.

  • Immutable by Default: Encourages immutability and safer code.

  • Concurrency Support: Through Akka actor model.

  • Interoperable with Java: Can use Java libraries seamlessly.

  • Pattern Matching: Simplifies branching logic.


Q3. What is the difference between Scala and Java?
Answer:

Feature Scala Java
Paradigm Functional + Object-Oriented Object-Oriented
Type Inference Yes No (strictly typed)
Syntax Concise Verbose
Immutability Encouraged by default Not enforced
Collections Rich and functional Less functional
Pattern Matching Yes No (requires verbose code)

Q4. What are the data types in Scala?
Answer:

  • Numeric Types: Int, Long, Float, Double, Short, Byte

  • Boolean: true/false

  • Character: Char

  • String

  • Unit: Represents void

  • Null and Nothing types


Q5. What is a Scala object?
Answer:
An object is a singleton instance of a class in Scala. Unlike Java, you don’t need to create an instance to use it. It’s often used for utility methods or the main method of a program.

object MyObject {
  def greet(): Unit = println("Hello, Scala!")
}

MyObject.greet()

2. Object-Oriented Programming in Scala

Q6. What is a class in Scala?
Answer:
A class is a blueprint for objects. It can have fields, methods, and constructors.

class Person(val name: String, var age: Int) {
  def greet(): Unit = println(s"Hello, my name is $name and I am $age years old")
}

val p = new Person("Yash", 25)
p.greet()

Q7. What are case classes?
Answer:
Case classes are special classes for immutable data structures. They automatically provide:

  • equals and hashCode

  • toString

  • copy method

  • Pattern matching support

case class Student(name: String, age: Int)
val s = Student("Yash", 25)
println(s.name) // Yash

Q8. What are traits in Scala?
Answer:
Traits are like interfaces in Java, but they can also contain implementation code. A class can inherit multiple traits.

trait Greeter {
  def greet(): Unit = println("Hello from trait")
}

class Person extends Greeter
val p = new Person
p.greet()  // Hello from trait

Q9. Explain Scala constructors.
Answer:

  • Primary constructor: Defined with class parameters.

  • Auxiliary constructor: Defined using def this() inside the class.

class Person(name: String) {
  var age: Int = 0
  def this(name: String, age: Int) = {
    this(name)
    this.age = age
  }
}

3. Functional Programming in Scala

Q10. What is a function in Scala?
Answer:
A function is a first-class citizen. You can assign it to variables, pass it as arguments, and return it from other functions.

val add = (a: Int, b: Int) => a + b
println(add(2, 3)) // 5

Q11. What is immutability in Scala?
Answer:

  • Immutable objects cannot be changed once created.

  • Encouraged to reduce bugs in multi-threaded applications.

val x = 10  // immutable
var y = 20  // mutable

Q12. What is higher-order function?
Answer:
A function that takes another function as a parameter or returns a function.

def applyFunc(f: Int => Int, x: Int) = f(x)
val square = (x: Int) => x * x
println(applyFunc(square, 5))  // 25

Q13. What is a closure in Scala?
Answer:
A closure is a function that captures variables from its surrounding scope.

var factor = 3
val multiplier = (x: Int) => x * factor
println(multiplier(2))  // 6

Q14. What is pattern matching?
Answer:
Pattern matching in Scala is similar to switch-case in Java but more powerful. It can match types, values, and structures.

val day = "Mon"
day match {
  case "Mon" => println("Start of week")
  case "Fri" => println("End of week")
  case _ => println("Midweek")
}

4. Collections in Scala

Q15. What are Scala collections?
Answer:
Scala collections are categorized into mutable and immutable:

  • Immutable collections: List, Set, Map, Tuple

  • Mutable collections: ArrayBuffer, ListBuffer, HashMap


Q16. What is the difference between List and Array in Scala?

Feature List Array
Mutability Immutable Mutable
Size Fixed after creation Fixed
Performance Slower for updates Faster for updates
Syntax List(1,2,3) Array(1,2,3)

Q17. What is a Tuple?
Answer:
A Tuple can store fixed number of items of different types.

val t = (1, "Scala", true)
println(t._2)  // Scala

Q18. What is an Option in Scala?
Answer:
Option is a container for optional values, helps avoid NullPointerException.

val someValue: Option[Int] = Some(10)
val noneValue: Option[Int] = None

5. Advanced Scala Concepts

Q19. What is a companion object?
Answer:
A companion object shares the same name as a class and can access its private members.

class Person(val name: String)
object Person {
  def apply(name: String) = new Person(name)
}
val p = Person("Yash")

Q20. What is a Future in Scala?
Answer:
A Future represents asynchronous computation that may complete later.

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

val f = Future {
  1 + 2
}

f.map(result => println(s"Result is $result"))

Q21. What is currying in Scala?
Answer:
Currying is the process of transforming a function with multiple arguments into a chain of functions with single arguments.

def add(a: Int)(b: Int) = a + b
println(add(2)(3))  // 5

Q22. What are implicit parameters in Scala?
Answer:
Implicit parameters are automatically passed by the compiler if an implicit value is in scope.

def greet(implicit name: String) = println(s"Hello, $name")
implicit val myName = "Yash"
greet  // Hello, Yash

Q23. What is a Scala object vs class?
Answer:

Feature Class Object
Instantiation Can have multiple instances Singleton, one instance
Constructor Can have primary/auxiliary constructors No constructors
Inheritance Can extend classes/traits Can extend classes/traits

Q24. How is exception handling done in Scala?
Answer:
Using try-catch-finally, similar to Java:

try {
  val result = 10 / 0
} catch {
  case e: ArithmeticException => println("Cannot divide by zero")
} finally {
  println("Execution completed")
}

Q25. Difference between val, var, and def in Scala?

Keyword Description
val Immutable variable
var Mutable variable
def Defines a method or function

6. Scala Collections & Functional Programming (Advanced)

Q26. What is the difference between map, flatMap, and filter in Scala?

Answer:

  • map: Transforms each element of a collection.

val nums = List(1, 2, 3)
val squared = nums.map(x => x * x)  // List(1, 4, 9)
  • flatMap: Transforms each element into a collection and flattens the result.

val words = List("Hello", "World")
val chars = words.flatMap(word => word.toList)  // List(H, e, l, l, o, W, o, r, l, d)
  • filter: Selects elements based on a condition.

val nums = List(1, 2, 3, 4)
val even = nums.filter(_ % 2 == 0)  // List(2, 4)

Q27. What is the difference between varargs and sequences in Scala?

Answer:

  • Varargs allow passing a variable number of arguments to a function.

  • Sequences (Seq) are collections that can store multiple elements.

def printAll(nums: Int*) = nums.foreach(println)
printAll(1, 2, 3)

val seq: Seq[Int] = Seq(1, 2, 3)

Q28. Explain fold, reduce, and scan in Scala collections.

Answer:

  • reduce: Aggregates values using a binary operator; requires non-empty collection.

  • fold: Like reduce but allows an initial value.

  • scan: Like fold but returns all intermediate results as a collection.

val nums = List(1, 2, 3)
nums.reduce(_ + _)  // 6
nums.fold(0)(_ + _) // 6
nums.scan(0)(_ + _) // List(0, 1, 3, 6)

Q29. What are immutable and mutable collections?

Answer:

  • Immutable collections: Cannot be changed after creation (List, Set, Map).

  • Mutable collections: Can be modified (ArrayBuffer, ListBuffer, HashMap).

import scala.collection.mutable.ListBuffer

val mutableList = ListBuffer(1, 2, 3)
mutableList += 4  // ListBuffer(1, 2, 3, 4)

Q30. What is a Lazy evaluation in Scala?

Answer:
Lazy evaluation delays computation until the value is actually needed. Useful for expensive operations.

lazy val x = { println("Calculating"); 42 }
println("Before accessing x")
println(x)  // Only now "Calculating" is printed

7. Concurrency and Futures

Q31. How do you create a Future in Scala?

Answer:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

val f = Future {
  Thread.sleep(1000)
  42
}

f.map(result => println(s"Result: $result"))
  • Futures run asynchronously.

  • Use map, flatMap, or onComplete to handle results.


Q32. What is the difference between Future and Promise?

Answer:

Feature Future Promise
Purpose Holds a value that will be available later Can be completed to provide a value to a Future
Who completes it Immutable, completed by system Mutable, completed manually
Usage Read-only access Write access to complete a Future
import scala.concurrent.Promise
val p = Promise[Int]()
val f = p.future
p.success(10)  // Completes the future

Q33. What is the actor model in Scala?

Answer:
The actor model (used in Akka) allows concurrent computation using actors, which encapsulate state and behavior and communicate via messages instead of shared memory.

import akka.actor._

class MyActor extends Actor {
  def receive = {
    case msg => println(s"Received: $msg")
  }
}

val system = ActorSystem("MySystem")
val actor = system.actorOf(Props[MyActor], "actor1")
actor ! "Hello Actors"

8. Advanced Scala Concepts

Q34. What are implicit conversions?

Answer:
Implicit conversions automatically convert a value from one type to another if needed.

implicit def intToString(x: Int): String = x.toString
val s: String = 42  // automatically converted

Q35. What is the difference between Any, AnyVal, AnyRef, Nothing, and Null in Scala?

Answer:

Type Description
Any Supertype of all types
AnyVal Base type of all value types (Int, Boolean, etc.)
AnyRef Base type of all reference types (like Object in Java)
Nothing Subtype of all types; represents no value
Null Subtype of all reference types; represents null

Q36. What is tail recursion?

Answer:
Tail recursion is a recursion where the recursive call is the last operation. Scala optimizes tail-recursive functions to avoid stack overflow.

def factorial(n: Int, acc: Int = 1): Int = {
  if (n <= 1) acc
  else factorial(n - 1, n * acc)
}
  • Use @tailrec annotation to enforce optimization.


Q37. Explain for-comprehension in Scala.

Answer:
For-comprehension is syntactic sugar for map, flatMap, and filter. Useful for working with collections and monads.

val numbers = List(1,2,3)
val doubled = for (n <- numbers if n % 2 == 1) yield n * 2
println(doubled)  // List(2, 6)

Q38. What is a Stream in Scala?

Answer:
A Stream is a lazy collection where elements are computed on demand.

val nums: Stream[Int] = 1 #:: 2 #:: 3 #:: Stream.empty
println(nums.head)  // 1
println(nums.tail.head) // 2

Q39. What are by-name parameters in Scala?

Answer:
By-name parameters are not evaluated immediately; their evaluation is deferred until used.

def printTwice(x: => Int) = println(x); println(x)
printTwice({ println("Evaluating"); 42 })

Output:

Evaluating
42
Evaluating
42

Q40. What is the difference between == and === in Scala?

Answer:

  • == checks structural equality (like .equals() in Java).

  • eq checks reference equality.

val a = "Scala"
val b = "Scala"
println(a == b)  // true
println(a eq b)  // false (depends on string interning)

9. Functional Programming in Scala (Advanced)

Q41. What are pure functions in Scala?
Answer:
A pure function:

  • Always returns the same output for the same input.

  • Has no side effects (does not modify external state).

def add(a: Int, b: Int): Int = a + b  // pure
var x = 0
def addWithSideEffect(a: Int) = { x += a; x }  // impure

Q42. What is a partially applied function?
Answer:
A function where some arguments are fixed, and the rest can be supplied later.

def add(a: Int, b: Int, c: Int) = a + b + c
val addFive = add(5, _: Int, _: Int)
println(addFive(3, 2))  // 10

Q43. What is a curried function?
Answer:
Currying transforms a function with multiple arguments into a chain of single-argument functions.

def multiply(a: Int)(b: Int) = a * b
val double = multiply(2) _
println(double(5))  // 10

Q44. What is the difference between map and foreach?

Feature map foreach
Returns New collection Unit (no return)
Usage Transform collection Apply side-effect operations
Example List(1,2).map(_*2) → List(2,4) List(1,2).foreach(println)

Q45. What is a monad in Scala?
Answer:
A monad is a design pattern used to wrap values and apply computations sequentially. Common examples: Option, List, Future.

val maybeValue: Option[Int] = Some(10)
val result = maybeValue.map(_ * 2)  // Some(20)

10. Advanced Collections

Q46. What is the difference between Vector and List?

Feature List Vector
Access time O(n) for random access O(log n)
Append/Prepend O(1) prepend, O(n) append O(log n)
Use case Small lists Large, random-access collections

Q47. How do you merge two Maps in Scala?

val map1 = Map(1 -> "A", 2 -> "B")
val map2 = Map(2 -> "C", 3 -> "D")
val merged = map1 ++ map2  // Map(1 -> "A", 2 -> "C", 3 -> "D")
  • The right-hand map overrides duplicates.


Q48. What is the difference between Set and Seq?

Feature Set Seq
Order Unordered Ordered
Duplicates Not allowed Allowed
Access by index No Yes

Q49. What are Streams/LazyLists in Scala 2.13+?
Answer:

  • Stream is deprecated; replaced by LazyList.

  • Evaluates elements on demand, useful for infinite sequences.

val nums: LazyList[Int] = LazyList.from(1)
println(nums.take(5).toList)  // List(1,2,3,4,5)

Q50. What is the difference between foldLeft and foldRight?

Feature foldLeft foldRight
Direction Left to right Right to left
Tail-recursive Yes No
Example List(1,2,3).foldLeft(0)(_+_) → 6 List(1,2,3).foldRight(0)(_+_) → 6

11. Concurrency and Futures

Q51. How to handle exceptions in a Future?

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

val f = Future { 10 / 0 }
f.onComplete {
  case scala.util.Success(value) => println(value)
  case scala.util.Failure(e) => println("Error: " + e.getMessage)
}
  • Use recover or recoverWith for error handling.


Q52. What is Await in Scala?
Answer:
Await blocks until a Future completes, generally used for testing or simple scripts.

import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global

val f = Future { 5 + 5 }
val result = Await.result(f, 2.seconds)
println(result)  // 10

Q53. Difference between Future and Thread?

Feature Future Thread
Management Managed by ExecutionContext Manual creation
Asynchronous Yes Yes
Composition Supports map/flatMap No direct composition
Lightweight Yes Heavier

Q54. How is concurrency handled in Scala without blocking?
Answer:

  • Using Futures for async operations

  • Using Akka Actors for message-passing concurrency

  • Using Streams/LazyList for lazy evaluation


12. Real-world Scala Examples

Q55. How to read a file in Scala?

import scala.io.Source

val source = Source.fromFile("test.txt")
for (line <- source.getLines()) println(line)
source.close()

Q56. How to filter and transform a list in one go?

val nums = List(1,2,3,4,5)
val result = nums.filter(_ % 2 == 0).map(_ * 10)
println(result)  // List(20, 40)

Q57. How to remove duplicates from a list?

val nums = List(1,2,2,3,3,3)
val distinctNums = nums.distinct
println(distinctNums)  // List(1,2,3)

Q58. How to define a recursive function in Scala?

def factorial(n: Int): Int = {
  if (n == 0) 1
  else n * factorial(n - 1)
}
println(factorial(5))  // 120

Q59. How to implement a simple cache using mutable Map?

import scala.collection.mutable

val cache = mutable.Map[String, Int]()
def expensiveComputation(key: String): Int = {
  cache.getOrElseUpdate(key, {
    println(s"Computing for $key")
    key.length * 10
  })
}

println(expensiveComputation("Scala"))  // Computes
println(expensiveComputation("Scala"))  // Uses cache

Q60. What are the common mistakes freshers make in Scala?
Answer:

  • Ignoring immutability and using var too often

  • Not understanding map vs foreach

  • Forgetting to handle Option types → NPE

  • Misusing Future without proper ExecutionContext

  • Using recursion without tail-call optimization

Experienced Interview Questions

 

1. Advanced Scala Basics

Q1. Explain the difference between Any, AnyVal, AnyRef, Nothing, and Null.

Answer:

Type Description
Any Root of all types (value + reference)
AnyVal Base class for all value types (Int, Boolean, Double, etc.)
AnyRef Base class for all reference types (like Object in Java)
Nothing Subtype of all types; represents no value (used in exceptions)
Null Subtype of all reference types; represents null
  • Use case: Nothing is used to signal failures (throw new Exception), Null for optional references, and AnyVal/AnyRef distinguishes primitive vs object types.


Q2. Difference between val, var, and def.

Keyword Description Usage
val Immutable value val x = 10
var Mutable variable var y = 10
def Method or function def add(a: Int, b: Int) = a + b
  • Experience tip: Prefer val over var for thread-safe and functional code.


Q3. What is a companion object and its use cases?

Answer:

  • A companion object shares the same name as a class and can access its private members.

  • Used for factory methods, utilities, constants, and singleton instances.

class Person(val name: String)
object Person {
  def apply(name: String) = new Person(name)
}
val p = Person("Yash")

Q4. Explain Scala constructors in depth.

  • Primary constructor: Defined in the class signature.

  • Auxiliary constructors: Defined using def this() and must call another constructor.

class Person(name: String) {
  var age: Int = _
  def this(name: String, age: Int) = { this(name); this.age = age }
}
  • Experience tip: Use primary constructors for immutability; auxiliary constructors are rarely needed.


2. Advanced Functional Programming

Q5. Difference between map, flatMap, filter, collect.

Function Description
map Transforms each element into another value
flatMap Transforms and flattens nested collections
filter Filters elements based on a predicate
collect Partial function; filters & transforms in one go
val nums = List(1,2,3,4)
nums.map(_*2)           // List(2,4,6,8)
nums.flatMap(x => List(x,x))  // List(1,1,2,2,3,3,4,4)
nums.filter(_%2==0)     // List(2,4)
nums.collect { case x if x%2==0 => x*10 } // List(20,40)

Q6. What are higher-order functions and examples?

  • Functions that take other functions as parameters or return functions.

def applyFunc(f: Int => Int, x: Int) = f(x)
val square = (x: Int) => x*x
applyFunc(square, 5)  // 25
  • Experience tip: Higher-order functions are used in map-reduce operations, Spark transformations, and custom combinators.


Q7. What are pure functions and side effects?

  • Pure function: Returns same output for same input, no side effects.

  • Side effect: Modifies state outside the function or performs I/O.

// Pure
def add(a:Int,b:Int) = a+b
// Impure
var x = 0
def addWithSideEffect(a:Int) = { x+=a; x }

Q8. What is tail recursion and why is it important?

  • Tail recursion: Last operation in function is a recursive call.

  • Optimized by compiler to avoid stack overflow.

@annotation.tailrec
def factorial(n:Int, acc:Int=1):Int = {
  if(n<=1) acc else factorial(n-1, n*acc)
}
  • Experience tip: Crucial for functional and recursive algorithms in production code.


3. Scala Collections (Advanced)

Q9. Difference between List, Vector, and ArrayBuffer.

Feature List Vector ArrayBuffer
Mutability Immutable Immutable Mutable
Access time O(n) O(log n) O(1)
Best use case Small lists Random access Frequent updates

Q10. Difference between Seq, IndexedSeq, Set, Map.

  • Seq: Ordered collection, allows duplicates.

  • IndexedSeq: Random access optimized (Vector).

  • Set: No duplicates, unordered.

  • Map: Key-value pairs, lookup optimized.


Q11. How do you merge Maps and handle conflicts?

val m1 = Map(1 -> "A", 2 -> "B")
val m2 = Map(2 -> "C", 3 -> "D")
val merged = m1 ++ m2 // Map(1->A,2->C,3->D)
  • Right-hand map overrides conflicting keys.


Q12. Difference between foldLeft and foldRight.

Feature foldLeft foldRight
Direction Left → Right Right → Left
Tail recursion Yes No
Example List(1,2,3).foldLeft(0)(+) → 6 List(1,2,3).foldRight(0)(+) → 6
  • Experience tip: Use foldLeft for large collections to avoid stack overflow.


4. Concurrency and Futures

Q13. Explain Futures and Promises.

  • Future: Holds a value computed asynchronously.

  • Promise: Allows manually completing a Future.

import scala.concurrent._
import ExecutionContext.Implicits.global

val f = Future { 10 + 5 }
val p = Promise[Int]()
p.success(42)
  • Experience tip: Avoid blocking (Await) in production; prefer non-blocking composition (map, flatMap).


Q14. Difference between Future and Thread.

Feature Future Thread
Management ExecutionContext Manual
Composition Supported Not supported
Lightweight Yes Heavier

Q15. Explain the actor model and Akka in Scala.

  • Actor: Encapsulated state, communicates via messages.

  • Akka: Toolkit for building concurrent, distributed, fault-tolerant apps.

import akka.actor._

class MyActor extends Actor {
  def receive = { case msg => println(s"Received: $msg") }
}
val system = ActorSystem("MySystem")
val actor = system.actorOf(Props[MyActor])
actor ! "Hello Akka"

5. Implicits and Type Classes

Q16. What are implicit parameters and conversions?

  • Implicit parameters: Passed automatically if in scope.

  • Implicit conversions: Automatically convert type when required.

implicit val defaultName = "Yash"
def greet(implicit name: String) = println(s"Hello, $name")
greet  // Hello, Yash

implicit def intToString(x: Int): String = x.toString
val s: String = 42  // auto-converted

Q17. What is a type class in Scala?

  • Encapsulates behavior for types without modifying them.

  • Example: Ordering[T], Numeric[T].

  • Used heavily in functional libraries like Cats or Scalaz.


6. Pattern Matching and Case Classes

Q18. What are case classes and their benefits?

  • Immutable data structures with automatic toString, equals, hashCode, copy.

  • Ideal for pattern matching.

case class Person(name: String, age: Int)
val p = Person("Yash", 25)
p match {
  case Person("Yash", _) => println("Found Yash")
  case _ => println("Unknown")
}

Q19. What are sealed traits and enums?

  • Sealed trait: All subclasses must be in same file; enables exhaustive pattern matching.

  • Enum (Scala 3): Type-safe representation of finite values.

sealed trait Day
case object Mon extends Day
case object Tue extends Day

Q20. Difference between match and if-else.

  • match is more expressive, supports pattern matching (types, structures).

  • if-else only evaluates boolean expressions.


7. Scala with Spark (Common in 4-year roles)

Q21. Difference between RDD, DataFrame, and Dataset.

Feature RDD DataFrame Dataset
Type Safety Weak Weak Strong
Performance Slower Faster (Catalyst optimization) Faster
API Functional SQL-like Functional + SQL

Q22. How to read CSV in Spark using Scala?

import org.apache.spark.sql.SparkSession
val spark = SparkSession.builder.appName("Example").getOrCreate()
val df = spark.read.option("header", "true").csv("data.csv")
df.show()

Q23. Difference between map and flatMap in Spark RDDs

  • map: Returns one output element per input element.

  • flatMap: Returns 0 or more output elements per input element (flattens result).


Q24. Explain persist vs cache in Spark.

  • cache: Default memory-only storage.

  • persist: Can store in memory, disk, or both (StorageLevel).


Q25. How to handle nulls in Spark DataFrame?

df.na.fill(0)          // Replace null with 0
df.na.drop()            // Remove rows with null
df.na.replace("col", Map("null" -> "default"))

8. Advanced Functional Programming

Q26. What is a Monad in Scala?
Answer:

  • A monad is a design pattern used to wrap values and chain computations.

  • Common examples: Option, List, Future.

  • Provides flatMap and map methods for chaining operations without explicit null checks or loops.

val maybeValue: Option[Int] = Some(10)
val result = maybeValue.map(_ * 2) // Some(20)
  • Experience tip: Monads help manage side effects, optional values, and asynchronous operations cleanly.


Q27. What is the difference between Option, Some, and None?

Term Description
Option Container for optional value (can be Some or None)
Some Represents a value inside Option
None Represents absence of value
val someValue: Option[Int] = Some(42)
val noneValue: Option[Int] = None
  • Helps avoid NullPointerException in functional programming.


Q28. Explain Either and its use cases.
Answer:

  • Either[L, R] represents two possibilities, usually Left for errors and Right for success.

def divide(a: Int, b: Int): Either[String, Int] =
  if(b == 0) Left("Division by zero") else Right(a/b)

val result = divide(10, 2)
result match {
  case Right(value) => println(s"Result: $value")
  case Left(err) => println(s"Error: $err")
}
  • Commonly used in error handling instead of exceptions.


Q29. What is a for-comprehension?
Answer:

  • Syntactic sugar for chaining map, flatMap, filter operations on monads.

val a = Some(10)
val b = Some(5)

val result = for {
  x <- a
  y <- b
} yield x + y

println(result) // Some(15)
  • Experience tip: Used extensively with Option, Future, List, and custom monads.


Q30. What is currying vs partially applied functions?

Concept Description
Currying Transform function with multiple arguments into sequence of single-argument functions
Partially Applied Function Fix some arguments of a function, leaving others open for later
// Currying
def multiply(a: Int)(b: Int) = a * b
val double = multiply(2)_ 
println(double(5))  // 10

// Partially Applied Function
def add(a: Int, b: Int, c: Int) = a + b + c
val add5 = add(5, _:Int, _:Int)
println(add5(3,2))  // 10

9. Concurrency and Futures

Q31. Difference between blocking and non-blocking operations

Feature Blocking Non-blocking
Thread waits Yes No
Resource usage High Low
Example Thread.sleep, Await Future, map/flatMap

Q32. How to handle exceptions in Future?

import scala.concurrent._
import scala.util.{Failure, Success}
import ExecutionContext.Implicits.global

val f = Future { 10 / 0 }

f.onComplete {
  case Success(value) => println(value)
  case Failure(ex) => println(s"Error: ${ex.getMessage}")
}
  • Use recover or recoverWith for functional error handling.


Q33. Explain Promise with an example

import scala.concurrent._
import ExecutionContext.Implicits.global

val p = Promise[Int]()
val f = p.future

f.onComplete {
  case Success(v) => println(s"Completed with $v")
  case Failure(e) => println(s"Failed: ${e.getMessage}")
}

p.success(42)  // Completes the future
  • Experience tip: Promises are useful when combining callback-based APIs with Futures.


Q34. Explain the actor model with Akka

  • Actor encapsulates state and behavior, communicates via immutable messages, avoids shared memory.

  • Akka allows concurrent, distributed, fault-tolerant systems.

import akka.actor._

class MyActor extends Actor {
  def receive = {
    case msg => println(s"Received: $msg")
  }
}

val system = ActorSystem("MySystem")
val actor = system.actorOf(Props[MyActor])
actor ! "Hello Akka"
  • Experience tip: Use actors for high concurrency without locks.


Q35. Difference between Future and Actor

Feature Future Actor
Concurrency Asynchronous computation Concurrent state machine
Communication Callback / composition Message passing
State Stateless Encapsulates state

10. Performance and Best Practices

Q36. Why prefer immutable collections in Scala?

  • Thread-safe by default

  • Avoid side effects in functional pipelines

  • Simplifies reasoning about code

  • Recommended in Spark transformations, Akka messages, and FP design


Q37. Difference between var, val, and lazy val

Keyword Description
var Mutable variable
val Immutable value, evaluated immediately
lazy val Immutable value, evaluated once on first access
lazy val x = { println("Computing"); 42 }
println(x)  // Prints "Computing" only now

Q38. Tail-call optimization and stack overflow

  • Use @tailrec annotation for recursion optimization.

  • Non-tail recursion may cause stack overflow for large inputs.

@annotation.tailrec
def sum(n:Int, acc:Int=0):Int = {
  if(n==0) acc else sum(n-1, acc+n)
}

Q39. Difference between fold, reduce, scan

Function Description
reduce Aggregates values, collection must be non-empty
fold Like reduce but with initial value
scan Like fold but returns all intermediate results
val nums = List(1,2,3)
nums.fold(0)(_+_)   // 6
nums.reduce(_+_)    // 6
nums.scan(0)(_+_)   // List(0,1,3,6)

11. Scala-Spark Integration

Q40. Difference between RDD, DataFrame, and Dataset

Feature RDD DataFrame Dataset
Type Safety Weak Weak Strong
Optimized No Catalyst engine Catalyst engine
API Functional SQL-like Functional + SQL

Q41. How to read/write CSV in Spark using Scala

import org.apache.spark.sql.SparkSession
val spark = SparkSession.builder.appName("Example").getOrCreate()

val df = spark.read.option("header","true").csv("data.csv")
df.show()
df.write.option("header","true").csv("output.csv")

Q42. Difference between map and flatMap in Spark RDDs

  • map: 1 input → 1 output

  • flatMap: 1 input → 0 or more outputs (flattened result)


Q43. How to handle nulls in Spark DataFrame

df.na.fill(0)        // Replace nulls with 0
df.na.drop()          // Drop rows with nulls
df.na.replace("col", Map("null" -> "default"))

Q44. What is Spark persist vs cache

  • cache(): memory-only storage (default)

  • persist(StorageLevel): can store in memory + disk


Q45. Explain broadcast variables and accumulators

  • Broadcast variables: Read-only, shared efficiently across nodes

  • Accumulators: Write-only, used to accumulate values across executors

val acc = sc.longAccumulator("MyAcc")
rdd.foreach(x => acc.add(x))
println(acc.value)

12. Real-world Scala Patterns

Q46. Implement a simple cache in Scala

import scala.collection.mutable

val cache = mutable.Map[String, Int]()
def expensiveComputation(key: String): Int =
  cache.getOrElseUpdate(key, {
    println(s"Computing for $key")
    key.length * 10
  })
  • Avoids recomputation for repeated inputs.


Q47. How to remove duplicates from a list

val nums = List(1,2,2,3,3,3)
val distinctNums = nums.distinct  // List(1,2,3)

Q48. Difference between == and eq

  • == checks structural equality (.equals)

  • eq checks reference equality

val a = "Scala"
val b = "Scala"
println(a == b)  // true
println(a eq b)  // false (depends on interning)

Q49. Best practices for functional programming in production

  • Prefer immutability (val)

  • Avoid side effects in functions

  • Use Option, Either instead of nulls/exceptions

  • Leverage map, flatMap, filter, and for-comprehensions

  • Tail recursion for recursive algorithms


Q50. Common mistakes for experienced developers

  • Overusing var → unsafe in concurrency

  • Blocking Futures with Await in production

  • Ignoring performance differences in collections (List vs Vector)

  • Misusing pattern matching → missing cases

  • Ignoring Spark transformations’ lazy evaluation → repeated computation


13. Advanced Concurrency and Akka

Q51. What are Akka Streams?
Answer:

  • Akka Streams provide a reactive and asynchronous way to process streaming data.

  • Built on Reactive Streams specification, handles back-pressure automatically.

import akka.actor.ActorSystem
import akka.stream.scaladsl._

implicit val system = ActorSystem("StreamSystem")

val source = Source(1 to 5)
val sink = Sink.foreach[Int](println)

source.runWith(sink)
  • Experience tip: Use Akka Streams for high-throughput data pipelines.


Q52. What is back-pressure in Akka Streams?

  • Back-pressure ensures producers do not overwhelm consumers in streaming pipelines.

  • The system automatically slows down producers if consumers are slower.


Q53. What are Actors, Supervisor strategies, and Mailboxes in Akka?

  • Actor: Encapsulates state, processes messages asynchronously.

  • Supervisor Strategy: Defines how a parent handles child failures (restart, resume, stop).

  • Mailbox: Queue of messages for the actor to process.


Q54. Difference between tell (!), ask (?), and pipeTo in Akka Actors

Operation Description
! Fire-and-forget message
? Returns Future for response
pipeTo Pipe Future result to another actor

Q55. How do you make Akka Actor state thread-safe?

  • Actors encapsulate state, only accessible via messages.

  • Avoid var in shared scope.

  • Use immutable messages.


14. Futures, Promises, and Asynchronous Programming

Q56. Difference between map, flatMap, and transform in Future

import scala.concurrent._
import ExecutionContext.Implicits.global

val f = Future(10)
val mapped = f.map(_*2)          // 20
val flatMapped = f.flatMap(x => Future(x*2))  // Future(20)
val transformed = f.transform(x => Success(x*2))  // Future(20)
  • map and flatMap are for success values, transform handles success & failure.


Q57. How do you compose multiple Futures?

val f1 = Future(10)
val f2 = Future(5)

val combined = for {
  a <- f1
  b <- f2
} yield a + b

combined.onComplete(println)  // 15

Q58. Difference between recover, recoverWith, and fallbackTo

Method Description
recover Handle failure and return value
recoverWith Handle failure and return another Future
fallbackTo Use alternative Future if original fails

Q59. Difference between blocking vs non-blocking in Futures

  • Blocking: Await.result(f, timeout)

  • Non-blocking: map, flatMap, onComplete

  • Best practice: Avoid blocking in production code.


15. Cats/Scalaz and Functional Libraries

Q60. What is Cats library in Scala?

  • Cats is a functional programming library providing type classes, monads, functors, and semigroups.

  • Helps write pure, composable functional code.

import cats.implicits._
val sum = List(1,2,3).combineAll
println(sum)  // 6

Q61. Difference between Functor, Applicative, and Monad

Concept Description
Functor Can apply map over a container
Applicative Can apply functions in context to values in context
Monad Can chain computations with flatMap

Q62. What is Validated vs Either in Cats?

  • Either stops at first failure.

  • Validated accumulates multiple errors.

import cats.data.Validated
import cats.implicits._

val v1 = Validated.valid 
val v2 = Validated.invalid[Int, String]("Error")

16. Spark and Big Data with Scala

Q63. How does lazy evaluation work in Spark?

  • Transformations are lazy; actions trigger computation.

  • Prevents unnecessary computation and optimizes DAG.


Q64. Difference between narrow and wide transformations

Transformation Description
Narrow One-to-one mapping (map, filter)
Wide Requires shuffle (groupBy, join)

Q65. What are partitions in Spark and how to optimize them?

  • Data divided into partitions for parallel processing.

  • Optimize with repartition or coalesce to improve performance.


Q66. What is Catalyst Optimizer?

  • Catalyst is Spark’s query optimizer for DataFrames and Datasets.

  • Performs logical, physical plan optimizations automatically.


Q67. How to handle skewed data in Spark?

  • Techniques:

    • Salting keys

    • Repartitioning large keys

    • Using broadcast join for smaller datasets


Q68. Difference between cache and persist

  • cache(): default memory-only

  • persist(StorageLevel): memory+disk or custom storage


17. Scala Best Practices and Patterns

Q69. When to use var vs val

  • Prefer val for immutability

  • Use var only for temporary state in tight loops or mutable buffers


Q70. Common Scala design patterns

  • Singleton (object)

  • Factory pattern (companion object)

  • Builder pattern (immutable objects)

  • Functional combinators (map/flatMap/filter)

  • Option/Either for error handling


Q71. How to write thread-safe immutable data structures

  • Use val for state

  • Return new instance for modifications

  • Avoid mutable shared state

case class Counter(value: Int) {
  def increment = copy(value + 1)
}

Q72. Difference between lazy val and def

Feature lazy val def
Evaluation Once, on first access Every call
Memory Stores result Does not store

Q73. How to debug performance in Scala

  • Use time measurements: System.nanoTime

  • Use profile tools: VisualVM, YourKit

  • Optimize collections (List vs Vector)

  • Avoid unnecessary recursion without tail optimization


Q74. How to handle large datasets efficiently in Scala

  • Use immutable collections with Vector or LazyList

  • Use parallel collections for CPU-bound tasks (.par)

  • Prefer Streams/Iterators for lazy evaluation


Q75. Difference between Stream and LazyList in Scala 2.13+

  • Stream is deprecated

  • LazyList is fully lazy and memory-efficient

  • Supports infinite sequences without stack overflow


Q76. Difference between mutable and immutable maps in Scala

import scala.collection.mutable
val mutableMap = mutable.Map(1->"A")
mutableMap(2) = "B"

val immutableMap = Map(1->"A")
val updated = immutableMap + (2 -> "B")  // returns new Map

Q77. How to implement caching in Scala

import scala.collection.mutable

object Cache {
  private val store = mutable.Map[String, Int]()
  def getOrCompute(key: String, compute: => Int): Int =
    store.getOrElseUpdate(key, compute)
}

Q78. How to write a recursive Fibonacci efficiently

@annotation.tailrec
def fib(n: Int, a: Int = 0, b: Int = 1): Int = {
  if(n==0) a
  else fib(n-1, b, a+b)
}
  • Tail recursion avoids stack overflow.


Q79. Difference between collect and map

Function Description
map Applies a function to all elements
collect Applies partial function; filters & transforms at once

Q80. Difference between varargs and Seq parameters

def sum(nums: Int*) = nums.sum
sum(1,2,3)

def sumSeq(nums: Seq[Int]) = nums.sum
sumSeq(Seq(1,2,3))
  • Varargs allow variable number of arguments

  • Seq requires collection