
- 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 - Generic Functions
We will explain the concept of generic functions in Scala programming in this chapter. You can write flexible and reusable code using generic functions. You can define functions that can operate on various data types with compile-time type safety.
Generic Functions
Generic functions are functions that take type parameters. So, it can operate on objects of different types. These type parameters act as placeholders for the actual data types that will be used when the function is called. So, there can be more flexible and reusable code.
A generic function is defined with one or more type parameters. These type parameters are specified within square brackets after the function name. These type parameters can be used to define the return type and the types of parameters used.
Syntax
The syntax of the generic function is -
def functionName[T](param: T): ReturnType = { // function body using type T }
Example
The following example shows a generic function in Scala programming -
object Demo { def printValue[T](value: T): Unit = { println(s"Value: $value") } def main(args: Array[String]): Unit = { printValue(42) // Output: Value: 42 printValue("Hello, Scala!") // Output: Value: Hello, Scala! printValue(3.14) // Output: Value: 3.14 } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
Value: 42 Value: Hello, Scala! Value: 3.14
In the example, the printValue function is defined as a generic function with a type parameter T. The function takes a value of type T and prints it. Demo object calls the printValue function with different types (Int, String, and Double).
Generic Methods within Classes
Generic methods can also be defined within classes. Generic methods can use class type parameters and define their own type parameters.
Syntax
The syntax of generic method inside a class -
class ClassName[T] { def methodName[U](param: U): ReturnType = { // method body using type U } }
Example
The following example shows a generic method within a generic class in Scala programming -
class Container[T](value: T) { def getValue: T = value def printValue[U](param: U): Unit = { println(param) } } object Demo { def main(args: Array[String]): Unit = { val container = new Container[String]("Scala!") container.printValue("Scala!") // 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
Scala!
In the example, Container class is defined as a generic class with a type parameter T. The printValue method within the Container class is defined as a generic method with a type parameter U. Demo object calls the generic method with a String type.
Using Multiple Type Parameters
You can define generic functions with multiple type parameters by specifying multiple type parameters within square brackets.
Syntax
The syntax of the generic function using multiple type parameter is -
def functionName[T, U](param1: T, param2: U): ReturnType = { // function body using types T and U }
Example
The following example shows a generic function with multiple type parameters in Scala -
def pairToString[T, U](first: T, second: U): String = { s"($first, $second)" } object Demo { def main(args: Array[String]): Unit = { println(pairToString(42, "Scala")) // (42, Scala) println(pairToString(3.14, true)) // (3.14, true) } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
(42, Scala) (3.14, true)
In the example, the pairToString function is defined as a generic function with two type parameters: T and U. Demo object calls generic function with different types (Int and String, Double and Boolean).
Bounded Type Parameters
Bounds can be used in generic functions to restrict the types. These can be used as arguments for a type parameter. This restricts the types that can be used as type arguments.
Syntax
The syntax of the generic function with bounded type parameter is -
def functionName[T <: UpperBound](param: T): ReturnType = { // function body using type T } def functionName[T >: LowerBound](param: T): ReturnType = { // function body using type T }
Example
The following example shows the use of bounds in generic functions in Scala programming -
class Animal { def sound(): Unit = { println("Animal sound") } } class Dog extends Animal { override def sound(): Unit = { println("Bark") } } def makeSound[T <: Animal](animal: T): Unit = { animal.sound() } object Demo { def main(args: Array[String]): Unit = { val dog = new Dog makeSound(dog) // Bark } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
Bark
In the example, the makeSound function uses an upper bound T <: Animal. So it restricts the type parameter to be Animal and its subclasses. Demo object calls the generic function with a Dog type.
Context Bounds in Generic Functions
Context bounds are a shorthand way to express a context parameter that depends on a type parameter. For example, a bound like :Ord on a type parameter A of a method and class indicates a context parameter with type Ord(A). Context bounds can be used to reduce code redundancy when passing implicit arguments.
Syntax
The syntax of the context bound in generic function is -
def functionName[T : TypeClass](param: T): ReturnType = { // function body using type T }
Example
The following example shows the use of context bounds in generic functions in Scala programming -
def compare[T : Ordering](a: T, b: T): Int = { val ord = implicitly[Ordering[T]] ord.compare(a, b) } object Demo { def main(args: Array[String]): Unit = { println(compare(3, 5)) // -1 println(compare("apple", "banana")) // -1 println(compare(5, 3)) // -1 println(compare("apple", "apple")) // -1 } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
-1 -1 1 0
In the example, the compare function uses a context bound T : Ordering. It indicates that there must be an implicit Ordering[T] in scope. Demo object calls the generic function with Int and String types.
Generic Functions Summary
- You can define methods with type parameters. So, it provides flexibility and type safety.
- Generic methods can be defined within classes. These can use class type parameters. These can also define their own type parameters.
- You can define multiple type parameters and use bounded type parameters to restrict the types that can be used as type arguments.
- Context bounds express that a type parameter must have an implicit value of a given type in scope.