Generics in Scala

// Starting with version 2.10, Scala has added support for
// *generics*, also known as *type parameters*.

import scala.reflect.ClassTag

// As an example of a generic function, `slicesIndex` takes
// a sequence of any type and an element of that type and
// returns the index of the first occurrence of v in s,
// or -1 if not present. The `ClassTag` context bound
// allows us to create arrays of type T.
def slicesIndex[T: ClassTag](s: Seq[T], v: T): Int = {
  s.indexOf(v)
}

// As an example of a generic type, `List` is a
// singly-linked list with values of any type.
class List[T] {
  private class Node(var value: T, var next: Node)
  private var head: Node = _
  private var tail: Node = _

  // We can define methods on generic types just like we
  // do on regular types, but we keep the type
  // parameter in place. The type is `List[T]`, not `List`.
  def push(v: T): Unit = {
    if (tail == null) {
      head = new Node(v, null)
      tail = head
    } else {
      tail.next = new Node(v, null)
      tail = tail.next
    }
  }

  // AllElements returns all the List elements as a sequence.
  def allElements: Seq[T] = {
    var elems = Seq.empty[T]
    var current = head
    while (current != null) {
      elems = elems :+ current.value
      current = current.next
    }
    elems
  }
}

object GenericsExample {
  def main(args: Array[String]): Unit = {
    val s = Seq("foo", "bar", "zoo")

    // When invoking generic functions, we can often rely
    // on *type inference*. Note that we don't have to
    // specify the type for `T` when calling `slicesIndex` - 
    // the compiler infers it automatically.
    println(s"index of zoo: ${slicesIndex(s, "zoo")}")

    // … though we could also specify it explicitly.
    val _ = slicesIndex[String](s, "zoo")

    val lst = new List[Int]
    lst.push(10)
    lst.push(13)
    lst.push(23)
    println(s"list: ${lst.allElements}")
  }
}

To run this Scala program:

$ scala GenericsExample.scala
index of zoo: 2
list: List(10, 13, 23)

This Scala code demonstrates the use of generics, which are similar to type parameters in other languages. The slicesIndex function is a generic function that works with sequences of any type, while the List class is a generic type that can hold elements of any type.

In Scala, we use square brackets [] to denote type parameters. The ClassTag context bound in slicesIndex is used to allow creation of arrays of type T, which is necessary for certain operations.

Scala’s type inference is quite powerful, allowing us to often omit explicit type parameters when calling generic functions or constructing generic types. However, we can still specify them explicitly if needed.

The List class demonstrates how to create a generic data structure, with methods that operate on the generic type. The allElements method returns all elements as a Seq, which is Scala’s equivalent of a slice or list in other languages.

This example showcases Scala’s support for generics, allowing for the creation of flexible and reusable code that can work with multiple types.