Skip to content

Commit a08b47c

Browse files
authored
Merge pull request #2497 from Sporarum/update-singleton-objects
Update singleton-objects.md to use scala 2/3 tabs
2 parents 737f12e + aadd3b7 commit a08b47c

File tree

1 file changed

+103
-4
lines changed

1 file changed

+103
-4
lines changed

_tour/singleton-objects.md

Lines changed: 103 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,52 @@ As a top-level value, an object is a singleton.
1616
As a member of an enclosing class or as a local value, it behaves exactly like a lazy val.
1717
# Defining a singleton object
1818
An object is a value. The definition of an object looks like a class, but uses the keyword `object`:
19+
20+
21+
{% tabs object-definition-box %}
22+
23+
{% tab 'Scala 2 and 3' for=object-definition-box %}
1924
```scala mdoc
2025
object Box
2126
```
27+
{% endtab %}
28+
29+
{% endtabs %}
2230

2331
Here's an example of an object with a method:
24-
```
32+
{% tabs singleton-logger-example class=tabs-scala-version %}
33+
34+
{% tab 'Scala 2' for=singleton-logger-example %}
35+
36+
```scala
2537
package logging
2638

2739
object Logger {
2840
def info(message: String): Unit = println(s"INFO: $message")
2941
}
3042
```
43+
{% endtab %}
44+
45+
{% tab 'Scala 3' for=singleton-logger-example %}
46+
47+
```scala
48+
package logging
49+
50+
object Logger:
51+
def info(message: String): Unit = println(s"INFO: $message")
52+
```
53+
{% endtab %}
54+
55+
{% endtabs %}
56+
3157
The method `info` can be imported from anywhere in the program. Creating utility methods like this is a common use case for singleton objects.
3258

3359
Let's see how to use `info` in another package:
60+
{% tabs singleton-usage-example class=tabs-scala-version %}
3461

35-
```
62+
{% tab 'Scala 2' for=singleton-usage-example %}
63+
64+
```scala
3665
import logging.Logger.info
3766

3867
class Project(name: String, daysToComplete: Int)
@@ -43,6 +72,24 @@ class Test {
4372
info("Created projects") // Prints "INFO: Created projects"
4473
}
4574
```
75+
{% endtab %}
76+
77+
{% tab 'Scala 3' for=singleton-usage-example %}
78+
79+
```scala
80+
import logging.Logger.info
81+
82+
class Project(name: String, daysToComplete: Int)
83+
84+
class Test:
85+
val project1 = Project("TPS Reports", 1)
86+
val project2 = Project("Website redesign", 5)
87+
info("Created projects") // Prints "INFO: Created projects"
88+
```
89+
{% endtab %}
90+
91+
{% endtabs %}
92+
4693

4794
The `info` method is visible because of the import statement, `import logging.Logger.info`.
4895

@@ -53,8 +100,11 @@ Note: If an `object` is not top-level but is nested in another class or object,
53100
## Companion objects
54101

55102
An object with the same name as a class is called a _companion object_. Conversely, the class is the object's companion class. A companion class or object can access the private members of its companion. Use a companion object for methods and values which are not specific to instances of the companion class.
56-
```
57-
import scala.math._
103+
{% tabs companion-object-circle class=tabs-scala-version %}
104+
105+
{% tab 'Scala 2' for=companion-object-circle %}
106+
```scala
107+
import scala.math.pow
58108

59109
case class Circle(radius: Double) {
60110
import Circle._
@@ -69,10 +119,34 @@ val circle1 = Circle(5.0)
69119

70120
circle1.area
71121
```
122+
{% endtab %}
123+
124+
{% tab 'Scala 3' for=companion-object-circle %}
125+
```scala
126+
import scala.math.pow
127+
128+
case class Circle(radius: Double):
129+
import Circle.*
130+
def area: Double = calculateArea(radius)
131+
132+
object Circle:
133+
private def calculateArea(radius: Double): Double = Pi * pow(radius, 2.0)
134+
135+
136+
val circle1 = Circle(5.0)
137+
138+
circle1.area
139+
```
140+
{% endtab %}
141+
142+
{% endtabs %}
72143

73144
The `class Circle` has a member `area` which is specific to each instance, and the singleton `object Circle` has a method `calculateArea` which is available to every instance.
74145

75146
The companion object can also contain factory methods:
147+
{% tabs companion-object-email class=tabs-scala-version %}
148+
149+
{% tab 'Scala 2' for=companion-object-email %}
76150
```scala mdoc
77151
class Email(val username: String, val domainName: String)
78152

@@ -95,6 +169,31 @@ scalaCenterEmail match {
95169
case None => println("Error: could not parse email")
96170
}
97171
```
172+
{% endtab %}
173+
174+
{% tab 'Scala 3' for=companion-object-email %}
175+
```scala
176+
class Email(val username: String, val domainName: String)
177+
178+
object Email:
179+
def fromString(emailString: String): Option[Email] =
180+
emailString.split('@') match
181+
case Array(a, b) => Some(Email(a, b))
182+
case _ => None
183+
184+
val scalaCenterEmail = Email.fromString("scala.center@epfl.ch")
185+
scalaCenterEmail match
186+
case Some(email) => println(
187+
s"""Registered an email
188+
|Username: ${email.username}
189+
|Domain name: ${email.domainName}
190+
""".stripMargin)
191+
case None => println("Error: could not parse email")
192+
```
193+
{% endtab %}
194+
195+
{% endtabs %}
196+
98197
The `object Email` contains a factory `fromString` which creates an `Email` instance from a String. We return it as an `Option[Email]` in case of parsing errors.
99198

100199
Note: If a class or object has a companion, both must be defined in the same file. To define companions in the REPL, either define them on the same line or enter `:paste` mode.

0 commit comments

Comments
 (0)