Skip to content

new classes tour #698

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
Apr 4, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 75 additions & 18 deletions tutorials/tour/_posts/2017-02-13-classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,46 +9,103 @@ categories: tour
num: 4
next-page: traits
previous-page: unified-types
topics: classes
prerequisite-knowledge: no-return-keyword, type-declaration-syntax, string-interpolation, procedures
---

Classes in Scala are static templates that can be instantiated into many objects at runtime.
Here is a class definition which defines a class `Point`:
Classes in Scala are blueprints for creating objects. They can contain methods,
values, variables, types, objects, traits, and classes which are collectively called _members_. Types, objects, and traits will be covered later in the tour.

## Defining a class
A minimal class definition is simply the keyword `class` and
an identifier. Class names should be capitalized.
```tut
class User

val user1 = new User
```
The keyword `new` is used to create an instance of the class. `User` has a default constructor which takes no arguments because no constructor was defined. However, you'll often want a constructor and class body. Here is an example class definition for a point:

```tut
class Point(var x: Int, var y: Int) {

def move(dx: Int, dy: Int): Unit = {
x = x + dx
y = y + dy
}

override def toString: String =
"(" + x + ", " + y + ")"
s"($x, $y)"
}

val point1 = new Point(2, 3)
point1.x // 2
println(point1) // prints (x, y)
```

Classes in Scala are parameterized with constructor arguments. The code above defines two constructor arguments, `x` and `y`; they are both visible in the whole body of the class.
This `Point` class has four members: the variables `x` and `y` and the methods `move` and
`toString`. Unlike many other languages, the primary constructor is in the class signature `(var x: Int, var y: Int)`. The `move` method takes two integer arguments and returns the Unit value `()`, which carries no information. This corresponds roughly with `void` in Java-like languages. `toString`, on the other hand, does not take any arguments but returns a `String` value. Since `toString` overrides `toString` from [`AnyRef`](unified-types.html), it is tagged with the `override` keyword.

## Constructors

Constructors can have optional parameters by providing a default value like so:

The class also includes two methods, `move` and `toString`. `move` takes two integer arguments but does not return a value (the return type `Unit` corresponds to `void` in Java-like languages). `toString`, on the other hand, does not take any parameters but returns a `String` value. Since `toString` overrides the pre-defined `toString` method, it is tagged with the `override` keyword.
```tut
class Point(var x: Int = 0, var y: Int = 0)

Note that in Scala, it isn't necessary to say `return` in order to return a value. The value returned from a method is simply the last value in the method body. In the case of the `toString` method above, the expression after the equals sign is evaluated and returned to the caller.
val origin = new Point // x and y are both set to 0
val point1 = new Point(1)
println(point1.x) // prints 1

Classes are instantiated with the `new` primitive, as follows:
```

In this version of the `Point` class, `x` and `y` have the default value `0` so no arguments are required. However, because the constructor reads arguments left to right, if you just wanted to pass in a `y` value, you would need to name the parameter.
```
class Point(var x: Int = 0, var y: Int = 0)
val point2 = new Point(y=2)
println(point2.y) // prints 2
```

This is also a good practice to enhance clarity.

## Private Members and Getter/Setter Syntax
Members are public by default. Use the `private` access modifier
to hide them from outside of the class.
```tut
object Classes {
def main(args: Array[String]) {
val pt = new Point(1, 2)
println(pt)
pt.move(10, 10)
println(pt)
class Point {
private var _x = 0
private var _y = 0
private val bound = 100

def x = _x
def x_= (newValue: Int): Unit = {
if (newValue < bound) _x = newValue else printWarning
}

def y = _y
def y_= (newValue: Int): Unit = {
if (newValue < bound) _y = newValue else printWarning
}

private def printWarning = println("WARNING: Out of bounds")
}
```

The program defines an executable application Classes in form of a top-level [singleton object](singleton-objects) with a `main` method. The `main` method creates a new `Point` and stores it in value `pt`. Note that values defined with the `val` construct are different from variables defined with the `var` construct (see class `Point` above) in that they do not allow updates; i.e. the value is constant.
val point1 = new Point
point1.x = 99
point1.y = 101 // prints the warning
```
In this version of the `Point` class, the data is stored in private variables `_x` and `_y`. There are methods `def x` and `def y` for accessing the private data. `def x_=` and `def y_=` are for validating and setting the value of `_x` and `_y`. Notice the special syntax for the setters: the method has `_=` appended to the identifier of the getter and the parameters come after.

Here is the output of the program:
Primary constructor parameters with `val` and `var` are public. However, because `val`s are immutable, you can't write the following.
```
class Point(val x: Int, val y: Int)
val point = new Point(1, 2)
point.x = 3 // <-- does not compile
```

Parameters without `val` or `var` are private values, visible only within the class.
```
(1, 2)
(11, 12)
class Point(x: Int, y: Int)
val point = new Point(1, 2)
point.x // <-- does not compile
```