Skip to content

Commit a818702

Browse files
committed
Actual final adjustments
1 parent 3ab5b4b commit a818702

File tree

1 file changed

+23
-2
lines changed

1 file changed

+23
-2
lines changed

_overviews/tutorials/binary-compatibility-for-library-authors.md

+23-2
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ Again, we recommend using MiMa to double-check that you have not broken binary c
178178
Sometimes, it is desirable to change the definition of a case class (adding and/or removing fields) while still staying backwards-compatible with the existing usage of the case class, i.e. not breaking the so-called _binary compatibility_. The first question you should ask yourself is “do you need a _case_ class?” (as opposed to a regular class, which can be easier to evolve in a binary compatible way). A good reason for using a case class is when you need a structural implementation of `equals` and `hashCode`.
179179

180180
To achieve that, follow this pattern:
181-
* make the primary constructor private (this makes private the `copy` method of the class)
181+
* make the primary constructor private (this makes the `copy` method of the class private as well)
182182
* define a private `unapply` function in the companion object (note that by doing that the case class loses the ability to be used as an extractor in match expressions)
183183
* for all the fields, define `withXXX` methods on the case class that create a new instance with the respective field changed (you can use the private `copy` method to implement them)
184184
* create a public constructor by defining an `apply` method in the companion object (it can use the private constructor)
@@ -197,7 +197,7 @@ case class Person private (name: String, age: Int):
197197

198198
object Person:
199199
// Create a public constructor (which uses the primary constructor)
200-
def apply(name: String, age: Int) = new Person(name, age)
200+
def apply(name: String, age: Int): Person = new Person(name, age)
201201
// Make the extractor private
202202
private def unapply(p: Person) = p
203203
```
@@ -236,6 +236,7 @@ alice match
236236

237237
Later in time, you can amend the original case class definition to, say, add an optional `address` field. You
238238
* add a new field `address` and a custom `withAddress` method,
239+
* update the public `apply` method in the companion object to initialize all the fields,
239240
* tell MiMa to [ignore](https://github.com/lightbend/mima#filtering-binary-incompatibilities) changes to the class constructor. This step is necessary because MiMa does not yet ignore changes in private class constructor signatures (see [#738](https://github.com/lightbend/mima/issues/738)).
240241

241242
{% tabs case_class_compat_4 %}
@@ -244,6 +245,10 @@ Later in time, you can amend the original case class definition to, say, add an
244245
case class Person private (name: String, age: Int, address: Option[String]):
245246
...
246247
def withAddress(address: Option[String]) = copy(address = address)
248+
249+
object Person:
250+
// Update the public constructor to also initialize the address field
251+
def apply(name: String, age: Int): Person = new Person(name, age, None)
247252
```
248253
{% endtab %}
249254
{% endtabs %}
@@ -287,6 +292,22 @@ println(bob.address)
287292
288293
A regular case class not following this pattern would break its usage, because by adding a new field changes some methods (which could be used by somebody else), for example `copy` or the constructor itself.
289294
295+
Optionally, you can also add overloads of the `apply` method in the companion object to initialize more fields
296+
in one call. In our example, we can add an overload that also initializes the `address` field:
297+
298+
{% tabs case_class_compat_7 %}
299+
{% tab 'Scala 3 Only' %}
300+
~~~ scala
301+
object Person:
302+
// Original public constructor
303+
def apply(name: String, age: Int): Person = new Person(name, age, None)
304+
// Additional constructor that also sets the address
305+
def apply(name: String, age: Int, address: String): Person =
306+
new Person(name, age, Some(address))
307+
~~~
308+
{% endtab %}
309+
{% endtabs %}
310+
290311
## Versioning Scheme - Communicating compatibility breakages
291312
292313
Library authors use versioning schemes to communicate compatibility guarantees between library releases to their users. Versioning schemes like [Semantic Versioning](https://semver.org/) (SemVer) allow

0 commit comments

Comments
 (0)