
- 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 - Context Bound
Context Bound is a simple way to express a common pattern of context parameter which is on type parameter. Type parameters are placeholders for types in generic code. These are declared in []. Context parameters enhance type parameters and these are implicit in their role. Context bounds are used for generic code, encode types into runtime objects and for type classes. Context bounds provide implicit info in the signature in functions with generic types. You can express constraints on type parameters which is easier to write generic code using context bound.
Context Bound
Context bounds introduced in Scala 2.8.0 and used for type class pattern. This pattern mimics Haskell type classes but is more verbose in Scala. Context bound needs a parameterized type, like Ordered[A] but not just String. Context bound describes implicit values. It declares that for type A, there is implicit value of type B[A].
In Scala, [: ord] on [T] in a method indicates [using Ord[T]]. It reduces redundancy. In many situations, context parameter names are not needed and the compiler uses them for synthesized arguments. This style is known as Ad-Hoc Polymorphism. Using context bound, you can clean the code and reduce verbosity.
Syntax
// regular function signature def process[T](implicit ev: Ordering[T]) {} // function signature using context bound def process[T: Ordering] {}
In this above code, we have defined the Ordering context bound on T type parameter. There must be an implicit value of Ordering[T] in the scope for T type. The Ordering provides details for tasks on type 'T' variables inside the function. The function Process is used with T type and with no arguments.
Above "Ordering" deprecated since 2.10, it was replaced with Ordered or Numeric in generics.
def maximum[T: Ord](xs: List[T]): T = xs.reduceLeft(max)
We took this example from Scala official documentation for context bound. This takes a list of T types and returns T type values. [:Ord] has bound on T. It encapsulates runtime info needed to handle values of type 'T'.
Example 1
Consider the following example demonstrating the use of Scala content bound –
import scala.math.Ordering object AnotherCompareExample { def findMax[T: Ordering](var1: T, var2: T): T = { if (implicitly[Ordering[T]].compare(var1, var2) > 0) var1 else var2 } def main(args: Array[String]): Unit = { println(findMax(3, 7)) println(findMax("apple", "orange")) println(findMax(3.14, 2.718)) } }
Output of this code will be,
7 orange 3.14
The function findMax works with any type ‘T’ having Ordering[T]. It takes two variables and var1 is returned if its value is greater than var2. The implicit ival is obtained using implicitly[Ordering[T]]. If ival.compare(var1, var2) > 0, it returns var1; otherwise, it returns var2.
Example 2
Here is another example of Scala content bound –
trait Animal { def species: String def sound: String } case class Dog(species: String) extends Animal { val sound = "Bark" } case class Cat(species: String) extends Animal { val sound = "Meow" } object AnimalSoundExample { def makeSound[T <: Animal](animal: T) = { s"The ${animal.species} makes a ${animal.sound} sound." } def main(args: Array[String]): Unit = { println(makeSound(Dog("Labrador"))) println(makeSound(Cat("Siamese"))) } }
Output of this code will be,
The Labrador makes a Bark sound. The Siamese makes a Meow sound.
The example is self-explanatory. A trait 'Animal' has species and sound. Dog and Cat classes extend it. The makeSound function has a context bound [: Animal] on T, taking one argument. This bound ensures 'animal' is an 'Animal' trait instance. It helps get implicit 'Animal[animal]' to access species and sound of the trait.
Multiple Context Bounds
A context bound asserts an implicit value's existence. For example, the method:
def complex[A : Fractional]
Requires Fractional[A] in scope. It is like:
def complex[A](implicit ev: Fractional[A])
Multiple bounds mean multiple assertions:
def complex[A : Fractional : Trig]
Requires Fractional[A] and Trig[A]. It is equivalent to:
def complex[A](implicit ev0: Fractional[A], ev1: Trig[A])
In the REPL:
trait Foo[A] trait Bar[A] def foo[A : Foo : Bar] = ??? // Equivalent to: [A](implicit ev1: Foo[A], ev2: Bar[A])Nothing
What are Context Bounds used for?
Context bounds are key in the typeclass pattern and referencing Haskell type classes. This pattern implements an alternative to inheritance and provides functionality through implicit adapter patterns.
In Scala 2.8, Ordering replaced Ordered in the library. For example,
def findMin[A: Ordering](x: A, y: A) = if (implicitly[Ordering[A]].lt(x, y)) x else y
But, it is usually written like this:
def findMin[A](x: A, y: A)(implicit ord: Ordering[A]) = { import ord.mkOrderingOps if (x < y) x else y }
It takes advantage of implicit conversions in Ordering for traditional operator style. Another example is Numeric in Scala 2.8.
def add[A: Numeric](a: A, b: A) = implicitly[Numeric[A]].plus(a, b)
Another example is the collection's CanBuildFrom. There's also ClassManifest for initializing arrays.
Use context bounds with typeclass patterns in your classes for separation of concerns. Avoid view bounds with good design in your own code. It is often used to work around someone else's design.