Top Interview Questions
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.
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.
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
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.
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.
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.
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")
}
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 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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. 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.
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.
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()
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
}
}
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")
}
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
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 |
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
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"
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)
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)
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 |
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
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
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.
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.
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.
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"
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.
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.
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"))
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
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 |
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)
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)
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
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.
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.
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")
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
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