Skip to content

rewrote generic classes tour #705

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 10, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
rewrote generic classes tour
  • Loading branch information
travissarles committed May 10, 2017
commit 305e2e0ecac1a75ba5958715ec65660c577ff0bd
59 changes: 34 additions & 25 deletions tutorials/tour/_posts/2017-02-13-generic-classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,49 @@ categories: tour
num: 18
next-page: variances
previous-page: sequence-comprehensions
assumed-knowledge: classes unified-types
---
Generic classes are classes which take a type as a parameter. They are particularly useful for collection classes.

Like in Java 5 (aka. [JDK 1.5](http://java.sun.com/j2se/1.5/)), Scala has built-in support for classes parameterized with types. Such generic classes are particularly useful for the development of collection classes.
Here is an example which demonstrates this:

## Defining a generic class
Generic classes take a type as a parameter within square brackets `[]`. One convention is to use the letter `A` as type parameter identifier, though any parameter name may be used.
```tut
class Stack[T] {
var elems: List[T] = Nil
def push(x: T) { elems = x :: elems }
def top: T = elems.head
def pop() { elems = elems.tail }
class Stack[A] {
private var elements: List[A] = Nil
def push(x: A) { elements = x :: elements }
def peek: A = elements.head
def pop(): A = {
val currentTop = peek
elements = elements.tail
currentTop
}
}
```
This implementation of a `Stack` class takes any type `A` as a parameter. This means the underlying list, `var elements: List[A] = Nil`, can only store elements of type `A`. The procedure `def push` only accepts objects of type `A` (note: `elements = x :: elements` reassigns `elements` to a new list created by prepending `x` to the current `elements`).

Class `Stack` models imperative (mutable) stacks of an arbitrary element type `T`. The type parameters enforces that only legal elements (that are of type `T`) are pushed onto the stack. Similarly, with type parameters we can express that method `top` will only yield elements of the given type.

Here are some usage examples:
## Usage

```tut
object GenericsTest extends App {
val stack = new Stack[Int]
stack.push(1)
stack.push('a')
println(stack.top)
stack.pop()
println(stack.top)
}
To use a generic class, put the type in the square brackets in place of `A`.
```
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop) // prints 2
println(stack.pop) // prints 1
```
The instance `stack` can only take Ints. However, if the type argument had subtypes, those could be passed in:
```
class Fruit
class Apple extends Fruit
class Banana extends Fruit

The output of this program will be:
val stack = new Stack[Fruit]
val apple = new Apple
val banana = new Banana

stack.push(apple)
stack.push(banana)
```
97
1
```
Class `Apple` and `Banana` both extend `Fruit` so we can push instances `apple` and `banana` onto the stack of `Fruit`.

_Note: subtyping of generic types is *invariant*. This means that if we have a stack of characters of type `Stack[Char]` then it cannot be used as an integer stack of type `Stack[Int]`. This would be unsound because it would enable us to enter true integers into the character stack. To conclude, `Stack[T]` is only a subtype of `Stack[S]` if and only if `S = T`. Since this can be quite restrictive, Scala offers a [type parameter annotation mechanism](variances.html) to control the subtyping behavior of generic types._
_Note: subtyping of generic types is *invariant*. This means that if we have a stack of characters of type `Stack[Char]` then it cannot be used as an integer stack of type `Stack[Int]`. This would be unsound because it would enable us to enter true integers into the character stack. To conclude, `Stack[A]` is only a subtype of `Stack[B]` if and only if `B = A`. Since this can be quite restrictive, Scala offers a [type parameter annotation mechanism](variances.html) to control the subtyping behavior of generic types._