liveBook · Manning

Generics

As explained in Functional Programming in Scala, Second Edition

A polymorphic method is a method declared with type parameters that can operate over values of multiple types.

Generics, also called polymorphic functions, abstract over types. A monomorphic function is fixed to one data type; a generic function uses one or more type parameters so the same definition can operate on many types. This removes type-specific detail and makes definitions easier to reuse. section 2.4 section 2.7

In Scala, a method declares type parameters in square brackets after its name, conventionally with short uppercase names such as A, B, and C. A type parameter introduces a type variable that can be used throughout the signature. Reusing A in several positions requires those positions to have the same type, with the compiler enforcing that relationship. section 2.4.1 section 2.4.1

Searching without assuming equality

A String-only findFirst can search an Array[String] for a String key, but its structure is nearly identical for Int or any other element type. Generalize it as findFirst[A](as: Array[A], p: A => Boolean): Int. The caller supplies p, a test for A, instead of relying on an equals method that may not be useful. The function returns the first matching index or -1. section 2.4.1

Listing 2.4 Polymorphic function to find an element in an array
def findFirst[A](as: Array[A], p: A => Boolean): Int =    #1
  @annotation.tailrec
  def loop(n: Int): Int =
    if n >= as.length then -1
    else if p(as(n)) then n                               #2
    else loop(n + 1)
 
  loop(0)

Compare the generic search signature with its recursive loop: A determines both the array element type and the predicate input, while the predicate supplies the only needed operation on an element. section 2.4.1

Generic signatures do more than permit reuse: they restrict what an implementation can do. For an unknown A, code can use only operations supplied as arguments or derived from them. This can turn implementation into type-guided reasoning. For partial1[A, B, C], the required B => C result must accept b: B and combine it with the available a: A by calling f(a, b). section 2.5 section 2.7

The same idea extends beyond ordinary methods. A polymorphic List[A] represents lists of different element types with one data-type definition. Polymorphic function types quantify over a type parameter for every type encountered, enabling transformations such as F[x] => G[x] while preserving the particular x. section 3.1 section 13.4.2

Parametricity can also yield guarantees: because a polymorphic map cannot behave differently according to the function types it receives, laws such as mapping identity can support free theorems and map-fusion reasoning. section 7.3.1

How Functional Programming in Scala, Second Edition covers it

How deep it goes
Defines method type parameters, traces findFirst, and derives partial1 from its signature; later extends to polymorphic function types.
Examples
Uses generic array search, partial application, parameterized List construction, Free interpreters, and safe mutable-state actions.
What it assumes
Starts from Scala and functional-programming basics while assuming willingness to read functions, recursion, and higher-order code.
What you can do after
Build it from scratch by declaring type parameters and using signatures to guide generic function implementations.
How it connects
Connects generics to higher-order functions, type-driven development, polymorphic data types, parametricity, and Free monads.

Also explained in

Compare how 20 books explain generics →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Programming in Scala, Second Edition. The section links point to the parts of the book it draws on.