Skip to content

Commit f98de8a

Browse files
authored
Merge pull request #2474 from sjrd/tabbed-code-tour-classes
Enable tabbed Scala 2/3 code in tour/classes.
2 parents 1b48a48 + 0d2932e commit f98de8a

File tree

1 file changed

+164
-13
lines changed

1 file changed

+164
-13
lines changed

_tour/classes.md

Lines changed: 164 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,37 @@ values, variables, types, objects, traits, and classes which are collectively ca
1818
## Defining a class
1919
A minimal class definition is simply the keyword `class` and
2020
an identifier. Class names should be capitalized.
21+
22+
{% tabs class-minimal-user class=tabs-scala-version %}
23+
24+
{% tab 'Scala 2' for=class-minimal-user %}
2125
```scala mdoc
2226
class User
2327

2428
val user1 = new User
2529
```
26-
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:
2730

31+
The keyword `new` is used to create an instance of the class.
32+
{% endtab %}
33+
34+
{% tab 'Scala 3' for=class-minimal-user %}
35+
```scala
36+
class User
37+
38+
val user1 = User()
39+
```
40+
41+
We call the class like a function, as `User()`, to create an instance of the class.
42+
It is also possible to explicitly use the `new` keyword, as `new User()`, although that is usually left out.
43+
{% endtab %}
44+
45+
{% endtabs %}
46+
47+
`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:
48+
49+
{% tabs class-point-example class=tabs-scala-version %}
50+
51+
{% tab 'Scala 2' for=class-point-example %}
2852
```scala mdoc
2953
class Point(var x: Int, var y: Int) {
3054

@@ -38,76 +62,203 @@ class Point(var x: Int, var y: Int) {
3862
}
3963

4064
val point1 = new Point(2, 3)
41-
println(point1.x) // 2
42-
println(point1) // prints (2, 3)
65+
println(point1.x) // prints 2
66+
println(point1) // prints (2, 3)
67+
```
68+
{% endtab %}
69+
70+
{% tab 'Scala 3' for=class-point-example %}
71+
```scala
72+
class Point(var x: Int, var y: Int):
73+
74+
def move(dx: Int, dy: Int): Unit =
75+
x = x + dx
76+
y = y + dy
77+
78+
override def toString: String =
79+
s"($x, $y)"
80+
end Point
81+
82+
val point1 = Point(2, 3)
83+
println(point1.x) // prints 2
84+
println(point1) // prints (2, 3)
4385
```
86+
{% endtab %}
87+
88+
{% endtabs %}
4489

4590
This `Point` class has four members: the variables `x` and `y` and the methods `move` and
46-
`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.
91+
`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 to `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.
4792

4893
## Constructors
4994

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

97+
{% tabs class-point-with-default-values class=tabs-scala-version %}
98+
99+
{% tab 'Scala 2' for=class-point-with-default-values %}
52100
```scala mdoc:nest
53101
class Point(var x: Int = 0, var y: Int = 0)
54102

55-
val origin = new Point // x and y are both set to 0
56-
val point1 = new Point(1)
57-
println(point1.x) // prints 1
103+
val origin = new Point // x and y are both set to 0
104+
val point1 = new Point(1) // y is set to 0
105+
println(point1) // prints (1, 0)
106+
```
107+
{% endtab %}
108+
109+
{% tab 'Scala 3' for=class-point-with-default-values %}
110+
```scala
111+
class Point(var x: Int = 0, var y: Int = 0)
58112

113+
val origin = Point() // x and y are both set to 0
114+
val point1 = Point(1) // y is set to 0
115+
println(point1) // prints (1, 0)
59116
```
117+
{% endtab %}
118+
119+
{% endtabs %}
60120

61121
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.
122+
123+
{% tabs class-point-named-argument class=tabs-scala-version %}
124+
125+
{% tab 'Scala 2' for=class-point-named-argument %}
62126
```scala mdoc:nest
63127
class Point(var x: Int = 0, var y: Int = 0)
64128
val point2 = new Point(y = 2)
65-
println(point2.y) // prints 2
129+
println(point2) // prints (0, 2)
66130
```
131+
{% endtab %}
132+
133+
{% tab 'Scala 3' for=class-point-named-argument %}
134+
```scala
135+
class Point(var x: Int = 0, var y: Int = 0)
136+
val point2 = Point(y = 2)
137+
println(point2) // prints (0, 2)
138+
```
139+
{% endtab %}
140+
141+
{% endtabs %}
67142

68143
This is also a good practice to enhance clarity.
69144

70145
## Private Members and Getter/Setter Syntax
71146
Members are public by default. Use the `private` access modifier
72147
to hide them from outside of the class.
148+
149+
{% tabs class-point-private-getter-setter class=tabs-scala-version %}
150+
151+
{% tab 'Scala 2' for=class-point-private-getter-setter %}
73152
```scala mdoc:reset
74153
class Point {
75154
private var _x = 0
76155
private var _y = 0
77156
private val bound = 100
78157

79158
def x: Int = _x
80-
def x_= (newValue: Int): Unit = {
81-
if (newValue < bound) _x = newValue else printWarning()
159+
def x_=(newValue: Int): Unit = {
160+
if (newValue < bound)
161+
_x = newValue
162+
else
163+
printWarning()
82164
}
83165

84166
def y: Int = _y
85-
def y_= (newValue: Int): Unit = {
86-
if (newValue < bound) _y = newValue else printWarning()
167+
def y_=(newValue: Int): Unit = {
168+
if (newValue < bound)
169+
_y = newValue
170+
else
171+
printWarning()
87172
}
88173

89-
private def printWarning() = println("WARNING: Out of bounds")
174+
private def printWarning(): Unit =
175+
println("WARNING: Out of bounds")
90176
}
91177

92178
val point1 = new Point
93179
point1.x = 99
94180
point1.y = 101 // prints the warning
95181
```
182+
{% endtab %}
183+
184+
{% tab 'Scala 3' for=class-point-private-getter-setter %}
185+
```scala
186+
class Point:
187+
private var _x = 0
188+
private var _y = 0
189+
private val bound = 100
190+
191+
def x: Int = _x
192+
def x_=(newValue: Int): Unit =
193+
if newValue < bound then
194+
_x = newValue
195+
else
196+
printWarning()
197+
198+
def y: Int = _y
199+
def y_=(newValue: Int): Unit =
200+
if newValue < bound then
201+
_y = newValue
202+
else
203+
printWarning()
204+
205+
private def printWarning(): Unit =
206+
println("WARNING: Out of bounds")
207+
end Point
208+
209+
val point1 = Point()
210+
point1.x = 99
211+
point1.y = 101 // prints the warning
212+
```
213+
{% endtab %}
214+
215+
{% endtabs %}
216+
96217
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.
97218

98219
Primary constructor parameters with `val` and `var` are public. However, because `val`s are immutable, you can't write the following.
220+
221+
{% tabs class-point-cannot-set-val class=tabs-scala-version %}
222+
223+
{% tab 'Scala 2' for=class-point-cannot-set-val %}
99224
```scala mdoc:fail
100225
class Point(val x: Int, val y: Int)
101226
val point = new Point(1, 2)
102227
point.x = 3 // <-- does not compile
103228
```
229+
{% endtab %}
230+
231+
{% tab 'Scala 3' for=class-point-cannot-set-val %}
232+
```scala
233+
class Point(val x: Int, val y: Int)
234+
val point = Point(1, 2)
235+
point.x = 3 // <-- does not compile
236+
```
237+
{% endtab %}
238+
239+
{% endtabs %}
104240

105241
Parameters without `val` or `var` are private values, visible only within the class.
242+
243+
{% tabs class-point-non-val-ctor-param class=tabs-scala-version %}
244+
245+
{% tab 'Scala 2' for=class-point-non-val-ctor-param %}
106246
```scala mdoc:fail
107247
class Point(x: Int, y: Int)
108248
val point = new Point(1, 2)
109249
point.x // <-- does not compile
110250
```
251+
{% endtab %}
252+
253+
{% tab 'Scala 3' for=class-point-non-val-ctor-param %}
254+
```scala
255+
class Point(x: Int, y: Int)
256+
val point = Point(1, 2)
257+
point.x // <-- does not compile
258+
```
259+
{% endtab %}
260+
261+
{% endtabs %}
111262

112263
## More resources
113264

0 commit comments

Comments
 (0)