
- Scala - Home
- Scala - Overview
- Scala - Features
- Scala - Environment Setup
- Scala - Build Tool (SBT)
- Scala - REPL
- Scala - Dot & Dotty
- Scala - Basic Syntax
- Scala - Hello World Program
- Scala - Identifiers
- Scala - Keywords
- Scala - Comments
- Scala - Code Blocks
- Scala - Semicolon
- Scala - Constructs
- Scala - Expressions
- Scala - Input and Output
- Scala - Optional Braces
- Scala - Underscore (_)
- Data Types and Variables
- Scala - Data Types
- Scala - Type Bounds
- Scala - Context Bound
- Scala - Variances
- Scala - Type Hierarchy
- Scala - Variables
- Scala - Variable Scopes
- Scala - Literals
- Scala - Numeric Types
- Scala - Boolean Types
- Scala - Char Type
- Scala - Unit Types
- Scala - Strings
- Scala - Arrays
- Scala - Null Type
- Scala - Nothing
- Scala - Any Type
- Scala - AnyRef Type
- Scala - Unified Types
- Scala - Dates and Times
- Scala - Ranges
- Scala - Multidimensional Arrays
- Scala - WrappedArray
- Scala - StringBuilder
- Scala - String Interpolation
- Scala - StringContext
- Scala - Type Casting
- Scala var vs val
- Scala Operators
- Scala - Operators
- Scala - Rules for Operators
- Scala - Arithmetic Operators
- Scala - Relational Operators
- Scala - Logical Operators
- Scala - Bitwise Operators
- Scala - Assignment Operators
- Scala - Operators Precedence
- Scala - Symbolic Operators
- Scala - Range Operator
- Scala - String Concatenation Operator
- Scala Conditional Statements
- Scala - IF ELSE
- Scala - IF-ELSE-IF-ELSE Statement
- Scala - Nested IF-ELSE Statement
- Scala Loop Statements
- Scala - Loop Statements
- Scala - while Loop
- Scala - do-while Loop
- Scala - Nested Loops
- Scala - for Loop
- Scala - break Statement
- Scala - yield Keyword
- Scala Classes & Objects
- Scala - Classes & Objects
- Scala - Constructors
- Scala - Auxiliary Constructor
- Scala - Primary Constructor
- Scala - This Keyword
- Scala - Nested Classes
- Scala - Getters and Setters
- Scala - Object Private Fields
- Scala - Singleton Object
- Scala - Companion Objects
- Scala - Creating Executable Programs
- Scala - Stateful Object
- Scala - Enumerations
- Scala - Polymorphism
- Scala - Access Modifiers
- Scala - Apply Method
- Scala - Update Methods
- Scala - UnapplySeq Method
- Scala - Inheritance
- Scala - Extending a Class
- Scala - Method Overloading
- Scala - Method Overriding
- Scala - Generic Classes
- Scala - Generic Functions
- Scala - Superclass Construction
- Scala Methods & Functions
- Scala - Functions
- Scala - Main Methods
- Scala - Functions Call-by-Name
- Scala - Functions with Named Arguments
- Scala - Function with Variable Arguments
- Scala - Recursion Functions
- Scala - Default Parameter Values
- Scala - Functions without Parameters
- Scala - Implicit Parameters
- Scala - Higher-Order Functions
- Scala - Nested Functions
- Scala - Extension Methods
- Scala - Anonymous Functions
- Partially Applied Functions
- Scala - Lazy Val
- Scala - Pure Function
- Scala - Currying Functions
- Scala - Control Abstractions
- Scala - Corecursion
- Scala - Unfold
- Scala - Tail Recursion
- Scala - Infinite Sequences
- Scala - Dynamic Invocation
- Scala - Lambda Expressions
- Scala Collections
- Scala - Collections
- Mutable and Immutable Collections
- Scala - Lists
- Scala - Sets
- Scala - Maps
- Scala - TreeMap
- Scala - SortedMap
- Scala - Tuples
- Scala - Iterators
- Scala - Options
- Scala - Infinite Streams
- Scala - Parallel Collections
- Scala - Algebraic Data Types
- Scala Pattern Matching
- Scala - Pattern Matching
- Scala - Type Patterns
- Scala - Exception Handling
- Scala - Extractors
- Scala - Regular Expressions
- Scala Files I/O
- Scala - Files I/O
- Scala Advanced Concepts
- Scala - Closures
- Scala - Futures
- Scala - Promises
- Scala - Traits
- Scala - Trait Mixins
- Scala - Layered Traits
- Scala - Trait Linearization
- Scala - Sealed Traits
- Scala - Transparent Traits
- Scala - Literal Type Arithmetic
- Scala - Inline keyword
- Scala - Def, Var & Val
- Scala - Dropped Features
- Scala - BDD Testing
Scala - Control Abstractions
This chapter takes you through the concept of control abstractions in Scala programming. You can define custom control structures that encapsulate patterns of control flow. It enhances code readability and reusability.
Control Abstractions
Control abstractions are used to create custom control structures that abstract avoid repetitive control flow patterns. So, your code will be more concise and expressive. These abstractions use object-oriented principles to encapsulate and control logic effectively.
Control abstractions are high-level constructs that abstract control flow patterns into reusable and expressive custom control structures with object-oriented design principles.
Syntax
The syntax of control abstraction in Scala is -
def controlAbstraction(params: Type)(body: => ReturnType): ReturnType = { // control flow logic body }
Example of Control Abstractions
The following example shows defining and using a simple control abstraction in Scala programming −
object Demo { def repeat(n: Int)(body: => Unit): Unit = { for (_ <- 1 to n) body } def main(args: Array[String]): Unit = { repeat(3) { println("Hello, Scala!") } } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
Hello, Scala! Hello, Scala! Hello, Scala!
In the example, the repeat function is a control abstraction that repeats a block of code given number of times.
Types of Control Abstractions
There are different types of control abstraction in Scala which are as follows −
1. Looping Abstractions
You can abstract repetitive code patterns using looping abstractions, so loops will be more expressive.
Syntax
The syntax of looping abstractions is -
def loop(n: Int)(body: => Unit): Unit = { for (_ <- 1 to n) body }
Example
object Demo { def loop(n: Int)(body: => Unit): Unit = { for (_ <- 1 to n) body } def main(args: Array[String]): Unit = { loop(5) { println("Looping") } } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
Looping Looping Looping Looping Looping
2. Conditional Abstractions
You can manage conditional logic using conditional abstractions in a more concise manner.
Syntax
The syntax of conditional abstractions is -
def unless(condition: Boolean)(body: => Unit): Unit = { if (!condition) body }
Example
object Demo { def unless(condition: Boolean)(body: => Unit): Unit = { if (!condition) body } def main(args: Array[String]): Unit = { unless(2 > 3) { println("2 is not greater than 3") } } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
2 is not greater than 3
3. Resource Management Abstractions
You can also manage resources using abstractions properly managed, like, closing files, database connections, etc.
Syntax
The syntax of resource management abstractions is -
def using[A <: { def close(): Unit }, B](resource: A)(body: A => B): B = { try { body(resource) } finally { resource.close() } }
Example
import java.io._ import scala.language.reflectiveCalls object Demo { def using[A <: { def close(): Unit }, B](resource: A)(body: A => B): B = { try { body(resource) } finally { resource.close() } } def main(args: Array[String]): Unit = { using(new PrintWriter("output.txt")) { writer => writer.write("Hello, Scala!") } } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
Check the output.txt file for the written content -
Hello, Scala!
4. Retry Abstractions
You can use retry abstractions to encapsulate retry logic. You can perform operations multiple times.
Syntax
The syntax of retry abstractions is -
def retry[T](n: Int)(block: => T): T = { var lastException: Option[Throwable] = None for (_ <- 1 to n) { try { return block } catch { case e: Throwable => lastException = Some(e) } } throw lastException.getOrElse(new RuntimeException("Unknown error")) }
Example
object Demo { def retry[T](n: Int)(block: => T): T = { var lastException: Option[Throwable] = None for (_ <- 1 to n) { try { return block } catch { case e: Throwable => lastException = Some(e) } } throw lastException.getOrElse(new RuntimeException("Unknown error")) } def main(args: Array[String]): Unit = { var attempts = 0 val result = retry(3) { attempts += 1 if (attempts < 3) throw new RuntimeException("Failed attempt") "Success" } println(result) } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
Success
5. Custom Control Abstractions
You can define custom control abstractions for your specific use cases. Spo enhances code modularity and readability.
Syntax
The syntax of custom control abstractions is as -
def customControl[A, B](params: Type)(body: => A): B = { // custom control flow logic body }
Example
Consider a custom control abstraction for timing the execution of a block of code -
object Demo { def time[A](body: => A): A = { val start = System.nanoTime() val result = body val end = System.nanoTime() println(s"Execution time: ${(end - start) / 1e6} ms") result } def main(args: Array[String]): Unit = { time { Thread.sleep(500) println("Slept for 500 ms") } } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
Slept for 500 ms Execution time: 500.x ms
Control Abstractions for Collections
You can use control abstractions to simplify operations on collections, like, mapping, filtering, folding, etc.
Syntax
The syntax of control abstractions for collections is -
def map[A, B](collection: Seq[A])(f: A => B): Seq[B] = { collection.map(f) } def filter[A](collection: Seq[A])(predicate: A => Boolean): Seq[A] = { collection.filter(predicate) }
Example
object Demo { def map[A, B](collection: Seq[A])(f: A => B): Seq[B] = { collection.map(f) } def filter[A](collection: Seq[A])(predicate: A => Boolean): Seq[A] = { collection.filter(predicate) } def main(args: Array[String]): Unit = { val nums = Seq(1, 2, 3, 4, 5) val doubled = map(nums)(_ * 2) val evens = filter(nums)(_ % 2 == 0) println(doubled) println(evens) } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
List(2, 4, 6, 8, 10) List(2, 4)
Control Abstractions Summary
- Control abstractions in Scala encapsulate control flow patterns in higher-order functions.
- Control abstractions simplify complex control flows, enhance code readability, and promote reuse.
- You can manage looping abstractions for repetitive code patterns.
- You can simply conditional logic using conditional abstractions.
- You can manage resources using abstractions.
- Retry abstractions encapsulate retry logic.
- Custom control abstractions can be defined for your specific use cases.
- You can simplify operations on collections using control abstractions for collections.