
- 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 - Methods
- Scala - Functions
- Scala - Methods vs 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 - Polymorphic Functions
- 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 - NumericRange
- Scala - Infinite Streams
- Scala - Parallel Collections
- Scala Advanced Types
- Scala - Union Types
- Scala - Intersection Types
- Scala - Type Aliases
- Scala - Structural Types
- Scala - Match Expression
- Scala - Singleton Type Operator
- Scala - Abstract Types
- Scala - Dependent Types
- Scala - Abstract Type Bounds
- Scala - Higher-Kinded Types
- Scala - Opaque Type Alias
- Scala - Path-Dependent Types
- Scala - Type Lambdas
- Scala - Type Inference
- Scala - Algebraic Data Types
- Scala Pattern Matching
- Scala - Pattern Matching
- Scala - Guards
- Scala - Variables in Patterns
- Scala - Type Patterns
- Scala - The Matchable Trait
- Scala - Matching Arrays
- Scala - Matching Lists
- Scala - Matching Tuples
- Scala - Exception Handling
- Scala - Extractors
- Scala - Pattern Bindings
- Scala - Regular Expressions
- Scala - Case Classes
- Scala - Partial Functions
- Scala - Packaging and Imports
- Scala - Implicit Imports
- Scala - Export Clauses
- Scala - Nested Packages
- Scala - Chained Packages
- Scala - Package Objects
- Scala Files I/O
- Scala - Files I/O
- Scala - Writing Files
- Scala - Listing Files
- Scala - Deleting Directories
- Scala - Check File Exists
- 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 - Process Management
- Scala - Scaladoc
- Scala - Literal Type Arithmetic
- Scala - Inline keyword
- Scala - Def, Var & Val
- Scala - Dropped Features
- Scala Unit Testing
- Scala - Unit Testing
- Scala - uTest
- Scala - MUnit
- Scala - ScalaTest Runner
- Scala - ScalaMock
- Scala - JUnit
- Scala - Mocking
- Scala - BDD Testing
Scala - Polymorphic Functions
This chapter takes you through the concept of polymorphic functions in Scala programming. You can write code by operating on different types and structures with type safety. Polymorphic functions are also known as generic functions. It enhances code flexibility and reusability.
Polymorphic Functions
Polymorphic functions use type parameters to work with different types with type safety. It is used in writing generic algorithms and data structures.
Definition
Polymorphic function is a function that operates on type parameters. These type parameters are used in square brackets [] and can be used in the function parameters and return type.
Syntax
The syntax of a polymorphic function in Scala is -
def functionName[T](parameter: T): ReturnType = { // function body }
Example
The following example shows defining and using a polymorphic function in Scala programming -
object Demo { def identity[T](x: T): T = x def main(args: Array[String]): Unit = { println(identity(42)) println(identity("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
42 Scala
In the example, the identity function is defined as polymorphic with a type parameter T. It returns same value it received. So, there is flexibility in polymorphic functions.
Advantages of Polymorphic Functions
There are various advantages of polymorphic functions. These promote code reuse for same function to operate on different types without rewriting the function for each type. Polymorphic functions also maintain type safety. So, operations on type parameters are valid for all types that can be passed to the function. Polymorphic functions have higher levels of abstraction. So it is easier to write generic algorithms and data structures that can work with any type.
Polymorphic Functions with Collections
Polymorphic functions are used with collections to perform operations that are independent of the specific type of elements in the collection.
Syntax
The syntax of using polymorphic functions with collections is -
def functionName[T](collection: List[T]): ReturnType = { // function body }
Example
Consider the example of using a polymorphic function with collections in Scala programming -
object Demo { def reverseList[T](list: List[T]): List[T] = list.reverse def main(args: Array[String]): Unit = { val numbers = List(1, 2, 3, 4, 5) val words = List("Scala", "is", "fun") println(reverseList(numbers)) println(reverseList(words)) } }
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(5, 4, 3, 2, 1) List(fun, is, Scala)
In the example, the reverseList function is defined as polymorphic with a type parameter T. It reverses the elements of a list. So there is reusability of polymorphic functions with different types of lists.
Multiple Type Parameters
Polymorphic functions can also have multiple type parameters. So you can operate these parameters on multiple types simultaneously.
Syntax
The syntax of polymorphic function with multiple type parameters is -
def functionName[T, U](param1: T, param2: U): ReturnType = { // function body }
Example
Consider the example of a polymorphic function with multiple type parameters in Scala programming -
object Demo { def pair[T, U](first: T, second: U): (T, U) = (first, second) def main(args: Array[String]): Unit = { println(pair(42, "Scala")) println(pair(3.14, List(1, 2, 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
(42, Scala) (3.14, List(1, 2, 3))
In the example, the pair function is defined with two type parameters, T and U. It creates a pair (tuple) from two values of potentially different types.
Polymorphic Functions with Constraints
Polymorphic functions can include constraints on type parameters, like, requiring a type to be a subtype of another type.
Syntax
The syntax of polymorphic function with constraints is -
def functionName[T <: SuperType](parameter: T): ReturnType = { // function body }
Example
Consider the example of polymorphic function with type constraints in Scala programming -
import scala.reflect.Selectable.reflectiveSelectable object Demo { def printLength[T <: { def length: Int }](item: T): Unit = { println(item.length) } def main(args: Array[String]): Unit = { printLength("Hello, Scala") printLength(List(1, 2, 3, 4)) } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
12 4
In the example, the printLength function is constrained to operate on types that have a length method. It will have type safety with flexibility.
Higher-Kinded Types in Polymorphic Functions
Scala supports higher-kinded types. So polymorphic functions can abstract over type constructors (types that take types as parameters).
Syntax
The syntax of polymorphic function with higher-kinded types is -
def functionName[F[_], T](container: F[T]): ReturnType = { // function body }
Example
Consider the example of polymorphic function with higher-kinded types in Scala programming -
object Demo { def lengthOfContainer[F[_], T](container: F[T])(implicit ev: F[T] => Iterable[T]): Int = { val iterableContainer = ev(container) iterableContainer.size } def main(args: Array[String]): Unit = { println(lengthOfContainer(List(1, 2, 3))) println(lengthOfContainer(Array(1, 2, 3, 4))) } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
3 4
In the example, the lengthOfContainer function abstracts over type constructors and calculates the size of a container.
Higher-Order Polymorphic Functions
Higher-order polymorphic functions either take other functions as parameters or return functions as results or both.
Syntax
The syntax of the higher order polymorphic function is -
def higherOrderFunction[T, U](input: T, f: T => U): U = { f(input) }
Example
The following example demonstrates a higher-order polymorphic function in Scala programming -
def applyFunction[T, U](value: T, f: T => U): U = { f(value) } object Demo { def main(args: Array[String]): Unit = { val result1 = applyFunction(10, (x: Int) => x * 2) val result2 = applyFunction("Scala", (s: String) => s.toUpperCase) println(result1) println(result2) } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
20 SCALA
In the example, applyFunction is a higher-order polymorphic function. It takes a value of type T and function f that operates on T and returns U. Demo object shows how this function can be used with different types (Int and String) and functions (Int => Int and String => String).
Polymorphic Functions Summary
- Polymorphic functions use type parameters to operate on different types with type safety.
- These promote code reusability, type safety, and abstraction.
- You can work with collections using polymorphic functions. These can have multiple type parameters, like, type constraints, higher-kinded types, etc.