diff --git a/.bundle/config b/.bundle/config
deleted file mode 100644
index 9bc01b4c32..0000000000
--- a/.bundle/config
+++ /dev/null
@@ -1,3 +0,0 @@
----
-BUNDLE_PATH: "vendor/bundle"
-BUNDLE_DISABLE_SHARED_GEMS: "true"
diff --git a/.drone.yml b/.drone.yml
deleted file mode 100644
index 7b74f75e3a..0000000000
--- a/.drone.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-pipeline:
- build:
- image: scalacenter/scala-rvm-jvm-coursier:2.0
- commands:
- - ./scripts/ci.sh
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000000..ce1bb0f48b
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+/_ja @scala/docs-ja
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000000..f48b4ada51
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,11 @@
+version: 2
+updates:
+- package-ecosystem: bundler
+ directory: "/"
+ schedule:
+ interval: daily
+ open-pull-requests-limit: 10
+ ignore:
+ - dependency-name: html-proofer
+ versions:
+ - "> 3.15.3"
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000000..e56f07a0ab
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,33 @@
+name: Build
+on: [push, pull_request]
+jobs:
+ build:
+ runs-on: ubuntu-22.04
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: 3.2.6
+ bundler-cache: true
+ - name: Set up coursier
+ uses: coursier/setup-action@v1.3.5
+ with:
+ jvm: adopt:11
+ - name: Run mdoc
+ run: |
+ ./scripts/run-mdoc.sh
+ rm -r /tmp/mdoc-out/
+ - name: Jekyll build
+ run: bundle exec jekyll build
+ - name: HTMLProofer
+ run: |
+ # # Checking for docs.scala-lang/blob/main leads to a chicken and egg problem because of the edit links of new pages.
+ bundle exec htmlproofer ./_site/\
+ --only-4xx\
+ --ignore-status-codes "400,401,403,429"\
+ --ignore-empty-alt\
+ --allow-hash-href\
+ --no-enforce-https\
+ --ignore-urls '/https://github.com/scala/,/www.oracle.com/'
+
diff --git a/.gitignore b/.gitignore
index c73823b558..055aee462d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,5 +8,5 @@ _site
vendor/bundle
.idea/
/coursier
-/tut-tmp/
.sass-cache/
+.jekyll-cache/
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000..b2bbc255f9
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,12 @@
+FROM ruby:3.2.6
+
+RUN gem install bundler:2.6.5
+
+WORKDIR /srv/jekyll
+
+COPY Gemfile .
+COPY Gemfile.lock .
+
+RUN echo -n "bundle version: " && bundle --version
+RUN chmod u+s /bin/chown
+RUN bundle install
diff --git a/Gemfile b/Gemfile
index 26b5aee372..31cb37fbea 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,15 +1,6 @@
source 'https://rubygems.org'
-gem 'jekyll-redirect-from'
-gem 'jekyll-scalafiddle'
+gem 'github-pages'
+gem 'webrick'
+#
gem 'html-proofer'
-gem 'kramdown-parser-gfm'
-# gem 'html-proofer' # link-checking: bundle exec htmlproofer ./_site/ --only-4xx --empty-alt-ignore --allow-hash-href
-
-# group :jekyll_plugins do
-# gem 'hawkins'
-# end
-
-# ^ Useful for live reloading the site in your
-# browser during development. To use, uncomment
-# and do:
-# bundle exec jekyll liveserve --incremental
+# gem 'html-proofer' # link-checking: bundle exec htmlproofer ./_site/ --only-4xx --ignore-empty-alt=true --allow-hash-href=true
diff --git a/Gemfile.lock b/Gemfile.lock
index 1db7590360..8088be3873 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,34 +1,146 @@
GEM
remote: https://rubygems.org/
specs:
- addressable (2.7.0)
- public_suffix (>= 2.0.2, < 5.0)
+ Ascii85 (2.0.1)
+ activesupport (8.0.1)
+ base64
+ benchmark (>= 0.3)
+ bigdecimal
+ concurrent-ruby (~> 1.0, >= 1.3.1)
+ connection_pool (>= 2.2.5)
+ drb
+ i18n (>= 1.6, < 2)
+ logger (>= 1.4.2)
+ minitest (>= 5.1)
+ securerandom (>= 0.3)
+ tzinfo (~> 2.0, >= 2.0.5)
+ uri (>= 0.13.1)
+ addressable (2.8.7)
+ public_suffix (>= 2.0.2, < 7.0)
+ afm (0.2.2)
+ async (2.23.0)
+ console (~> 1.29)
+ fiber-annotation
+ io-event (~> 1.9)
+ metrics (~> 0.12)
+ traces (~> 0.15)
+ base64 (0.2.0)
+ benchmark (0.4.0)
+ bigdecimal (3.1.9)
+ coffee-script (2.4.1)
+ coffee-script-source
+ execjs
+ coffee-script-source (1.12.2)
colorator (1.1.0)
- concurrent-ruby (1.1.7)
- em-websocket (0.5.1)
+ commonmarker (0.23.11)
+ concurrent-ruby (1.3.5)
+ connection_pool (2.5.0)
+ console (1.29.3)
+ fiber-annotation
+ fiber-local (~> 1.1)
+ json
+ csv (3.3.2)
+ dnsruby (1.72.3)
+ base64 (~> 0.2.0)
+ simpleidn (~> 0.2.1)
+ drb (2.2.1)
+ em-websocket (0.5.3)
eventmachine (>= 0.12.9)
- http_parser.rb (~> 0.6.0)
- ethon (0.12.0)
- ffi (>= 1.3.0)
+ http_parser.rb (~> 0)
+ ethon (0.16.0)
+ ffi (>= 1.15.0)
eventmachine (1.2.7)
- ffi (1.13.1)
+ execjs (2.10.0)
+ faraday (2.12.2)
+ faraday-net_http (>= 2.0, < 3.5)
+ json
+ logger
+ faraday-net_http (3.4.0)
+ net-http (>= 0.5.0)
+ ffi (1.17.1-arm64-darwin)
+ ffi (1.17.1-x64-mingw-ucrt)
+ ffi (1.17.1-x86_64-linux-gnu)
+ fiber-annotation (0.2.0)
+ fiber-local (1.1.0)
+ fiber-storage
+ fiber-storage (1.0.0)
forwardable-extended (2.6.0)
- html-proofer (3.15.3)
- addressable (~> 2.3)
+ gemoji (4.1.0)
+ github-pages (232)
+ github-pages-health-check (= 1.18.2)
+ jekyll (= 3.10.0)
+ jekyll-avatar (= 0.8.0)
+ jekyll-coffeescript (= 1.2.2)
+ jekyll-commonmark-ghpages (= 0.5.1)
+ jekyll-default-layout (= 0.1.5)
+ jekyll-feed (= 0.17.0)
+ jekyll-gist (= 1.5.0)
+ jekyll-github-metadata (= 2.16.1)
+ jekyll-include-cache (= 0.2.1)
+ jekyll-mentions (= 1.6.0)
+ jekyll-optional-front-matter (= 0.3.2)
+ jekyll-paginate (= 1.1.0)
+ jekyll-readme-index (= 0.3.0)
+ jekyll-redirect-from (= 0.16.0)
+ jekyll-relative-links (= 0.6.1)
+ jekyll-remote-theme (= 0.4.3)
+ jekyll-sass-converter (= 1.5.2)
+ jekyll-seo-tag (= 2.8.0)
+ jekyll-sitemap (= 1.4.0)
+ jekyll-swiss (= 1.0.0)
+ jekyll-theme-architect (= 0.2.0)
+ jekyll-theme-cayman (= 0.2.0)
+ jekyll-theme-dinky (= 0.2.0)
+ jekyll-theme-hacker (= 0.2.0)
+ jekyll-theme-leap-day (= 0.2.0)
+ jekyll-theme-merlot (= 0.2.0)
+ jekyll-theme-midnight (= 0.2.0)
+ jekyll-theme-minimal (= 0.2.0)
+ jekyll-theme-modernist (= 0.2.0)
+ jekyll-theme-primer (= 0.6.0)
+ jekyll-theme-slate (= 0.2.0)
+ jekyll-theme-tactile (= 0.2.0)
+ jekyll-theme-time-machine (= 0.2.0)
+ jekyll-titles-from-headings (= 0.5.3)
+ jemoji (= 0.13.0)
+ kramdown (= 2.4.0)
+ kramdown-parser-gfm (= 1.1.0)
+ liquid (= 4.0.4)
mercenary (~> 0.3)
- nokogumbo (~> 2.0)
- parallel (~> 1.3)
+ minima (= 2.5.1)
+ nokogiri (>= 1.16.2, < 2.0)
+ rouge (= 3.30.0)
+ terminal-table (~> 1.4)
+ webrick (~> 1.8)
+ github-pages-health-check (1.18.2)
+ addressable (~> 2.3)
+ dnsruby (~> 1.60)
+ octokit (>= 4, < 8)
+ public_suffix (>= 3.0, < 6.0)
+ typhoeus (~> 1.3)
+ hashery (2.1.2)
+ html-pipeline (2.14.3)
+ activesupport (>= 2)
+ nokogiri (>= 1.4)
+ html-proofer (5.0.10)
+ addressable (~> 2.3)
+ async (~> 2.1)
+ nokogiri (~> 1.13)
+ pdf-reader (~> 2.11)
rainbow (~> 3.0)
typhoeus (~> 1.3)
yell (~> 2.0)
- http_parser.rb (0.6.0)
- i18n (0.9.5)
+ zeitwerk (~> 2.5)
+ http_parser.rb (0.8.0)
+ i18n (1.14.7)
concurrent-ruby (~> 1.0)
- jekyll (3.9.0)
+ io-event (1.9.0)
+ jekyll (3.10.0)
addressable (~> 2.4)
colorator (~> 1.0)
+ csv (~> 3.0)
em-websocket (~> 0.5)
- i18n (~> 0.7)
+ i18n (>= 0.7, < 2)
jekyll-sass-converter (~> 1.0)
jekyll-watch (~> 2.0)
kramdown (>= 1.17, < 3)
@@ -37,56 +149,185 @@ GEM
pathutil (~> 0.9)
rouge (>= 1.7, < 4)
safe_yaml (~> 1.0)
- jekyll-redirect-from (0.15.0)
+ webrick (>= 1.0)
+ jekyll-avatar (0.8.0)
+ jekyll (>= 3.0, < 5.0)
+ jekyll-coffeescript (1.2.2)
+ coffee-script (~> 2.2)
+ coffee-script-source (~> 1.12)
+ jekyll-commonmark (1.4.0)
+ commonmarker (~> 0.22)
+ jekyll-commonmark-ghpages (0.5.1)
+ commonmarker (>= 0.23.7, < 1.1.0)
+ jekyll (>= 3.9, < 4.0)
+ jekyll-commonmark (~> 1.4.0)
+ rouge (>= 2.0, < 5.0)
+ jekyll-default-layout (0.1.5)
+ jekyll (>= 3.0, < 5.0)
+ jekyll-feed (0.17.0)
+ jekyll (>= 3.7, < 5.0)
+ jekyll-gist (1.5.0)
+ octokit (~> 4.2)
+ jekyll-github-metadata (2.16.1)
+ jekyll (>= 3.4, < 5.0)
+ octokit (>= 4, < 7, != 4.4.0)
+ jekyll-include-cache (0.2.1)
+ jekyll (>= 3.7, < 5.0)
+ jekyll-mentions (1.6.0)
+ html-pipeline (~> 2.3)
+ jekyll (>= 3.7, < 5.0)
+ jekyll-optional-front-matter (0.3.2)
+ jekyll (>= 3.0, < 5.0)
+ jekyll-paginate (1.1.0)
+ jekyll-readme-index (0.3.0)
+ jekyll (>= 3.0, < 5.0)
+ jekyll-redirect-from (0.16.0)
jekyll (>= 3.3, < 5.0)
+ jekyll-relative-links (0.6.1)
+ jekyll (>= 3.3, < 5.0)
+ jekyll-remote-theme (0.4.3)
+ addressable (~> 2.0)
+ jekyll (>= 3.5, < 5.0)
+ jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0)
+ rubyzip (>= 1.3.0, < 3.0)
jekyll-sass-converter (1.5.2)
sass (~> 3.4)
- jekyll-scalafiddle (1.0.1)
- jekyll (~> 3.0)
+ jekyll-seo-tag (2.8.0)
+ jekyll (>= 3.8, < 5.0)
+ jekyll-sitemap (1.4.0)
+ jekyll (>= 3.7, < 5.0)
+ jekyll-swiss (1.0.0)
+ jekyll-theme-architect (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-cayman (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-dinky (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-hacker (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-leap-day (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-merlot (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-midnight (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-minimal (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-modernist (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-primer (0.6.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-github-metadata (~> 2.9)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-slate (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-tactile (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-time-machine (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-titles-from-headings (0.5.3)
+ jekyll (>= 3.3, < 5.0)
jekyll-watch (2.2.1)
listen (~> 3.0)
- kramdown (2.3.0)
+ jemoji (0.13.0)
+ gemoji (>= 3, < 5)
+ html-pipeline (~> 2.2)
+ jekyll (>= 3.0, < 5.0)
+ json (2.10.2)
+ kramdown (2.4.0)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
- liquid (4.0.3)
- listen (3.2.1)
+ liquid (4.0.4)
+ listen (3.9.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
+ logger (1.6.6)
mercenary (0.3.6)
- mini_portile2 (2.4.0)
- nokogiri (1.10.10)
- mini_portile2 (~> 2.4.0)
- nokogumbo (2.0.2)
- nokogiri (~> 1.8, >= 1.8.4)
- parallel (1.19.2)
+ metrics (0.12.1)
+ minima (2.5.1)
+ jekyll (>= 3.5, < 5.0)
+ jekyll-feed (~> 0.9)
+ jekyll-seo-tag (~> 2.1)
+ minitest (5.25.4)
+ net-http (0.6.0)
+ uri
+ nokogiri (1.18.8-arm64-darwin)
+ racc (~> 1.4)
+ nokogiri (1.18.8-x64-mingw-ucrt)
+ racc (~> 1.4)
+ nokogiri (1.18.8-x86_64-linux-gnu)
+ racc (~> 1.4)
+ octokit (4.25.1)
+ faraday (>= 1, < 3)
+ sawyer (~> 0.9)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
- public_suffix (4.0.5)
- rainbow (3.0.0)
- rb-fsevent (0.10.4)
- rb-inotify (0.10.1)
+ pdf-reader (2.14.1)
+ Ascii85 (>= 1.0, < 3.0, != 2.0.0)
+ afm (~> 0.2.1)
+ hashery (~> 2.0)
+ ruby-rc4
+ ttfunk
+ public_suffix (5.1.1)
+ racc (1.8.1)
+ rainbow (3.1.1)
+ rb-fsevent (0.11.2)
+ rb-inotify (0.11.1)
ffi (~> 1.0)
- rexml (3.2.4)
- rouge (3.22.0)
+ rexml (3.4.1)
+ rouge (3.30.0)
+ ruby-rc4 (0.1.5)
+ rubyzip (2.4.1)
safe_yaml (1.0.5)
sass (3.7.4)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
- typhoeus (1.4.0)
+ sawyer (0.9.2)
+ addressable (>= 2.3.5)
+ faraday (>= 0.17.3, < 3)
+ securerandom (0.4.1)
+ simpleidn (0.2.3)
+ terminal-table (1.8.0)
+ unicode-display_width (~> 1.1, >= 1.1.1)
+ traces (0.15.2)
+ ttfunk (1.8.0)
+ bigdecimal (~> 3.1)
+ typhoeus (1.4.1)
ethon (>= 0.9.0)
+ tzinfo (2.0.6)
+ concurrent-ruby (~> 1.0)
+ unicode-display_width (1.8.0)
+ uri (1.0.3)
+ webrick (1.9.1)
yell (2.2.2)
+ zeitwerk (2.7.2)
PLATFORMS
- ruby
+ arm64-darwin-22
+ arm64-darwin-23
+ arm64-darwin-24
+ x64-mingw-ucrt
+ x86_64-linux
DEPENDENCIES
+ github-pages
html-proofer
- jekyll-redirect-from
- jekyll-scalafiddle
- kramdown-parser-gfm
+ webrick
BUNDLED WITH
- 1.17.2
+ 2.6.5
diff --git a/README.md b/README.md
index eef762ce16..013a66267c 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,17 @@
# Scala Documentation #
-[](https://platform-ci.scala-lang.org/scala/docs.scala-lang)
+[](https://github.com/scala/docs.scala-lang/actions/workflows/build.yml?query=branch%3Amain)
This repository contains the source for the Scala documentation website, as well as the source for "Scala Improvement Process" (SIP) documents.
+## Dependencies ##
+
+This site uses a Jekyll, a Ruby framework. You'll need Ruby and Bundler installed; see [Jekyll installation instructions](https://jekyllrb.com/docs/installation/) for the details.
+
## Quickstart ##
To build and view the site locally:
- gem install bundler
bundle install
bundle exec jekyll serve -I
@@ -16,27 +19,44 @@ To build and view the site locally:
For more details, read on.
-## Quickstart with Docker ##
+## Quickstart with Docker Compose ##
+
+You need to have [Docker Engine](https://docs.docker.com/engine/) and [Docker Compose](https://docs.docker.com/compose/) installed on your machine.
+Under macOS (Intel or Apple silicon), instead of installing [Docker Desktop](https://docs.docker.com/desktop/) you can also use [HomeBrew](https://brew.sh/) with [Colima](https://github.com/abiosoft/colima): `brew install colima docker docker-compose`.
+UID and GID environment variables are needed to avoid docker from writing files as root in your directory.
+By default, docker-compose will use the file docker-compose.yml which will build the website and serve it on 0.0.0.0:4000 .
+If you just need to build the website, add ```-f docker-compose_build-only.yml```
+
+```
+env UID="$(id -u)" GID="$(id -g)" docker-compose up
+```
+
+The generated site is available at `http://localhost:4000`.
-To build and view site with docker:
+When the website dependencies change (the content of the `Gemfile`),
+you have to re-build the Docker image:
- docker-compose up
+```
+env UID="$(id -u)" GID="$(id -g)" docker-compose up --build
+```
-It will incrementally build and serve site at `http://localhost:8080`
+If you have problems with the Docker image or want to force the rebuild of the Docker image:
+```
+env UID="$(id -u)" GID="$(id -g)" docker-compose build --no-cache
+```
+
+
+For more details on the Docker option, see also [this issue](https://github.com/scala/docs.scala-lang/issues/1286).
## Contributing ##
-Please have a look at [https://docs.scala-lang.org/contribute.html](https://docs.scala-lang.org/contribute.html) before making a contribution.
+Please have a look at [Add New Guides/Tutorials](https://docs.scala-lang.org/contribute/add-guides.html) before making a contribution.
This document gives an overview of the type of documentation contained within the Scala Documentation repository and the repository's structure.
Small changes, or corrected typos will generally be pulled in right away. Large changes, like the addition of new documents, or the rewriting of
existing documents will be thoroughly reviewed-- please keep in mind that, generally, new documents must be very well-polished, complete, and maintained
in order to be accepted.
-## Dependencies ##
-
-This site uses a Jekyll, a Ruby framework. You'll need Ruby and Bundler installed; see [Jekyll installation instructions](https://jekyllrb.com/docs/installation/) for the details.
-
## Building & Viewing ##
cd into the directory where you cloned this repository, then install the required gems with `bundle install`. This will automatically put the gems into `./vendor/bundle`.
@@ -62,9 +82,9 @@ The markdown used in this site uses [kramdown](https://kramdown.gettalong.org/)
### Markdown Editor for OSX ###
-There's a free markdown editor for OSX called [Mou](http://25.io/mou/). It's quite convenient to work with, and it generates the translated Markdown in real-time alongside of your editor window, as can be seen here:
+There's a free markdown editor for OSX called [MacDown](https://github.com/MacDownApp/macdown). It's quite convenient to work with, and it generates the translated Markdown in real-time alongside of your editor window, as can be seen here:
-
+
## License ##
diff --git a/_ba/tour/abstract-type-members.md b/_ba/tour/abstract-type-members.md
index 9e577d7cda..b7034b6922 100644
--- a/_ba/tour/abstract-type-members.md
+++ b/_ba/tour/abstract-type-members.md
@@ -15,7 +15,7 @@ Trejtovi i apstraktne klase mogu imati apstraktne tipove kao članove.
To znači da konkretne implementacije definišu stvarni tip.
Slijedi primjer:
-```tut
+```scala mdoc
trait Buffer {
type T
val element: T
@@ -26,7 +26,7 @@ U gornjem primjeru smo definisali apstraktni tip `T`.
On se koristi za opis člana `element`.
Ovaj trejt možemo naslijediti u apstraktnoj klasi i dodati gornju granicu tipa za `T` da bi ga učinili preciznijim.
-```tut
+```scala mdoc
abstract class SeqBuffer extends Buffer {
type U
type T <: Seq[U]
@@ -40,7 +40,7 @@ mora biti podtip `Seq[U]` za neki novi apstraktni tip `U`.
Trejtovi ili [klase](classes.html) s apstraktnim tip-članovima se često koriste u kombinaciji s instanciranjem anonimnih klasa.
Radi ilustracije, pogledaćemo program koji radi s sekvencijalnim baferom koji sadrži listu integera:
-```tut
+```scala mdoc
abstract class IntSeqBuffer extends SeqBuffer {
type U = Int
}
@@ -61,7 +61,7 @@ Metoda `newIntSeqBuf` koristi anonimnu klasu kao implementaciju `IntSeqBuf` pos
Često je moguće pretvoriti apstraktni tip-član u tipski parametar klase i obrnuto.
Slijedi verzija gornjeg koda koji koristi tipske parametre:
-```tut
+```scala mdoc:nest
abstract class Buffer[+T] {
val element: T
}
diff --git a/_ba/tour/annotations.md b/_ba/tour/annotations.md
index d39d970873..24b17a9012 100644
--- a/_ba/tour/annotations.md
+++ b/_ba/tour/annotations.md
@@ -5,7 +5,7 @@ language: ba
partof: scala-tour
num: 32
-next-page: default-parameter-values
+next-page: packages-and-imports
previous-page: by-name-parameters
---
@@ -30,7 +30,7 @@ Redoslijed anotacijskih klauza nije bitan.
Određene anotacije će uzrokovati pad kompajliranja ako određeni uslovi nisu ispunjeni.
Npr, anotacija `@tailrec` osigurava da je metoda [tail-rekurzivna](https://en.wikipedia.org/wiki/Tail_call). Tail-rekurzija može zadržati memorijske zahtjeve konstantnim.
Evo kako se koristi na metodi koja izračunava faktorijel:
-```tut
+```scala mdoc
import scala.annotation.tailrec
def factorial(x: Int): Int = {
diff --git a/_ba/tour/automatic-closures.md b/_ba/tour/automatic-closures.md
deleted file mode 100644
index 90f751ee2c..0000000000
--- a/_ba/tour/automatic-closures.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-layout: tour
-title: Automatic Type-Dependent Closure Construction
-partof: scala-tour
-
-language: ba
----
diff --git a/_ba/tour/basics.md b/_ba/tour/basics.md
index 6204faa74b..97956e6149 100644
--- a/_ba/tour/basics.md
+++ b/_ba/tour/basics.md
@@ -14,9 +14,9 @@ Na ovoj stranici ćemo objasniti osnove Scale.
## Probavanje Scale u browseru
-Scalu možete probati u Vašem browser sa ScalaFiddle aplikacijom.
+Scalu možete probati u Vašem browser sa Scastie aplikacijom.
-1. Idite na [https://scalafiddle.io](https://scalafiddle.io).
+1. Idite na [Scastie](https://scastie.scala-lang.org/).
2. Zalijepite `println("Hello, world!")` u lijevi panel.
3. Kliknite "Run" dugme. Izlaz će se pojaviti u desnom panelu.
@@ -30,7 +30,7 @@ Izrazi su izjave koje imaju vrijednost.
```
Rezultate izraza možete prikazati pomoću `println`.
-```tut
+```scala mdoc
println(1) // 1
println(1 + 1) // 2
println("Hello!") // Hello!
@@ -41,33 +41,33 @@ println("Hello," + " world!") // Hello, world!
Rezultatima možete dodijeliti naziv pomoću ključne riječi `val`.
-```tut
+```scala mdoc
val x = 1 + 1
println(x) // 2
```
-Imenovani rezultati, kao `x` ovdje, nazivaju se vrijednostima.
+Imenovani rezultati, kao `x` ovdje, nazivaju se vrijednostima.
Referenciranje vrijednosti ne okida njeno ponovno izračunavanje.
Vrijednosti se ne mogu mijenjati.
-```tut:fail
+```scala mdoc:fail
x = 3 // Ovo se ne kompajlira.
```
Tipovi vrijednosti mogu biti (automatski) zaključeni, ali možete i eksplicitno navesti tip:
-```tut
+```scala mdoc:nest
val x: Int = 1 + 1
```
-Primijetite da deklaracija tipa `Int` dolazi nakon identifikatora `x`. Također morate dodati i `:`.
+Primijetite da deklaracija tipa `Int` dolazi nakon identifikatora `x`. Također morate dodati i `:`.
### Varijable
Varijable su kao vrijednosti, osim što ih možete promijeniti. Varijable se definišu ključnom riječju `var`.
-```tut
+```scala mdoc:nest
var x = 1 + 1
x = 3 // Ovo se kompajlira jer je "x" deklarisano s "var" ključnom riječju.
println(x * x) // 9
@@ -75,7 +75,7 @@ println(x * x) // 9
Kao i s vrijednostima, tip možete eksplicitno navesti ako želite:
-```tut
+```scala mdoc:nest
var x: Int = 1 + 1
```
@@ -86,7 +86,7 @@ Izraze možete kombinovati okružujući ih s `{}`. Ovo se naziva blok.
Rezultat zadnjeg izraza u bloku je rezultat cijelog bloka, također.
-```tut
+```scala mdoc
println({
val x = 1 + 1
x + 1
@@ -99,7 +99,7 @@ Funkcije su izrazi koji primaju parametre.
Možete definisati anonimnu funkciju (bez imena) koja vraća cijeli broj plus jedan:
-```tut
+```scala mdoc
(x: Int) => x + 1
```
@@ -107,21 +107,21 @@ Na lijevoj strani `=>` je lista parametara. Na desnoj strani je izraz koji koris
Funkcije možete i imenovati.
-```tut
+```scala mdoc
val addOne = (x: Int) => x + 1
println(addOne(1)) // 2
```
Funkcije mogu imati više parametara.
-```tut
+```scala mdoc
val add = (x: Int, y: Int) => x + y
println(add(1, 2)) // 3
```
Ili bez parametara.
-```tut
+```scala mdoc
val getTheAnswer = () => 42
println(getTheAnswer()) // 42
```
@@ -132,7 +132,7 @@ Metode izgledaju i ponašaju se vrlo slično funkcijama, ali postoji nekoliko ra
Metode se definišu ključnom riječju `def`. Nakon `def` slijedi naziv, lista parametara, povratni tip, i tijelo.
-```tut
+```scala mdoc:nest
def add(x: Int, y: Int): Int = x + y
println(add(1, 2)) // 3
```
@@ -141,14 +141,14 @@ Primijetite da je povratni tip deklarisan _nakon_ liste parametara i dvotačke `
Metode mogu imati više listi parametara.
-```tut
+```scala mdoc
def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier
println(addThenMultiply(1, 2)(3)) // 9
```
Ili bez listi parametara ikako.
-```tut
+```scala mdoc
def name: String = System.getProperty("name")
println("Hello, " + name + "!")
```
@@ -157,15 +157,13 @@ Postoje i neke druge razlike, ali zasad, možete misliti o njima kao nečemu sli
Metode mogu imati višelinijske izraze također.
-{% scalafiddle %}
-```tut
+```scala mdoc
def getSquareString(input: Double): String = {
val square = input * input
square.toString
}
println(getSquareString(2.5)) // 6.25
```
-{% endscalafiddle %}
Zadnjo izraz u tijelu metode je povratna vrijednost metode. (Scala ima ključnu riječ `return`, ali se rijetko koristi.)
@@ -173,20 +171,20 @@ Zadnjo izraz u tijelu metode je povratna vrijednost metode. (Scala ima ključnu
Klasu možete definisati ključnom riječju `class` praćenom imenom i parametrima konstruktora.
-```tut
+```scala mdoc
class Greeter(prefix: String, suffix: String) {
def greet(name: String): Unit =
println(prefix + name + suffix)
}
```
-Povratni tip metode `greet` je `Unit`, koji kaže da metoda ne vraća ništa značajno.
-Koristi se slično kao `void` u Javi ili C-u.
-(Razlika je u tome što svaki Scalin izraz mora imati neku vrijednost, postoji singlton vrijednost tipa `Unit`, piše se `()`.
+Povratni tip metode `greet` je `Unit`, koji kaže da metoda ne vraća ništa značajno.
+Koristi se slično kao `void` u Javi ili C-u.
+(Razlika je u tome što svaki Scalin izraz mora imati neku vrijednost, postoji singlton vrijednost tipa `Unit`, piše se `()`.
Ne prenosi nikakvu korisnu informaciju.)
Instancu klase možete kreirati pomoću ključne riječi `new`.
-```tut
+```scala mdoc
val greeter = new Greeter("Hello, ", "!")
greeter.greet("Scala developer") // Hello, Scala developer!
```
@@ -195,16 +193,16 @@ Detaljniji pregled klasa biće dat [kasnije](classes.html).
## Case klase
-Scala ima poseban tip klase koji se zove "case" klasa.
+Scala ima poseban tip klase koji se zove "case" klasa.
Po defaultu, case klase su nepromjenjive i porede se po vrijednosti. Možete ih definisati s `case class` ključnim riječima.
-```tut
+```scala mdoc
case class Point(x: Int, y: Int)
```
Instancu case klase možete kreirati i bez ključne riječi `new`.
-```tut
+```scala mdoc
val point = Point(1, 2)
val anotherPoint = Point(1, 2)
val yetAnotherPoint = Point(2, 2)
@@ -212,17 +210,17 @@ val yetAnotherPoint = Point(2, 2)
I porede se po vrijednosti.
-```tut
+```scala mdoc
if (point == anotherPoint) {
- println(point + " and " + anotherPoint + " are the same.")
+ println(s"$point and $anotherPoint are the same.")
} else {
- println(point + " and " + anotherPoint + " are different.")
+ println(s"$point and $anotherPoint are different.")
} // Point(1,2) i Point(1,2) su iste.
if (point == yetAnotherPoint) {
- println(point + " and " + yetAnotherPoint + " are the same.")
+ println(s"$point and $yetAnotherPoint are the same.")
} else {
- println(point + " and " + yetAnotherPoint + " are different.")
+ println(s"$point and $yetAnotherPoint are different.")
} // Point(1,2) su Point(2,2) različite.
```
@@ -235,7 +233,7 @@ Objasnićemo ih u dubinu [kasnije](case-classes.html).
Objekti su jedine instance svojih definicija. Možete misliti o njima kao singltonima svoje vlastite klase.
Objekte možete definisati ključnom riječju `object`.
-```tut
+```scala mdoc
object IdFactory {
private var counter = 0
def create(): Int = {
@@ -247,7 +245,7 @@ object IdFactory {
Objektima možete pristupati referenciranjem njihovog imena.
-```tut
+```scala mdoc
val newId: Int = IdFactory.create()
println(newId) // 1
val newerId: Int = IdFactory.create()
@@ -262,7 +260,7 @@ Trejtovi su tipovi koji sadrže polja i metode. Više trejtova se može kombino
Definišu se pomoću `trait` ključne riječi.
-```tut
+```scala mdoc:nest
trait Greeter {
def greet(name: String): Unit
}
@@ -270,7 +268,7 @@ trait Greeter {
Metode trejtova mogu imati defaultnu implementaciju.
-```tut
+```scala mdoc:reset
trait Greeter {
def greet(name: String): Unit =
println("Hello, " + name + "!")
@@ -279,7 +277,7 @@ trait Greeter {
Možete naslijediti trejtove s `extends` ključnom riječi i redefinisati (override) implementacije s `override` ključnom riječi.
-```tut
+```scala mdoc
class DefaultGreeter extends Greeter
class CustomizableGreeter(prefix: String, postfix: String) extends Greeter {
@@ -301,12 +299,12 @@ Trejtove ćemo pokriti u dubinu [kasnije](traits.html).
## Glavna metoda
-Glavna metoda je ulazna tačka programa.
+Glavna metoda je ulazna tačka programa.
Java Virtuelna Mašina traži da se glavna metoda zove `main` i da prima jedan argument, niz stringova.
Koristeći objekt, možete definisati glavnu metodu ovako:
-```tut
+```scala mdoc
object Main {
def main(args: Array[String]): Unit =
println("Hello, Scala developer!")
diff --git a/_ba/tour/by-name-parameters.md b/_ba/tour/by-name-parameters.md
index e166f5242f..5cfc42f8cb 100644
--- a/_ba/tour/by-name-parameters.md
+++ b/_ba/tour/by-name-parameters.md
@@ -13,7 +13,7 @@ previous-page: operators
_By-name parametri_ (u slobodnom prevodu "po-imenu parametri") se izračunavaju samo kada se koriste.
Oni su kontrastu sa _by-value parametrima_ ("po-vrijednosti parametri").
Da bi parametar bio pozivan by-name, dodajte `=>` prije njegovog tipa.
-```tut
+```scala mdoc
def calculate(input: => Int) = input * 37
```
By-name parametri imaju prednost da se ne izračunavaju ako se ne koriste u tijelu funkcije.
@@ -21,7 +21,7 @@ U drugu ruku, by-value parametri imaju prednost da se izračunavaju samo jednom.
Ovo je primjer kako bi mogli implementirati while petlju:
-```tut
+```scala mdoc
def whileLoop(condition: => Boolean)(body: => Unit): Unit =
if (condition) {
body
diff --git a/_ba/tour/case-classes.md b/_ba/tour/case-classes.md
index a4cac6fad7..0c6de6d7b4 100644
--- a/_ba/tour/case-classes.md
+++ b/_ba/tour/case-classes.md
@@ -17,7 +17,7 @@ U sljedećem koraku turneje, vidjećemo kako su korisne u [podudaranju uzoraka (
## Definisanje case klase
Minimalna case klasa se sastoji iz ključnih riječi `case class`, identifikatora, i liste parametara (koja može biti prazna):
-```tut
+```scala mdoc
case class Book(isbn: String)
val frankenstein = Book("978-0486282114")
diff --git a/_ba/tour/classes.md b/_ba/tour/classes.md
index 534b1c6f27..29f170dca0 100644
--- a/_ba/tour/classes.md
+++ b/_ba/tour/classes.md
@@ -18,7 +18,7 @@ Tipovi, objekti i trejtovi biće pokriveni kasnije.
## Definisanje klase
Minimalna definicija klase sastoji se od riječi `class` i identifikatora. Imena klasa bi trebala počinjati velikim slovom.
-```tut
+```scala mdoc
class User
val user1 = new User
@@ -28,7 +28,7 @@ Ključna riječ `new` koristi se za kreiranje instance klase.
Međutim, često ćete imati konstruktor i tijelo klase.
Slijedi definicija klase `Point` (en. tačka):
-```tut
+```scala mdoc
class Point(var x: Int, var y: Int) {
def move(dx: Int, dy: Int): Unit = {
@@ -56,7 +56,7 @@ Pošto `toString` prebrisava metodu `toString` iz [`AnyRef`](unified-types.html)
Konstruktori mogu imati opcione parametre koristeći podrazumijevane vrijednosti:
-```tut
+```scala mdoc:nest
class Point(var x: Int = 0, var y: Int = 0)
val origin = new Point // x and y are both set to 0
@@ -67,7 +67,7 @@ println(point1.x) // prints 1
U ovoj verziji klase `Point`, `x` i `y` imaju podrazumijevanu vrijednost `0` tako da ne morate proslijediti argumente.
Međutim, pošto se argumenti konstruktora čitaju s lijeva na desno, ako želite proslijediti samo `y` vrijednost, morate imenovati parametar.
-```
+```scala mdoc:nest
class Point(var x: Int = 0, var y: Int = 0)
val point2 = new Point(y=2)
println(point2.y) // prints 2
@@ -78,7 +78,7 @@ Ovo je također dobra praksa zbog poboljšanja čitljivosti.
## Privatni članovi i sintaksa getera/setera
Članovi su javni (`public`) po defaultu.
Koristite `private` modifikator pristupa da sakrijete članove klase.
-```tut
+```scala mdoc:nest
class Point {
private var _x = 0
private var _y = 0
@@ -108,14 +108,14 @@ Primijetite specijalnu sintaksu za setere: metoda ima `_=` nadodano na identifik
Parametri primarnog konstruktora s `val` i `var` su javni.
Međutim, pošto su `val` nepromjenjivi, ne možete napisati sljedeće.
-```
+```scala mdoc:fail
class Point(val x: Int, val y: Int)
val point = new Point(1, 2)
point.x = 3 // <-- does not compile
```
Parametri bez `val` ili `var` su privatne vrijednosti, vidljive samo unutar klase.
-```
+```scala mdoc:fail
class Point(x: Int, y: Int)
val point = new Point(1, 2)
point.x // <-- does not compile
diff --git a/_ba/tour/compound-types.md b/_ba/tour/compound-types.md
index 316d874c85..3781e866e3 100644
--- a/_ba/tour/compound-types.md
+++ b/_ba/tour/compound-types.md
@@ -15,7 +15,7 @@ U Scali ovo može biti izraženo pomoću *složenih tipova*, koji su presjeci ti
Pretpostavimo da imamo dva trejta: `Cloneable` i `Resetable`:
-```tut
+```scala mdoc
trait Cloneable extends java.lang.Cloneable {
override def clone(): Cloneable = {
super.clone().asInstanceOf[Cloneable]
diff --git a/_ba/tour/default-parameter-values.md b/_ba/tour/default-parameter-values.md
index 38be16bcc1..f4fc257900 100644
--- a/_ba/tour/default-parameter-values.md
+++ b/_ba/tour/default-parameter-values.md
@@ -13,7 +13,7 @@ prerequisite-knowledge: named-arguments, function syntax
Scala omogućuje davanje podrazumijevanih vrijednosti parametrima koje dozvoljavaju korisniku metode da izostavi te parametre.
-```tut
+```scala mdoc
def log(message: String, level: String = "INFO") = println(s"$level: $message")
log("System starting") // prints INFO: System starting
@@ -22,7 +22,7 @@ log("User not found", "WARNING") // prints WARNING: User not found
Parametar `level` ima podrazumijevanu vrijednost tako da je opcioni. Na zadnjoj liniji, argument `"WARNING"` prebrisava podrazumijevani argument `"INFO"`. Gdje biste koristili overloadane metode u Javi, možete koristiti metode s opcionim parametrima da biste postigli isti efekat. Međutim, ako korisnik izostavi argument, bilo koji sljedeći argumenti moraju biti imenovani.
-```tut
+```scala mdoc
class Point(val x: Double = 0, val y: Double = 0)
val point1 = new Point(y = 1)
@@ -31,7 +31,7 @@ Ovdje moramo reći `y = 1`.
Podrazumijevani parametri u Scali nisu opcioni kada se koriste iz Java koda:
-```tut
+```scala mdoc:reset
// Point.scala
class Point(val x: Double = 0, val y: Double = 0)
```
diff --git a/_ba/tour/extractor-objects.md b/_ba/tour/extractor-objects.md
index 979f2d4250..0d0618aa00 100644
--- a/_ba/tour/extractor-objects.md
+++ b/_ba/tour/extractor-objects.md
@@ -11,15 +11,15 @@ previous-page: regular-expression-patterns
---
Ekstraktor objekat je objekat koji ima `unapply` metodu.
-Dok je `apply` metoda kao konstruktor koji uzima argumente i kreira objekat, `unapply` metoda prima objekat i pokušava vratiti argumente.
+Dok je `apply` metoda kao konstruktor koji uzima argumente i kreira objekat, `unapply` metoda prima objekat i pokušava vratiti argumente.
Ovo se najčešće koristi u podudaranju uzoraka i parcijalnim funkcijama.
-```tut
+```scala mdoc
import scala.util.Random
object CustomerID {
- def apply(name: String) = s"$name--${Random.nextLong}"
+ def apply(name: String) = s"$name--${Random.nextLong()}"
def unapply(customerID: String): Option[String] = {
val name = customerID.split("--").head
@@ -34,14 +34,14 @@ customer1ID match {
}
```
-Metoda `apply` kreira `CustomerID` string od argumenta `name`.
-Metoda `unapply` radi suprotno da dobije `name` nazad.
-Kada pozovemo `CustomerID("Sukyoung")`, to je skraćena sintaksa za `CustomerID.apply("Sukyoung")`.
+Metoda `apply` kreira `CustomerID` string od argumenta `name`.
+Metoda `unapply` radi suprotno da dobije `name` nazad.
+Kada pozovemo `CustomerID("Sukyoung")`, to je skraćena sintaksa za `CustomerID.apply("Sukyoung")`.
Kada pozovemo `case CustomerID(name) => customer1ID`, ustvari pozivamo `unapply` metodu.
Metoda `unapply` se može koristiti i za dodjelu vrijednosti.
-```tut
+```scala mdoc
val customer2ID = CustomerID("Nico")
val CustomerID(name) = customer2ID
println(name) // prints Nico
@@ -49,7 +49,7 @@ println(name) // prints Nico
Ovo je ekvivalentno `val name = CustomerID.unapply(customer2ID).get`. Ako se uzorak ne podudari, baciće se `scala.MatchError` izuzetak:
-```tut:fail
+```scala mdoc:crash
val CustomerID(name2) = "--asdfasdfasdf"
```
diff --git a/_ba/tour/for-comprehensions.md b/_ba/tour/for-comprehensions.md
index efdeb57dc8..7d5d0f9166 100644
--- a/_ba/tour/for-comprehensions.md
+++ b/_ba/tour/for-comprehensions.md
@@ -21,7 +21,7 @@ Komprehensija evaluira tijelo `e` za svako vezivanje varijable generisano od str
Slijedi primjer:
-```tut
+```scala mdoc
case class User(name: String, age: Int)
val userBase = List(User("Travis", 28),
@@ -38,7 +38,7 @@ twentySomethings.foreach(name => println(name)) // prints Travis Dennis
Slijedi malo komplikovaniji primjer koji s dva generatora. Izračunava sve parove brojeva između `0` i `n-1` čija je suma jednaka vrijednosti `v`:
-```tut
+```scala mdoc
def foo(n: Int, v: Int) =
for (i <- 0 until n;
j <- i until n if i + j == v)
@@ -54,5 +54,5 @@ Ovdje je `n == 10` i `v == 10`. U prvoj iteraciji, `i == 0` i `j == 0` tako da `
Bez `if` čuvara, ovo bi ispisalo sljedeće:
```
-(0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (0, 5) (0, 6) (0, 7) (0, 8) (0, 9) (1, 1) ...
+(0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (0, 5) (0, 6) (0, 7) (0, 8) (0, 9) (1, 0) ...
```
diff --git a/_ba/tour/generic-classes.md b/_ba/tour/generic-classes.md
index c86d8f3f8f..6b52e9ccd8 100644
--- a/_ba/tour/generic-classes.md
+++ b/_ba/tour/generic-classes.md
@@ -19,10 +19,11 @@ Vrlo su korisne za implementiranje kolekcija.
Generičke klase primaju tip kao parametar u uglastim zagradama `[]`.
Konvencija je da se koristi slovo `A` kao identifikator tipa, mada se može koristiti bilo koje ime.
-```tut
+```scala mdoc
class Stack[A] {
private var elements: List[A] = Nil
- def push(x: A) { elements = x :: elements }
+ def push(x: A): Unit =
+ elements = x :: elements
def peek: A = elements.head
def pop(): A = {
val currentTop = peek
diff --git a/_ba/tour/higher-order-functions.md b/_ba/tour/higher-order-functions.md
index e7ac3103aa..56f1c1807a 100644
--- a/_ba/tour/higher-order-functions.md
+++ b/_ba/tour/higher-order-functions.md
@@ -14,15 +14,15 @@ Scala dozvoljava definisanje funkcija višeg reda.
To su funkcije koje _primaju druge funkcije kao parametre_, ili čiji je _rezultat funkcija_.
Ovo je funkcija `apply` koja uzima drugu funkciju `f` i vrijednost `v` i primjenjuje funkciju `f` na `v`:
-```tut
+```scala mdoc
def apply(f: Int => String, v: Int) = f(v)
```
_Napomena: metode se automatski pretvaraju u funkcije ako to kontekst zahtijeva._
Ovo je još jedan primjer:
-
-```tut
+
+```scala mdoc
class Decorator(left: String, right: String) {
def layout[A](x: A) = left + x.toString() + right
}
@@ -33,7 +33,7 @@ object FunTest extends App {
println(apply(decorator.layout, 7))
}
```
-
+
Izvršavanjem se dobije izlaz:
```
diff --git a/_ba/tour/implicit-conversions.md b/_ba/tour/implicit-conversions.md
index 090dc03323..5a1ea3b9fa 100644
--- a/_ba/tour/implicit-conversions.md
+++ b/_ba/tour/implicit-conversions.md
@@ -43,11 +43,11 @@ Implicitno importovani objekt `scala.Predef` deklariše nekoliko predefinisanih
Naprimjer, kada se pozivaju Javine metode koje očekuju `java.lang.Integer`, možete proslijediti `scala.Int`.
Možete, zato što `Predef` uključuje slj. implicitnu konverziju:
-```tut
+```scala mdoc
import scala.language.implicitConversions
-implicit def int2Integer(x: Int) =
- java.lang.Integer.valueOf(x)
+implicit def int2Integer(x: Int): Integer =
+ Integer.valueOf(x)
```
Pošto su implicitne konverzije opasne ako se koriste pogrešno, kompajler upozorava kada kompajlira definiciju implicitne konverzije.
diff --git a/_ba/tour/implicit-parameters.md b/_ba/tour/implicit-parameters.md
index 5b50d8f5e9..c39d87d626 100644
--- a/_ba/tour/implicit-parameters.md
+++ b/_ba/tour/implicit-parameters.md
@@ -22,7 +22,7 @@ Argumenti koji se mogu proslijediti kao implicitni parametri spadaju u dvije kat
U sljedećem primjeru definisaćemo metodu `sum` koja izračunava sumu liste elemenata koristeći `add` i `unit` operacije monoida.
Molimo primijetite da implicitne vrijednosti ne mogu biti top-level, već moraju biti članovi templejta.
-```tut
+```scala mdoc
abstract class SemiGroup[A] {
def add(x: A, y: A): A
}
diff --git a/_ba/tour/inner-classes.md b/_ba/tour/inner-classes.md
index 41dd73ed91..ef72aa8929 100644
--- a/_ba/tour/inner-classes.md
+++ b/_ba/tour/inner-classes.md
@@ -17,11 +17,11 @@ Pretpostavimo da želimo da nas kompejler spriječi da pomiješamo koji čvorovi
Radi ilustracije razlike, prikazaćemo implementaciju klase grafa:
-```tut
+```scala mdoc
class Graph {
class Node {
var connectedNodes: List[Node] = Nil
- def connectTo(node: Node) {
+ def connectTo(node: Node): Unit = {
if (!connectedNodes.exists(node.equals)) {
connectedNodes = node :: connectedNodes
}
@@ -35,11 +35,11 @@ class Graph {
}
}
```
-
+
U našem programu, grafovi su predstavljeni listom čvorova (`List[Node]`).
Svaki čvor ima listu drugih čvorova s kojima je povezan (`connectedNodes`). Klasa `Node` je _path-dependent tip_ jer je ugniježdena u klasi `Graph`. Stoga, svi čvorovi u `connectedNodes` moraju biti kreirani koristeći `newNode` iz iste instance klase `Graph`.
-```tut
+```scala mdoc
val graph1: Graph = new Graph
val node1: graph1.Node = graph1.newNode
val node2: graph1.Node = graph1.newNode
@@ -47,14 +47,14 @@ val node3: graph1.Node = graph1.newNode
node1.connectTo(node2)
node3.connectTo(node1)
```
-
+
Eksplicitno smo deklarisali tip `node1`, `node2`, i `node3` kao `graph1.Node` zbog jasnosti ali ga je kompajler mogao sam zaključiti. Pošto kada pozivamo `graph1.newNode` koja poziva `new Node`, metoda koristi instancu `Node` specifičnu instanci `graph1`.
Da imamo dva grafa, sistem tipova Scale ne dozvoljava miješanje čvorova definisanih u različitim grafovima,
jer čvorovi različitih grafova imaju različit tip.
Ovo je primjer netačnog programa:
-
-```
+
+```scala mdoc:fail
val graph1: Graph = new Graph
val node1: graph1.Node = graph1.newNode
val node2: graph1.Node = graph1.newNode
@@ -69,12 +69,12 @@ U Javi bi zadnja linija prethodnog primjera bila tačna.
Za čvorove oba grafa, Java bi dodijelila isti tip `Graph.Node`; npr. `Node` bi imala prefiks klase `Graph`.
U Scali takav tip je također moguće izraziti, piše se kao `Graph#Node`.
Ako želimo povezati čvorove različitih grafova, moramo promijeniti definiciju naše inicijalne implementacije grafa:
-
-```tut
+
+```scala mdoc:nest
class Graph {
class Node {
var connectedNodes: List[Graph#Node] = Nil
- def connectTo(node: Graph#Node) {
+ def connectTo(node: Graph#Node): Unit = {
if (!connectedNodes.exists(node.equals)) {
connectedNodes = node :: connectedNodes
}
@@ -88,6 +88,6 @@ class Graph {
}
}
```
-
+
> Primijetite da ovaj program ne dozvoljava da dodamo čvor u dva različita grafa.
Ako bi htjeli ukloniti i ovo ograničenje, moramo promijeniti tipski parametar `nodes` u `Graph#Node`.
diff --git a/_ba/tour/lower-type-bounds.md b/_ba/tour/lower-type-bounds.md
index 8261a2e77c..85dd54a401 100644
--- a/_ba/tour/lower-type-bounds.md
+++ b/_ba/tour/lower-type-bounds.md
@@ -17,7 +17,7 @@ Izraz `B >: A` izražava tipski parametar `B` ili apstraktni tip `B` koji je nad
Kroz sljedeći primjer vidjećemo zašto je ovo korisno:
-```tut:fail
+```scala mdoc:fail
trait Node[+B] {
def prepend(elem: B): Node[B]
}
@@ -43,7 +43,7 @@ Ovo ne radi jer su funkcije *kontra*varijantne u svojim tipovima parametara i *k
Da bismo popravili ovo, moramo zamijeniti varijansu tipskog parametra `elem` u `prepend`.
Ovo radimo uvođenjem novog tipskog parametra `U` koji ima `B` kao svoju donju granicu tipa.
-```tut
+```scala mdoc
trait Node[+B] {
def prepend[U >: B](elem: U): Node[U]
}
@@ -60,7 +60,7 @@ case class Nil[+B]() extends Node[B] {
```
Sada možemo uraditi sljedeće:
-```tut
+```scala mdoc
trait Bird
case class AfricanSwallow() extends Bird
case class EuropeanSwallow() extends Bird
diff --git a/_ba/tour/mixin-class-composition.md b/_ba/tour/mixin-class-composition.md
index 66ad5f623e..a8216abfb6 100644
--- a/_ba/tour/mixin-class-composition.md
+++ b/_ba/tour/mixin-class-composition.md
@@ -13,7 +13,7 @@ prerequisite-knowledge: inheritance, traits, abstract-classes, unified-types
Mixini su trejtovi koji se koriste za kompoziciju klase.
-```tut
+```scala mdoc
abstract class A {
val message: String
}
@@ -29,23 +29,23 @@ val d = new D
d.message // I'm an instance of class B
d.loudMessage // I'M AN INSTANCE OF CLASS B
```
-Klasa `D` je nadklasa od `B` i mixina `C`.
+Klasa `D` je nadklasa od `B` i mixina `C`.
Klase mogu imati samo jednu nadklasu alid mogu imati više mixina (koristeći ključne riječi `extends` i `with` respektivno). Mixini i nadklasa mogu imati isti nadtip.
Pogledajmo sada zanimljiviji primjer počevši od apstraktne klase:
-
-```tut
+
+```scala mdoc
abstract class AbsIterator {
type T
def hasNext: Boolean
def next(): T
}
```
-
+
Klasa ima apstraktni tip `T` i standardne metode iteratora.
Dalje, implementiraćemo konkretnu klasu (svi apstraktni članovi `T`, `hasNext`, i `next` imaju implementacije):
-```tut
+```scala mdoc
class StringIterator(s: String) extends AbsIterator {
type T = Char
private var i = 0
@@ -59,14 +59,14 @@ class StringIterator(s: String) extends AbsIterator {
```
`StringIterator` prima `String` i može se koristiti za iteraciju nad `String`om (npr. da vidimo da li sadrži određeni karakter).
-
+
trait RichIterator extends AbsIterator {
- def foreach(f: T => Unit) { while (hasNext) f(next()) }
+ def foreach(f: T => Unit): Unit = { while (hasNext) f(next()) }
}
Kreirajmo sada trejt koji također nasljeđuje `AbsIterator`.
-```tut
+```scala mdoc
trait RichIterator extends AbsIterator {
def foreach(f: T => Unit): Unit = while (hasNext) f(next())
}
@@ -74,16 +74,16 @@ trait RichIterator extends AbsIterator {
Pošto je `RichIterator` trejt, on ne mora implementirati apstraktne članove `AbsIterator`a.
-Željeli bismo iskombinirati funkcionalnosti `StringIterator`a i `RichIterator`a u jednoj klasi.
+Željeli bismo iskombinirati funkcionalnosti `StringIterator`a i `RichIterator`a u jednoj klasi.
-```tut
+```scala mdoc
object StringIteratorTest extends App {
class Iter extends StringIterator("Scala") with RichIterator
val iter = new Iter
iter foreach println
}
```
-
+
Nova klasa `Iter` ima `StringIterator` kao nadklasu i `RichIterator` kao mixin.
S jednostrukim nasljeđivanjem ne bismo mogli postići ovaj nivo fleksibilnosti.
diff --git a/_ba/tour/multiple-parameter-lists.md b/_ba/tour/multiple-parameter-lists.md
index ed9f22c1b1..68230aa12b 100644
--- a/_ba/tour/multiple-parameter-lists.md
+++ b/_ba/tour/multiple-parameter-lists.md
@@ -16,7 +16,7 @@ onda će to vratiti funkciju koja prima preostale liste parametara kao argumente
Primjer:
-```tut
+```scala mdoc
object CurryTest extends App {
def filter(xs: List[Int], p: Int => Boolean): List[Int] =
diff --git a/_ba/tour/named-arguments.md b/_ba/tour/named-arguments.md
index abe434c3b4..6656b02da2 100644
--- a/_ba/tour/named-arguments.md
+++ b/_ba/tour/named-arguments.md
@@ -12,7 +12,7 @@ prerequisite-knowledge: function-syntax
Kada se pozivaju metode, možete koristiti imena varijabli eksplicitno pri pozivu:
-```tut
+```scala mdoc
def printName(first: String, last: String): Unit = {
println(first + " " + last)
}
diff --git a/_ba/tour/nested-functions.md b/_ba/tour/nested-functions.md
index 7c4adc75b2..1a00eaba59 100644
--- a/_ba/tour/nested-functions.md
+++ b/_ba/tour/nested-functions.md
@@ -13,7 +13,7 @@ previous-page: higher-order-functions
U Scali je moguće ugnježdavati definicije metode.
Sljedeći objekt sadrži metodu `factorial` za računanje faktorijela datog broja:
-```tut
+```scala mdoc
def factorial(x: Int): Int = {
def fact(x: Int, accumulator: Int): Int = {
if (x <= 1) accumulator
diff --git a/_ba/tour/operators.md b/_ba/tour/operators.md
index 259fdca8fe..f1e8f3da07 100644
--- a/_ba/tour/operators.md
+++ b/_ba/tour/operators.md
@@ -25,7 +25,7 @@ Međutim, lakše je čitati kada se napiše kao infiksni operator:
## Definisanje i korištenje operatora
Možete koristiti bilo koji legalni identifikator kao operator.
To uključuje i imena kao `add` ili simbole kao `+`.
-```tut
+```scala mdoc
case class Vec(x: Double, y: Double) {
def +(that: Vec) = Vec(this.x + that.x, this.y + that.y)
}
@@ -42,7 +42,7 @@ Koristeći zagrade, možete pisati kompleksne izraze s čitljivom sintaksom.
Slijedi definicija klase `MyBool` koja definiše tri metode `and`, `or`, i `negate`.
-```tut
+```scala mdoc
case class MyBool(x: Boolean) {
def and(that: MyBool): MyBool = if (x) that else this
def or(that: MyBool): MyBool = if (x) this else that
@@ -52,7 +52,7 @@ case class MyBool(x: Boolean) {
Sada je moguće koristiti `and` i `or` kao infiksne operatore:
-```tut
+```scala mdoc
def not(x: MyBool) = x.negate
def xor(x: MyBool, y: MyBool) = (x or y) and not(x and y)
```
@@ -71,7 +71,7 @@ Kada izraz koristi više operatora, operatori se primjenjuju bazirano na priorit
&
^
|
-(sva slova)
+(sva slova, $, _)
```
Ovo se odnosi na metode koje definišete. Npr, sljedeći izraz:
```
diff --git a/_ba/tour/pattern-matching.md b/_ba/tour/pattern-matching.md
index 6c902033a2..e303e05d63 100644
--- a/_ba/tour/pattern-matching.md
+++ b/_ba/tour/pattern-matching.md
@@ -16,7 +16,7 @@ Podudaranje uzoraka je mehanizam za provjeranje da li vrijednost odgovara uzroku
## Sintaksa
Izraz za podudaranje ima vrijednost, `match` ključnu riječ, i bar jednu `case` klauzu.
-```tut
+```scala mdoc
import scala.util.Random
val x: Int = Random.nextInt(10)
@@ -34,7 +34,7 @@ Zadnji slučaj, `_`, je "uhvati sve" slučaj za brojeve veće od 2.
Slučajevi se još zovu i _alternative_.
Izrazi za podudaranje imaju vrijednost.
-```tut
+```scala mdoc
def matchTest(x: Int): String = x match {
case 1 => "one"
case 2 => "two"
@@ -50,7 +50,7 @@ Stoga, metoda `matchTest` vraća `String`.
Case klase su posebno korisne za podudaranje uzoraka.
-```tut
+```scala mdoc
abstract class Notification
case class Email(sender: String, title: String, body: String) extends Notification
@@ -118,7 +118,7 @@ U `case Email(email, _, _) if importantPeopleInfo.contains(email)`, uzorak se po
## Podudaranje samo tipa
Možete podudarati samo tip ovako:
-```tut
+```scala mdoc
abstract class Device
case class Phone(model: String) extends Device {
def screenOff = "Turning screen off"
@@ -140,7 +140,7 @@ Konvencija je da se koristi prvo slovo tipa kao identifikator (`p` i `c` ovdje).
Trejtovi i klase mogu biti `sealed` što znači da svi podtipovi moraju biti reklarisani u istom fajlu.
Ovo osigurava da su svi podtipovi poznati.
-```tut
+```scala mdoc
sealed abstract class Furniture
case class Couch() extends Furniture
case class Chair() extends Furniture
diff --git a/_ba/tour/polymorphic-methods.md b/_ba/tour/polymorphic-methods.md
index 2fcb672428..a5ad6e27f4 100644
--- a/_ba/tour/polymorphic-methods.md
+++ b/_ba/tour/polymorphic-methods.md
@@ -18,7 +18,7 @@ Vrijednosni parameteri ("obični") su ograđeni parom zagrada, dok su tipski par
Slijedi primjer:
-```tut
+```scala mdoc
def listOfDuplicates[A](x: A, length: Int): List[A] = {
if (length < 1)
Nil
diff --git a/_ba/tour/regular-expression-patterns.md b/_ba/tour/regular-expression-patterns.md
index 6936f74013..558b039a24 100644
--- a/_ba/tour/regular-expression-patterns.md
+++ b/_ba/tour/regular-expression-patterns.md
@@ -14,7 +14,7 @@ previous-page: singleton-objects
Regularni izrazi su stringovi koji se mogu koristiti za traženje uzoraka u podacima.
Bilo koji string se može pretvoriti u regularni izraz pozivom `.r` metode.
-```tut
+```scala mdoc
import scala.util.matching.Regex
val numberPattern: Regex = "[0-9]".r
@@ -30,7 +30,7 @@ U gornjem primjeru, `numberPattern` je `Regex`
Također, možete tražiti grupe regularnih izraza koristeći zagrade.
-```tut
+```scala mdoc
import scala.util.matching.Regex
val keyValPattern: Regex = "([0-9a-zA-Z-#() ]+): ([0-9a-zA-Z-#() ]+)".r
diff --git a/_ba/tour/self-types.md b/_ba/tour/self-types.md
index da47a626bc..9b0ccd95a2 100644
--- a/_ba/tour/self-types.md
+++ b/_ba/tour/self-types.md
@@ -17,7 +17,7 @@ Self-tip je način da se suzi tip `this` ili drugi identifikator koji je alijas
Sintaksa izgleda kao obična funkcija ali znači nešto sasvim drugačije.
Da bi koristili self-tip u trejtu, napišite identifikator, tip drugog trejta za umiksavanje, i `=>` (tj. `someIdentifier: SomeOtherTrait =>`).
-```tut
+```scala mdoc
trait User {
def username: String
}
diff --git a/_ba/tour/singleton-objects.md b/_ba/tour/singleton-objects.md
index 7c74f5318e..7f8ac84ba4 100644
--- a/_ba/tour/singleton-objects.md
+++ b/_ba/tour/singleton-objects.md
@@ -44,7 +44,7 @@ ako krug s velikim “C” ili “O” ima savijenu ivicu (kao papir), možete k
Klasa i njen kompanjon objekt, ako ga ima, moraju biti definisani u istom izvornom fajlu:
-```tut
+```scala mdoc
class IntPair(val x: Int, val y: Int)
object IntPair {
diff --git a/_ba/tour/traits.md b/_ba/tour/traits.md
index 6d0356cda0..8f7a82cc9e 100644
--- a/_ba/tour/traits.md
+++ b/_ba/tour/traits.md
@@ -18,12 +18,12 @@ Klase i objekti mogu naslijediti trejtove ali trejtovi ne mogu biti instancirani
## Definisanje trejta
Minimalni trejt je samo ključna riječ `trait` i identifikator:
-```tut
+```scala mdoc
trait HairColor
```
Trejtovi su vrlo korisni s generičkim tipovima i apstraktnim metodama.
-```tut
+```scala mdoc
trait Iterator[A] {
def hasNext: Boolean
def next(): A
@@ -34,7 +34,7 @@ Nasljeđivanje `trait Iterator[A]` traži tip `A` i implementacije metoda `hasNe
## Korištenje trejtova
Koristite `extends` za nasljeđivanje trejta. Zatim implementirajte njegove apstraktne članove koristeći `override` ključnu riječ:
-```tut
+```scala mdoc:nest
trait Iterator[A] {
def hasNext: Boolean
def next(): A
@@ -62,7 +62,7 @@ Ona nasljeđuje `Iterator[Int]` što znači da `next` mora vraćati `Int`.
## Podtipovi
Podtipovi trejtova mogu se koristiti gdje se trejt traži.
-```tut
+```scala mdoc
import scala.collection.mutable.ArrayBuffer
trait Pet {
diff --git a/_ba/tour/tuples.md b/_ba/tour/tuples.md
index 34bceaa3d1..99f49e7247 100644
--- a/_ba/tour/tuples.md
+++ b/_ba/tour/tuples.md
@@ -10,4 +10,4 @@ previous-page: traits
---
(this section of the tour has not been translated yet. pull request
-with translation welcome!)
\ No newline at end of file
+with translation welcome!)
diff --git a/_ba/tour/type-inference.md b/_ba/tour/type-inference.md
index 3ff6ab6ce6..d3b7eb1867 100644
--- a/_ba/tour/type-inference.md
+++ b/_ba/tour/type-inference.md
@@ -16,7 +16,7 @@ Povratni tipovi metoda također mogu biti izostavljeni jer oni odgovaraju tipu t
Slijedi jedan primjer:
-```tut
+```scala mdoc
object InferenceTest1 extends App {
val x = 1 + 2 * 3 // the type of x is Int
val y = x.toString() // the type of y is String
@@ -27,7 +27,7 @@ object InferenceTest1 extends App {
Za rekurzivne metode, kompajler nije u mogućnosti da zaključi tip rezultata.
Ovo je program koji se ne može kompajlirati iz ovog razloga:
-```tut:fail
+```scala mdoc:fail
object InferenceTest2 {
def fac(n: Int) = if (n == 0) 1 else n * fac(n - 1)
}
@@ -58,7 +58,7 @@ val y: Int = id[Int](1)
U nekim situacijama može biti vrlo opasno osloniti se na Scalin mehanizam zaključivanja tipova:
-```tut:fail
+```scala mdoc:fail
object InferenceTest4 {
var obj = null
obj = new Object()
diff --git a/_ba/tour/unified-types.md b/_ba/tour/unified-types.md
index 7f9787e5b9..92c1e2a61e 100644
--- a/_ba/tour/unified-types.md
+++ b/_ba/tour/unified-types.md
@@ -18,14 +18,14 @@ Dijagram ispod prikazuje hijerarhiju Scala klasa.
## Hijerarhija tipova u Scali ##
-[`Any`](https://www.scala-lang.org/api/2.12.1/scala/Any.html) je nadtip svih tipova, zove se još i vrh-tip.
+[`Any`](https://www.scala-lang.org/api/2.12.1/scala/Any.html) je nadtip svih tipova, zove se još i vrh-tip.
Definiše određene univerzalne metode kao što su `equals`, `hashCode` i `toString`.
`Any` ima dvije direktne podklase, `AnyVal` i `AnyRef`.
-`AnyVal` predstavlja vrijednosne tipove. Postoji devet predefinisanih vrijednosnih tipova i oni ne mogu biti `null`:
+`AnyVal` predstavlja vrijednosne tipove. Postoji devet predefinisanih vrijednosnih tipova i oni ne mogu biti `null`:
`Double`, `Float`, `Long`, `Int`, `Short`, `Byte`, `Char`, `Unit` i `Boolean`.
-`Unit` je vrijednosni tip koji ne nosi značajnu informaciju. Postoji tačno jedna instanca tipa `Unit` koja se piše `()`.
+`Unit` je vrijednosni tip koji ne nosi značajnu informaciju. Postoji tačno jedna instanca tipa `Unit` koja se piše `()`.
Sve funkcije moraju vratiti nešto tako da je `Unit` ponekad koristan povratni tip.
`AnyRef` predstavlja referencne tipove. Svi nevrijednosni tipovi definišu se kao referencni.
@@ -34,7 +34,7 @@ Ako se Scala koristi u kontekstu JRE, onda `AnyRef` odgovara klasi `java.lang.Ob
Slijedi primjer koji demonstrira da su stringovi, integeri, karakteri, booleani i funkcije svi objekti kao bilo koji drugi:
-```tut
+```scala mdoc
val list: List[Any] = List(
"a string",
732, // an integer
@@ -64,9 +64,9 @@ Vrijednosni tipovi mogu biti kastovani na sljedeći način:
Npr:
-```tut
+```scala mdoc
val x: Long = 987654321
-val y: Float = x // 9.8765434E8 (određena doza preciznosti se gubi ovdje)
+val y: Float = x.toFloat // 9.8765434E8 (određena doza preciznosti se gubi ovdje)
val face: Char = '☺'
val number: Int = face // 9786
@@ -76,17 +76,17 @@ Kastovanje je jednosmjerno. Ovo se ne kompajlira:
```
val x: Long = 987654321
-val y: Float = x // 9.8765434E8
+val y: Float = x.toFloat // 9.8765434E8
val z: Long = y // Does not conform
```
Također možete kastovati i referencni tip u podtip. Ovo će biti pokriveno kasnije.
## Nothing i Null
-`Nothing` je podtip svih tipova, također se zove i donji tip (en. bottom type). Ne postoji vrijednost koja ima tip `Nothing`.
+`Nothing` je podtip svih tipova, također se zove i donji tip (en. bottom type). Ne postoji vrijednost koja ima tip `Nothing`.
Česta upotreba ovog tipa je signalizacija neterminacije kao što je bacanje izuzetka, izlaz iz programa, ili beskonačna petlja (tj. tip izraza koji se ne izračunava u vrijednost, ili metoda koja se ne završava normalno).
-`Null` je podtip svih referencnih tipova (tj. bilo kog podtipa `AnyRef`).
-Ima jednu vrijednost koja se piše literalom `null`.
-`Null` se uglavnom koristi radi interoperabilnosti s ostalim JVM jezicima i skoro nikad se ne koristi u Scala kodu.
+`Null` je podtip svih referencnih tipova (tj. bilo kog podtipa `AnyRef`).
+Ima jednu vrijednost koja se piše literalom `null`.
+`Null` se uglavnom koristi radi interoperabilnosti s ostalim JVM jezicima i skoro nikad se ne koristi u Scala kodu.
Alternative za `null` obradićemo kasnije.
diff --git a/_ba/tour/upper-type-bounds.md b/_ba/tour/upper-type-bounds.md
index ce4f4e198e..e91d904d5d 100644
--- a/_ba/tour/upper-type-bounds.md
+++ b/_ba/tour/upper-type-bounds.md
@@ -15,7 +15,7 @@ Takve granice tipa ograničavaju konkretne vrijednosti tipskih varijabli i ponek
_Gornja granica tipa_ `T <: A` kaže da se tipska varijabla `T` odnosi na podtip tipa `A`.
Slijedi primjer koji demonstrira gornju granicu tipa za tipski parametar klase `PetContainer`:
-```tut
+```scala mdoc
abstract class Animal {
def name: String
}
@@ -42,7 +42,7 @@ val dogContainer = new PetContainer[Dog](new Dog)
val catContainer = new PetContainer[Cat](new Cat)
```
-```tut:fail
+```scala mdoc:fail
val lionContainer = new PetContainer[Lion](new Lion) // this would not compile
```
Klasa `PetContainer` prima tipski parametar `P` koji mora biti podtip od `Pet`.
diff --git a/_ba/tour/variances.md b/_ba/tour/variances.md
index 0540982844..2920e00dac 100644
--- a/_ba/tour/variances.md
+++ b/_ba/tour/variances.md
@@ -14,7 +14,7 @@ Varijansa je korelacija podtipskih veza kompleksnih tipova i podtipskih veza nji
Scala podržava anotacije varijanse tipskih parametara [generičkih klasa](generic-classes.html), dozvoljavajući im da budu kovarijantni, kontravarijantni, ili invarijantni ako se anotacije ne koriste.
Korištenje varijanse u sistemu tipova dozvoljava pravljenje intuitivnijih veza među kompleksnim tipovima, a nedostatak varijanse može ograničiti ponovno iskorištenje klasne apstrakcije.
-```tut
+```scala mdoc
class Foo[+A] // kovarijantna klasa
class Bar[-A] // kontravarijantna klasa
class Baz[A] // invarijantna klasa
@@ -28,7 +28,7 @@ Ovo dozvoljava pravljenje vrlo intuitivnih podtipskih veza koristeći generiku.
Razmotrite sljedeću strukturu klasa:
-```tut
+```scala mdoc
abstract class Animal {
def name: String
}
@@ -44,7 +44,7 @@ Intuitivno, ima smisla da su lista mačaka i lista pasa također liste životinj
U sljedećem primjeru, metoda `printAnimalNames` prima listu životinja kao argument i ispisuje njihova imena, svako na idućoj liniji.
Da `List[A]` nije kovarijantna, zadnja dva poziva metode se ne bi kompajlirali, što bi značajno ograničilo korisnost `printAnimalNames` metode.
-```tut
+```scala mdoc
object CovarianceTest extends App {
def printAnimalNames(animals: List[Animal]): Unit = {
animals.foreach { animal =>
@@ -73,7 +73,7 @@ To jest, za neku `class Writer[-A]`, kontravarijantno `A` znači da za dva tipa
Razmotrimo `Cat`, `Dog`, i `Animal` klase u sljedećem primjeru:
-```tut
+```scala mdoc
abstract class Printer[-A] {
def print(value: A): Unit
}
@@ -81,7 +81,7 @@ abstract class Printer[-A] {
`Printer[A]` je jednostavna klasa koja zna ispisati neki tip `A`. Definišimo neke podklase za specifične tipove:
-```tut
+```scala mdoc
class AnimalPrinter extends Printer[Animal] {
def print(animal: Animal): Unit =
println("The animal's name is: " + animal.name)
@@ -99,7 +99,7 @@ Inverzna veza ne vrijedi, jer `Printer[Cat]` ne zna kako da ispiše bilo koju `A
Stoga, terbali bismo moći zamijeniti `Printer[Animal]` za `Printer[Cat]`, ako želimo, i praveći `Printer[A]` kontravarijantnim nam to dozvoljava.
-```tut
+```scala mdoc
object ContravarianceTest extends App {
val myCat: Cat = Cat("Boots")
@@ -129,7 +129,7 @@ Ovo znač da nisu ni kovarijantne ni kontravarijantne.
U kontekstu sljedećeg primjera, `Container` klasa je invarijantna.
`Container[Cat]` _nije_ `Container[Animal]`, niti obrnuto.
-```tut
+```scala mdoc
class Container[A](value: A) {
private var _value: A = value
def getValue: A = _value
@@ -162,7 +162,7 @@ Za ovaj primjer koristićemo literal notaciju `A => B` za predstavljanje `Functi
Pretpostavimo da imamo sličnu hijerarhiju klasa `Cat`, `Dog`, `Animal` otprije, plus sljedeće:
-```tut
+```scala mdoc
class SmallAnimal
class Mouse extends SmallAnimal
```
diff --git a/_books/1-programming-in-scala-4th.md b/_books/1-programming-in-scala-5th.md
similarity index 52%
rename from _books/1-programming-in-scala-4th.md
rename to _books/1-programming-in-scala-5th.md
index cb43ef35f1..826e5361df 100644
--- a/_books/1-programming-in-scala-4th.md
+++ b/_books/1-programming-in-scala-5th.md
@@ -1,12 +1,11 @@
---
-title: "Programming in Scala, 4th ed"
-link: https://booksites.artima.com/programming_in_scala_4ed
-image: /resources/img/books/ProgrammingInScala.gif
-status: Updated for Scala 2.13
+title: "Programming in Scala, 5th ed"
+link: https://www.artima.com/shop/programming_in_scala_5ed
+image: /resources/img/books/ProgrammingInScala.png
+status: Updated for Scala 3
authors: ["Martin Odersky", "Lex Spoon", "Bill Venners"]
-publisher:
+publisher: Artima
+publisherLink: https://www.artima.com/books
---
-(First edition [available for free online reading](https://www.artima.com/pins1ed/))
-
-This book is co-authored by the language's designer, Martin Odersky. It provides depth and clarity on the diverse features of the language. The book provides both an authoritative reference for Scala and a systematic tutorial covering all the features in the language. Once you are familiar with the basics of Scala you will appreciate having this source of invaluable examples and precise explanations of Scala on hand. The book is available from [Artima](https://booksites.artima.com/programming_in_scala_4ed). Award winning book - [Jolt Productivity award](https://www.drdobbs.com/joltawards/232601431) for Technical Books.
+This book is co-authored by the language's designer, Martin Odersky. It provides depth and clarity on the diverse features of the language. The book provides both an authoritative reference for Scala and a systematic tutorial covering all the features in the language. Once you are familiar with the basics of Scala you will appreciate having this source of invaluable examples and precise explanations of Scala on hand. The book is available from [Artima](https://www.artima.com/shop/programming_in_scala_5ed). Award winning book - [Jolt Productivity award](https://www.drdobbs.com/joltawards/232601431) for Technical Books.
diff --git a/_books/2-programming-scala.md b/_books/2-programming-scala.md
index 27a1e9ce61..8fc729169f 100644
--- a/_books/2-programming-scala.md
+++ b/_books/2-programming-scala.md
@@ -1,11 +1,11 @@
---
title: "Programming Scala"
-link: https://shop.oreilly.com/product/0636920033073.do
+link: http://programming-scala.com
image: /resources/img/books/ProgrammingScala-final-border.gif
-status: Updated for Scala 2.12
-authors: ["Alex Payne", "Dean Wampler"]
+status: Updated for Scala 3
+authors: ["Dean Wampler"]
publisher: O’Reilly
publisherLink: https://www.oreilly.com/
---
-Both are industry experts, Alex Payne being the lead API programmer at Twitter, a social networking service based on Scala. O’Reilly, the publisher, writes: "Learn how to be more productive with Scala, a new multi-paradigm language for the Java Virtual Machine (JVM) that integrates features of both object-oriented and functional programming. With this book, you'll discover why Scala is ideal for highly scalable, component-based applications that support concurrency and distribution. You'll also learn how to leverage the wealth of Java class libraries to meet the practical needs of enterprise and Internet projects more easily."
+Dean is a well-known member of the Scala community, using Scala recently for streaming data systems at Lightbend and now at Domino Data Lab. This edition covers the new features of Scala 3, with comparisons to Scala 2, both to explain why the changes were made and how they improve Scala, and also to enable developers using mixed Scala 2 and 3 code bases to work effectively. The book is aimed at professional programmers who want a comprehensive, in-depth, yet pragmatic tour of Scala and best practices for using it.
diff --git a/_books/3-scala-for-the-impatient.md b/_books/3-scala-for-the-impatient.md
new file mode 100644
index 0000000000..72c7c01f6d
--- /dev/null
+++ b/_books/3-scala-for-the-impatient.md
@@ -0,0 +1,23 @@
+---
+title: "Scala for the Impatient"
+link: https://horstmann.com/scala/
+image: /resources/img/books/scala_for_the_impatient.jpg
+status: Updated for Scala 3
+authors: ["Cay Horstmann"]
+publisher: Addison-Wesley Professional
+publisherLink: https://www.oreilly.com/publisher/addison-wesley-professional/
+---
+
+What you get:
+
+* Up to date coverage of Scala 3
+* A rapid introduction to Scala for programmers who are competent in another language such as Java, C#, Python, JavaScript, or C++
+* Blog-length chunks of information that you can digest quickly
+* An organization that you'll find useful as a quick reference
+
+What you don't get:
+
+* An introduction into programming or object-oriented design
+* Religion about the superiority of one paradigm or another
+* Cute or academic examples
+* Mind-numbing details about syntax minutiae
diff --git a/_books/3-hands-on-scala.md b/_books/4-hands-on-scala.md
similarity index 100%
rename from _books/3-hands-on-scala.md
rename to _books/4-hands-on-scala.md
diff --git a/_books/5-get-programming.md b/_books/5-get-programming.md
new file mode 100644
index 0000000000..5d6803860d
--- /dev/null
+++ b/_books/5-get-programming.md
@@ -0,0 +1,11 @@
+---
+title: "Get Programming with Scala"
+link: https://www.manning.com/books/get-programming-with-scala
+image: /resources/img/books/get-programming-book.png
+status: Covers Scala 2 and 3
+authors: ["Daniela Sfregola"]
+publisher: Manning
+publisherLink: https://www.manning.com/
+---
+
+"The perfect starting point for your journey into Scala and functional programming. Scala is a multi-style programming language for the JVM that supports both object-oriented and functional programming. Master Scala, and you'll be well-equipped to match your programming approach to the type of problem you're dealing with. Packed with examples and exercises, _Get Programming with Scala_ is the perfect starting point for developers with some OO knowledge who want to learn Scala and pick up a few FP skills along the way."
diff --git a/_books/4-creative-scala.md b/_books/6-creative-scala.md
similarity index 100%
rename from _books/4-creative-scala.md
rename to _books/6-creative-scala.md
diff --git a/_books/6-scala-puzzlers.bd b/_books/6-scala-puzzlers.bd
deleted file mode 100644
index a60753e483..0000000000
--- a/_books/6-scala-puzzlers.bd
+++ /dev/null
@@ -1,11 +0,0 @@
----
-title: "Scala Puzzlers"
-link: https://www.artima.com/shop/scala_puzzlers
-image: /resources/img/books/scala-puzzlers-book.jpg
-status: Available now
-authors: ["Andrew Phillips", "Nermin Šerifović"]
-publisher: Artima Press
-publisherLink: https://www.artima.com/index.jsp
----
-
-"Getting code to do what we want it to do is perhaps the essence of our purpose as developers. So there are few things more intriguing or important than code that we think we understand, but that behaves rather contrary to our expectations. Scala Puzzlers is a collection of such examples in Scala. It is not only an entertaining and instructive way of understanding this highly expressive language better. It will also help you recognize many counter-intuitive traps and pitfalls and prevent them from inflicting further production bug hunt stress on Scala developers."
diff --git a/_books/5-functional-programming-in-scala.md b/_books/7-functional-programming-in-scala.md
similarity index 72%
rename from _books/5-functional-programming-in-scala.md
rename to _books/7-functional-programming-in-scala.md
index e90d36e92d..0b878c6b15 100644
--- a/_books/5-functional-programming-in-scala.md
+++ b/_books/7-functional-programming-in-scala.md
@@ -1,11 +1,13 @@
---
title: "Functional Programming in Scala"
-link: https://www.manning.com/books/functional-programming-in-scala
-image: /resources/img/books/FPiS_93x116.png
-status: Available now
-authors: ["Paul Chiusano", "Rúnar Bjarnason"]
+link: https://www.manning.com/books/functional-programming-in-scala-second-edition
+image: /resources/img/books/FPiS_93x116.jpg
+status: Updated for Scala 3
+authors: ["Michael Pilquist", "Paul Chiusano", "Rúnar Bjarnason"]
publisher: Manning
publisherLink: https://www.manning.com/
---
-"Functional programming (FP) is a style of software development emphasizing functions that don't depend on program state... Functional Programming in Scala is a serious tutorial for programmers looking to learn FP and apply it to the everyday business of coding. The book guides readers from basic techniques to advanced topics in a logical, concise, and clear progression. In it, you'll find concrete examples and exercises that open up the world of functional programming."
\ No newline at end of file
+"Functional programming (FP) is a style of software development emphasizing functions that don't depend on program state... Functional Programming in Scala is a serious tutorial for programmers looking to learn FP and apply it to the everyday business of coding. The book guides readers from basic techniques to advanced topics in a logical, concise, and clear progression. In it, you'll find concrete examples and exercises that open up the world of functional programming."
+
+Forewords by Daniel Spiewak and Martin Odersky.
diff --git a/_cheatsheets/index.md b/_cheatsheets/index.md
index 2b4cc489ec..679e4ed242 100644
--- a/_cheatsheets/index.md
+++ b/_cheatsheets/index.md
@@ -7,7 +7,7 @@ partof: cheatsheet
by: Brendan O'Connor
about: Thanks to Brendan O'Connor, this cheatsheet aims to be a quick reference of Scala syntactic constructions. Licensed by Brendan O'Connor under a CC-BY-SA 3.0 license.
-languages: [ba, fr, ja, pl, pt-br, zh-cn, th, ru]
+languages: [ba, fr, ja, pl, pt-br, zh-cn, th, ru, uk]
---
@@ -220,7 +220,6 @@ languages: [ba, fr, ja, pl, pt-br, zh-cn, th, ru]
import scala.util.control.Breaks._
-
breakable {
for (x <- xs) {
if (Math.random < 0.1)
@@ -332,7 +331,7 @@ breakable {
var y = x
val readonly = 5
private var secret = 1
- def this = this(42)
+ def this() = this(42)
}
Constructor is class body. Declare a public member. Declare a gettable but not settable member. Declare a private member. Alternative constructor.
diff --git a/_config.yml b/_config.yml
index 6ab7b65d5c..e1ed8d682e 100644
--- a/_config.yml
+++ b/_config.yml
@@ -15,8 +15,9 @@ keywords:
- Document
- Guide
-scala-version: 2.13.3
-scala-212-version: 2.12.12
+scala-version: 2.13.16
+scala-212-version: 2.12.20
+scala-3-version: 3.7.1
collections:
style:
@@ -40,9 +41,6 @@ collections:
permalink: /:collection/:path.html
books:
output: false
- getting-started:
- output: true
- permalink: /:collection/:path.html
ja: # Japanese translations
output: true
permalink: /:collection/:path.html
@@ -82,6 +80,9 @@ collections:
th: # Thai translations
output: true
permalink: /:collection/:path.html
+ uk: # Ukrainian translations
+ output: true
+ permalink: /:collection/:path.html
defaults:
-
@@ -90,11 +91,126 @@ defaults:
type: "tour"
values:
overview-name: "Tour of Scala"
+ -
+ scope:
+ path: "_overviews/getting-started"
+ values:
+ permalink: "/:path.html"
+ -
+ scope:
+ path: "_overviews/macros"
+ values:
+ scala2: true
+ versionSpecific: true
+ -
+ scope:
+ path: "_overviews/reflection"
+ values:
+ scala2: true
+ versionSpecific: true
+ -
+ scope:
+ path: "_overviews/quasiquotes"
+ values:
+ scala2: true
+ versionSpecific: true
+ -
+ scope:
+ path: "_overviews/repl"
+ values:
+ scala2: true
+ versionSpecific: true
+ -
+ scope:
+ path: "_overviews/plugins"
+ values:
+ scala2: true
+ versionSpecific: true
+ -
+ scope:
+ path: "_overviews/compiler-options"
+ values:
+ scala2: true
+ versionSpecific: true
+ -
+ scope:
+ path: "_overviews/scala3-book"
+ values:
+ scala3: true
+ # num: 99 # to list them in the TOC, should be overwritten individually
+ partof: scala3-book
+ type: section
+ overview-name: "Scala 3 — Book"
+ layout: multipage-overview
+ permalink: "/scala3/book/:title.html"
+ -
+ scope:
+ path: "_overviews/contribute"
+ values:
+ partof: scala-contribution
+ overview-name: Contributing to Scala's OSS Ecosystem
+ layout: multipage-overview
+ permalink: "/contribute/:title.html"
+ -
+ scope:
+ path: "_overviews/scala3-migration"
+ values:
+ scala3: true
+ # num: 99 # to list them in the TOC, should be overwritten individually
+ partof: scala3-migration
+ type: section
+ overview-name: "Scala 3 Migration Guide"
+ layout: multipage-overview
+ permalink: "/scala3/guides/migration/:title.html"
+ -
+ scope:
+ path: "_overviews/scala3-contribution"
+ values:
+ scala3: true
+ partof: scala3-contribution
+ type: section
+ overview-name: "Guide to Scala 3 Compiler Contribution"
+ layout: multipage-overview
+ permalink: "/scala3/guides/contribution/:title.html"
+ -
+ scope:
+ path: "_overviews/scala3-macros"
+ values:
+ scala3: true
+ versionSpecific: true
+ partof: scala3-macros
+ overview-name: "Macros in Scala 3"
+ layout: multipage-overview
+ permalink: "/scala3/guides/macros/:title.html"
+ -
+ scope:
+ path: "_overviews/scala3-scaladoc"
+ values:
+ scala3: true
+ versionSpecific: true
+ partof: scala3-scaladoc
+ overview-name: "Scaladoc"
+ layout: multipage-overview
+ permalink: "/scala3/guides/scaladoc/:title.html"
+ -
+ scope:
+ path: "_overviews/toolkit"
+ values:
+ partof: toolkit
+ overview-name: "The Scala Toolkit"
+ layout: multipage-overview
+ permalink: "/toolkit/:title.html"
+ -
+ scope:
+ path: "scala3"
+ values:
+ scala3: true
+
highlighter: rouge
permalink: /:categories/:title.html:output_ext
baseurl:
-exclude: ["vendor"]
+scala3ref: "https://docs.scala-lang.org/scala3/reference"
+exclude: ["vendor", ".metals"]
plugins:
- jekyll-redirect-from
- - jekyll-scalafiddle
diff --git a/_data/compiler-options.yml b/_data/compiler-options.yml
index fb67497392..f4cced5028 100644
--- a/_data/compiler-options.yml
+++ b/_data/compiler-options.yml
@@ -260,7 +260,7 @@
type: "String"
arg: "release"
default:
- description: "Compile for a specific version of the Java platform. Supported targets: 6, 7, 8, 9"
+ description: "Compile for a specific version of the Java platform. Supported targets: 8, 11, or any higher version listed at https://docs.scala-lang.org/overviews/jdk-compatibility/overview.html"
abbreviations:
- "--release"
- option: "-sourcepath"
@@ -379,8 +379,6 @@
description: "Warn when nullary methods return Unit."
- choice: "inaccessible"
description: "Warn about inaccessible types in method signatures."
- - choice: "nullary-override"
- description: "Warn when non-nullary `def f()` overrides nullary `def f`."
- choice: "infer-any"
description: "Warn when a type argument is inferred to be `Any`."
- choice: "missing-interpolator"
@@ -469,10 +467,6 @@
schema:
type: "Boolean"
description: "Don't perform exhaustivity/unreachability analysis. Also, ignore @switch annotation."
- - option: "-Xno-uescape"
- schema:
- type: "Boolean"
- description: "Disable handling of \\u unicode escapes."
- option: "-Xnojline"
schema:
type: "Boolean"
@@ -611,9 +605,22 @@
- option: "-Vimplicits"
schema:
type: "Boolean"
- description: "Show more detail on why some implicits are not applicable."
+ description: "Print dependent missing implicits."
abbreviations:
- "-Xlog-implicits"
+ - option: "-Vimplicits-verbose-tree"
+ schema:
+ type: "Boolean"
+ description: "Display all intermediate implicits in a chain."
+ - option: "-Vimplicits-max-refined"
+ schema:
+ type: "Int"
+ default: "0"
+ description: "max chars for printing refined types, abbreviate to `F {...}`"
+ - option: "-Vtype-diffs"
+ schema:
+ type: "Boolean"
+ description: "Print found/required error messages as colored diffs."
- option: "-Vinline"
schema:
type: "String"
@@ -1126,8 +1133,6 @@
description: "Warn when nullary methods return Unit."
- choice: "inaccessible"
description: "Warn about inaccessible types in method signatures."
- - choice: "nullary-override"
- description: "Warn when non-nullary `def f()` overrides nullary `def f`."
- choice: "infer-any"
description: "Warn when a type argument is inferred to be `Any`."
- choice: "missing-interpolator"
diff --git a/_data/doc-nav-header.yml b/_data/doc-nav-header.yml
index 5f9e5b9b0c..772da79703 100644
--- a/_data/doc-nav-header.yml
+++ b/_data/doc-nav-header.yml
@@ -1,25 +1,47 @@
-- title: API
+- title: Getting Started
url: "#"
submenu:
- - title: Current
- url: https://www.scala-lang.org/api/current/
- - title: Nightly
- url: https://www.scala-lang.org/files/archive/nightly/2.13.x/api/2.13.x/
- - title: All Versions
- url: "/api/all.html"
+ - title: Install Scala
+ url: "/getting-started/install-scala.html"
+ - title: Scala IDEs
+ url: "/getting-started/scala-ides.html"
- title: Learn
url: "#"
submenu:
- - title: Getting Started
- url: "/getting-started/index.html"
- title: Tour of Scala
url: "/tour/tour-of-scala.html"
- - title: Scala Book
+ - title: Scala 3 Book
+ url: "/scala3/book/introduction.html"
+ - title: Scala 2 Book
url: "/overviews/scala-book/introduction.html"
+ - title: Online Courses
+ url: "/online-courses.html"
+- title: Scala 3 Migration
+ url: "#"
+ submenu:
+ - title: What's New?
+ url: "/scala3/new-in-scala3.html"
+ - title: Migrating From Scala 2
+ url: "/scala3/guides/migration/compatibility-intro.html"
+ - title: New Features for Scaladoc
+ url: "/scala3/scaladoc.html"
+ - title: Videos and Talks
+ url: "/scala3/talks.html"
+- title: Tutorials
+ url: "#"
+ submenu:
+ - title: Getting Started with Scala in IntelliJ
+ url: "/getting-started/intellij-track/getting-started-with-scala-in-intellij.html"
+ - title: Getting Started with Scala and sbt
+ url: "/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.html"
- title: Scala for Java Programmers
url: "/tutorials/scala-for-java-programmers.html"
- - title: Online Resources
- url: "/learn.html"
+ - title: Scala on Android
+ url: "/tutorials/scala-on-android.html"
+ - title: Scala with Maven
+ url: "/tutorials/scala-with-maven.html"
+ - title: Using the Scala Toolkit
+ url: "/toolkit/introduction.html"
- title: Reference
url: "#"
submenu:
@@ -27,15 +49,23 @@
url: "/overviews/index.html"
- title: Books
url: "/books.html"
- - title: Scala FAQs
+ - title: Scala FAQ
url: "/tutorials/FAQ/index.html"
- - title: Language Spec
+ - title: Scala 2 Language Specification
url: http://scala-lang.org/files/archive/spec/2.13/
-- title: Style Guide
- url: "/style/index.html"
-- title: Cheatsheet
- url: "/cheatsheets/index.html"
-- title: Glossary
- url: "/glossary/index.html"
+ - title: Scala 3 Language Specification
+ url: http://scala-lang.org/files/archive/spec/3.4/
+ - title: Scala 3 Language Reference
+ url: "https://docs.scala-lang.org/scala3/reference"
+ - title: Scala Contribution Guide
+ url: "/contribute/"
+ - title: Style Guide
+ url: "/style/index.html"
+ - title: Cheatsheet
+ url: "/cheatsheets/index.html"
+ - title: Glossary
+ url: "/glossary/index.html"
+- title: API
+ url: "/api/all.html"
- title: SIPs
url: "/sips/index.html"
diff --git a/_data/footer.yml b/_data/footer.yml
index b810181f92..789017f8b9 100644
--- a/_data/footer.yml
+++ b/_data/footer.yml
@@ -21,9 +21,11 @@
links:
- title: Community
url: "http://scala-lang.org/community/"
- - title: Mailing Lists
- url: "http://scala-lang.org/community/index.html#mailing-lists"
- - title: Chat Rooms & More
+ - title: Scala Ambassadors
+ url: "http://scala-lang.org/ambassadors/"
+ - title: Forums
+ url: "http://scala-lang.org/community/index.html#forums"
+ - title: Chat
url: "http://scala-lang.org/community/index.html#chat-rooms"
- title: Libraries and Tools
url: "http://scala-lang.org/community/index.html#community-libraries-and-tools"
@@ -39,16 +41,28 @@
- title: Scala
class: scala
links:
+ - title: Governance
+ url: "http://scala-lang.org/governance/"
- title: Blog
url: "http://scala-lang.org/blog/"
- title: Code of Conduct
url: "http://scala-lang.org/conduct/"
- title: License
url: "http://scala-lang.org/license/"
+ - title: Security Policy
+ url: "http://scala-lang.org/security/"
- title: Social
class: social
links:
- title: GitHub
url: "https://github.com/scala/scala"
- - title: Twitter
- url: "https://twitter.com/scala_lang"
+ - title: Mastodon
+ url: "https://fosstodon.org/@scala_lang"
+ - title: Bluesky
+ url: "https://bsky.app/profile/scala-lang.org"
+ - title: X
+ url: "https://x.com/scala_lang"
+ - title: Discord
+ url: "https://discord.com/invite/scala"
+ - title: LinkedIn
+ url: "https://www.linkedin.com/company/scala-center/"
\ No newline at end of file
diff --git a/_data/messages.yml b/_data/messages.yml
new file mode 100644
index 0000000000..642a7ac557
--- /dev/null
+++ b/_data/messages.yml
@@ -0,0 +1 @@
+scam-banner: "**⚠️ Beware of Scams**: since Feb 2024, scammers are using [fake Scala websites to sell courses](https://www.scala-lang.org/blog/2024/03/01/fake-scala-courses.html), please check you are using an official source."
diff --git a/_data/nav-header.yml b/_data/nav-header.yml
index 26bd280020..792c68fc1e 100644
--- a/_data/nav-header.yml
+++ b/_data/nav-header.yml
@@ -1,12 +1,14 @@
-- title: Documentation
+- title: Learn
url: "/"
-- title: Download
+- title: Install
url: https://www.scala-lang.org/download/
+- title: Playground
+ url: https://scastie.scala-lang.org
+- title: Find A Library
+ url: https://index.scala-lang.org
- title: Community
url: https://www.scala-lang.org/community/
-- title: Libraries
- url: https://index.scala-lang.org
-- title: Contribute
- url: https://www.scala-lang.org/contribute/
+- title: Governance
+ url: https://www.scala-lang.org/governance/
- title: Blog
url: https://www.scala-lang.org/blog/
diff --git a/_data/overviews-ja.yml b/_data/overviews-ja.yml
index f6cbeb34cd..60277bd90c 100644
--- a/_data/overviews-ja.yml
+++ b/_data/overviews-ja.yml
@@ -58,8 +58,32 @@
- category: 言語
description: "Scala 言語の機能をカバーするガイドと概要"
overviews:
+ - title: "Scala 2 から Scala 3 への移行"
+ icon: suitcase
+ root: "scala3/guides/"
+ url: "migration/compatibility-intro.html"
+ description: "Scala 3 との互換性と移行について知っておくべきことすべて"
+ - title: "Scala 3 マクロ"
+ by: Nicolas Stucki
+ icon: magic
+ root: "scala3/guides/"
+ url: "macros"
+ description: "Scala 3 のマクロの書き方に関係する全ての機能をカバーする詳しいチュートリアル"
+ label-text: new in Scala 3
+ - title: 値クラスと汎用トレイト
+ by: Mark Harrah
+ description: "値クラスは Scala で実行時のオブジェクトアロケーションを避ける新しい仕組みだ。これは新しい AnyVal サブクラスを定義することで達成できる。"
+ icon: gem
+ url: "core/value-classes.html"
+ - title: TASTyの概要
+ by: Alvin Alexander
+ icon: birthday-cake
+ root: "scala3/guides/"
+ url: "tasty-overview.html"
+ description: "Scala のエンドユーザー向けの TASTy のフォーマットの概要"
+ label-text: new in Scala 3
- title: 文字列補間
- icon: usd
+ icon: dollar-sign
url: "core/string-interpolation.html"
description: >
文字列補間は、ユーザーが加工文字列リテラル(processed string literal)に変数参照を直接埋め込めるようにしてくれる。以下例。
@@ -70,11 +94,6 @@
by: Josh Suereth
description: "Scala 2.10 は暗黙クラス(implicit class)と呼ばれる新しい機能を導入した。暗黙クラスは implicit キーワードでマークされたクラスだ。このキーワードはそのクラスがスコープ内にあるとき、そのプライマリコンストラクターが暗黙変換に利用可能にする。"
url: "core/implicit-classes.html"
- - title: 値クラスと汎用トレイト
- by: Mark Harrah
- description: "値クラスは Scala で実行時のオブジェクトアロケーションを避ける新しい仕組みだ。これは新しい AnyVal サブクラスを定義することで達成できる。"
- icon: diamond
- url: "core/value-classes.html"
- category: ライブラリの作成
description: "Scala エコシステム向けのオープンソースライブラリの貢献方法のガイド"
@@ -258,18 +277,6 @@
- category: レガシー
description: "最近の Scala バージョン(2.12以上)には関係なくなった機能をカバーするガイド。"
overviews:
- - title: Scala アクター移行ガイド
- by: Vojin Jovanovic and Philipp Haller
- icon: truck
- url: "core/actors-migration-guide.html"
- description: "Scala アクターから Akka への移行を容易にするため、Actor Migration Kit(AMK)を用意した。AMK は、Scala アクターの拡張から構成され、プロジェクトのクラスパスに scala-actors-migration.jar を含めることで有効になる。加えて、Akka 2.1 はアクター DSL シングルトンのような機能を導入し、Scala アクターを使ったコードを Akka へ容易に変換することを可能にしている。このドキュメントの目的はユーザーに移行プロセスを案内し、AMK の使い方を説明することだ。"
- - title: Scala アクター API
- by: Philipp Haller and Stephen Tu
- icon: users
- url: "core/actors.html"
- description: "このガイドは Scala 2.8/2.9 の scala.actors パッケージの API を説明する。組織は論理的に同類の型のグループに従う。トレイト階層は個々のセクションを構造化することを考慮している。既存の Scaladoc ベースの API ドキュメントを補間するため、これらトレイトが定義する様々なメソッドの実行時の挙動にフォーカスする。"
- label-color: "#899295"
- label-text: deprecated
- title: Scala 2.8 から 2.12 までのコレクション
by: Martin Odersky
icon: sitemap
diff --git a/_data/overviews-ru.yml b/_data/overviews-ru.yml
index 8387b36946..f4a652a032 100644
--- a/_data/overviews-ru.yml
+++ b/_data/overviews-ru.yml
@@ -60,7 +60,7 @@
description: "Руководства и обзоры, охватывающие функционал языка Scala."
overviews:
- title: Строковая интерполяция
- icon: usd
+ icon: dollar-sign
url: "core/string-interpolation.html"
description: >
Строковая интерполяция позволяет пользователям встраивать данные из переменных непосредственно в обрабатываемые строковые литералы. Вот пример:
@@ -74,7 +74,7 @@
- title: Вычислительные Классы и Универсальные Трейты
by: Mark Harrah
description: "Вычислительные-Классы - это новый механизм в Scala, позволяющий избежать создания объектов во время исполнения, которое достигается за счет объявления класса в качестве подкласса AnyVal."
- icon: diamond
+ icon: gem
url: "core/value-classes.html"
- category: Создание своих библиотек
@@ -258,18 +258,6 @@
- category: Наследие
description: "Руководство по функционалу, которые больше не соответствуют последним версиям Scala (2.12+)."
overviews:
- - title: Руководство по миграции Scala Акторов
- by: Vojin Jovanovic и Philipp Haller
- icon: truck
- url: "core/actors-migration-guide.html"
- description: "Для облегчения миграции со Скала Актеров на Акка мы предоставили Миграционный Комплект для Актеров (МКА). МКА состоит из расширения Scala Акторов, которое позволяет включить scala-actors-migration.jar в пространство классов проекта. Кроме того, Akka 2.1 включает в себя такие функции, как ActorDSL singleton, которые позволяют осуществлять простое преобразование кода с использованием Scala Actors в Akka. Цель этого документа - помочь пользователям пройти через процесс миграции и объяснить, как использовать МКА."
- - title: API Scala Акторов
- by: Philipp Haller и Stephen Tu
- icon: users
- url: "core/actors.html"
- description: "В данном руководстве описывается API пакета scala.actors версии 2.8/2.9. Сгруппированы по типам, которые логически принадлежат друг другу. Иерархия трейтов учитывается при структурировании отдельных разделов. Основное внимание уделяется поведению во время исполнения различных методов, которое дополняет существующую документацию по API на основе Scaladoc."
- label-color: "#899295"
- label-text: устарело
- title: Scala коллекции с 2.8 по 2.12
by: Martin Odersky
icon: sitemap
diff --git a/_data/overviews-uk.yml b/_data/overviews-uk.yml
new file mode 100644
index 0000000000..02be500922
--- /dev/null
+++ b/_data/overviews-uk.yml
@@ -0,0 +1,348 @@
+- category: Стандартна бібліотека
+ description: "Посібники та огляди стандартної бібліотеки Scala."
+ overviews:
+ - title: Scala колекції
+ by: Martin Odersky та Julien Richard-Foy
+ icon: sitemap
+ url: "collections-2.13/introduction.html"
+ description: "Бібліотека колекцій Scala."
+ subdocs:
+ - title: Вступ
+ url: "collections-2.13/introduction.html"
+ - title: Змінювані та незмінювані колекції
+ url: "collections-2.13/overview.html"
+ - title: Трейт Iterable
+ url: "collections-2.13/trait-iterable.html"
+ - title: Трейти послідовностей. Seq, IndexedSeq та LinearSeq
+ url: "collections-2.13/seqs.html"
+ - title: Реалізація незмінюваних колекцій
+ url: "collections-2.13/concrete-immutable-collection-classes.html"
+ - title: Реалізація змінюваних колекцій
+ url: "collections-2.13/concrete-mutable-collection-classes.html"
+ - title: Масиви
+ url: "collections-2.13/arrays.html"
+ - title: Рядки
+ url: "collections-2.13/strings.html"
+ - title: Показники продуктивності
+ url: "collections-2.13/performance-characteristics.html"
+ - title: Рівність
+ url: "collections-2.13/equality.html"
+ - title: Відображення
+ url: "collections-2.13/views.html"
+ - title: Ітератори
+ url: "collections-2.13/iterators.html"
+ - title: Створення колекцій з нуля
+ url: "collections-2.13/creating-collections-from-scratch.html"
+ - title: Перетворення між колекціями Java та Scala
+ url: "collections-2.13/conversions-between-java-and-scala-collections.html"
+ - title: Міграція проєкту до колекцій Scala 2.13
+ icon: sitemap
+ url: "core/collections-migration-213.html"
+ description: "Ця сторінка описує основні зміни в колекціях для користувачів, які переходять на Scala 2.13. Також, розглянуто варіанти побудови проєкти з перехресною сумісністю для Scala 2.11/2.12 і 2.13."
+ - title: Архітектура колекцій Scala
+ icon: sitemap
+ url: "core/architecture-of-scala-213-collections.html"
+ by: Julien Richard-Foy
+ description: "Ці сторінки описують архітектуру фреймворку колекцій, представленого в Scala 2.13. У порівнянні з Collections API ви дізнаєтеся більше про внутрішню роботу фреймворка."
+ - title: Реалізація користувацьких колекцій
+ icon: building
+ url: "core/custom-collections.html"
+ by: Martin Odersky, Lex Spoon та Julien Richard-Foy
+ description: "У цьому документі ви дізнаєтеся, як фреймворк колекцій допомагає вам визначати власні колекції за допомогою кількох рядків коду, повторно використовуючи переважну частину функцій колекції з фреймворку."
+ - title: Додавання спеціальних операцій до колекцій
+ icon: building
+ url: "core/custom-collection-operations.html"
+ by: Julien Richard-Foy
+ description: "У цьому посібнику показано, як писати перетворення, що застосовуються до всіх типів колекцій і повертати той самий тип колекції. Також, як писати операції, які параметризуються типом колекції."
+
+- category: Мова
+ description: "Посібники та огляди, що охоплюють функції на мові Scala."
+ overviews:
+ - title: Міграція зі Scala 2 на Scala 3
+ by: Adrien Piquerez
+ icon: suitcase
+ root: "scala3/guides/"
+ url: "migration/compatibility-intro.html"
+ description: "Все, що потрібно знати про сумісність і міграцію на Scala 3."
+ - title: Макроси Scala 3
+ by: Nicolas Stucki
+ icon: magic
+ root: "scala3/guides/"
+ url: "macros"
+ description: "Детальний підручник, який охоплює всі можливості, пов'язані з написанням макросів у Scala 3."
+ label-text: нове в Scala 3
+ - title: Класи значень та універсальні трейти
+ by: Mark Harrah
+ description: "Класи значень – це новий механізм у Scala, що дозволяє уникнути виділення об'єктів під час виконання. Це досягається за допомогою визначення нових підкласів AnyVal."
+ icon: gem
+ url: "core/value-classes.html"
+ - title: Огляд TASTy
+ by: Alvin Alexander
+ icon: birthday-cake
+ label-text: нове в Scala 3
+ root: "scala3/guides/"
+ url: "tasty-overview.html"
+ description: "Огляд формату TASTy, призначеного для користувачів мови Scala."
+ - title: Інтерполяція рядків
+ icon: dollar-sign
+ url: "core/string-interpolation.html"
+ description: >
+ Інтерполяція рядків дозволяє користувачам вбудовувати посилання на змінні безпосередньо в оброблені рядкові літерали. Ось приклад:
+
val name = "James"
+ println(s"Hello, $name") // Hello, James
+ Літерал s"Hello, $name" є рядковим літералом, який буде додатково оброблено. Це означає, що компілятор виконує додаткову роботу над цим літералом. Оброблений рядковий літерал позначається набором символів, що передують ". Інтерполяція рядків була введена в SIP-11.
+ - title: Неявні класи
+ by: Josh Suereth
+ description: "Scala 2.10 представила нову функцію під назвою неявні класи. Неявний клас — це клас, позначений ключовим словом implicit. Це ключове слово робить основний конструктор класу доступним для неявних перетворень, коли клас знаходиться в області видимості."
+ url: "core/implicit-classes.html"
+
+- category: Створення бібліотек
+ description: "Посібники щодо розробки бібліотек з відкритим кодом для екосистеми Scala."
+ overviews:
+ - title: Посібник для авторів бібліотек
+ by: Julien Richard-Foy
+ icon: tasks
+ url: "contributors/index.html"
+ description: "Перелічує всі інструменти, які автори бібліотек мають налаштувати для публікації та документування своїх бібліотек."
+
+- category: Паралельне та конкурентне програмування
+ description: "Повні посібники, що охоплюють деякі бібліотеки Scala для паралельного та конкурентного програмування."
+ overviews:
+ - title: Future та Promise
+ by: Philipp Haller, Aleksandar Prokopec, Heather Miller, Viktor Klang, Roland Kuhn та Vojin Jovanovic
+ icon: tasks
+ url: "core/futures.html"
+ description: "Ф'ючери дають можливість міркувати про паралельне виконання багатьох операцій – ефективним і не блокуючим способом. Ф'ючер — це об’єкт-заповнювач для значення, яке може ще не існувати. Як правило, вартість Ф'ючеру надається одночасно і може згодом використовуватися. Складання одночасних завдань таким чином, як правило, призводить до швидшого, асинхронного, не блокувального паралельного коду."
+ - title: Паралельні колекції
+ by: Aleksandar Prokopec та Heather Miller
+ icon: rocket
+ url: "parallel-collections/overview.html"
+ description: "Бібліотека паралельних колекцій Scala."
+ subdocs:
+ - title: Огляд
+ url: "parallel-collections/overview.html"
+ - title: Реалізація паралельних колекцій
+ url: "parallel-collections/concrete-parallel-collections.html"
+ - title: Перетворення паралельних колекцій
+ url: "parallel-collections/conversions.html"
+ - title: Конкурентні Try
+ url: "parallel-collections/ctries.html"
+ - title: Архітектура бібліотеки паралельних колекцій
+ url: "parallel-collections/architecture.html"
+ - title: Створення користувацьких паралельних колекцій
+ url: "parallel-collections/custom-parallel-collections.html"
+ - title: Конфігурація паралельних колекцій
+ url: "parallel-collections/configuration.html"
+ - title: Вимірювання продуктивності
+ url: "parallel-collections/performance.html"
+
+- category: Сумісність
+ description: "Що з чим працює (чи ні)."
+ overviews:
+ - title: Сумісність версій JDK
+ description: "Які версії Scala працюють на яких версіях JDK"
+ icon: coffee
+ url: "jdk-compatibility/overview.html"
+ - title: Бінарна сумісність релізів Scala
+ description: "Якщо дві версії Scala бінарно сумісні, можна безпечно скомпілювати свій проєкт на одній версії Scala та зв'язати з іншою версією Scala під час виконання. Безпечне зв'язування під час виконання (тільки!) означає, що JVM не генерує (підклас) LinkageError під час виконання вашої програми у змішаному сценарії, припускаючи, що вона не виникає при компіляції та запуску в одній версії Scala. Конкретно це означає, що ви можете мати зовнішні залежності від вашого шляху до класу під час виконання, які використовують іншу версію Scala, ніж та, з якою ви компілюєте, за умови, що вони сумісні з бінарними файлами. Іншими словами, окрема компіляція в різних версіях, сумісних з бінарними файлами, не створює проблем у порівнянні з компіляцією та запуском всього в одній версії Scala."
+ icon: puzzle-piece
+ url: "core/binary-compatibility-of-scala-releases.html"
+ - title: Бінарна сумісність для авторів бібліотек
+ description: "Різноманітний і повний набір бібліотек важливий для будь-якої продуктивної екосистеми програмного забезпечення. Хоча розробляти та розповсюджувати бібліотеки Scala легко, добре авторство бібліотеки виходить за рамки простого написання коду та його публікації. У цьому посібнику ми розглянемо важливу тему бінарної сумісності."
+ icon: puzzle-piece
+ url: "core/binary-compatibility-for-library-authors.html"
+
+- category: Інструменти
+ description: "Довідковий матеріал про основні інструменти Scala, такі як покоління Scala REPL і Scaladoc."
+ overviews:
+ - title: Scala 2 REPL
+ icon: terminal
+ url: "repl/overview.html"
+ description: |
+ Scala REPL це інструмент (scala) для виконання виразів в Scala.
+
+ Команда scala виконає скрипт шляхом обгортання його в шаблон, а потім компіляції та виконання отриманої програми
+ - title: Scaladoc для Scala 3
+ by: Krzysztof Romanowski, Aleksander Boruch-Gruszecki, Andrzej Ratajczak, Kacper Korban, Filip Zybała
+ icon: book
+ root: "scala3/guides/"
+ url: "scaladoc"
+ label-text: оновлено
+ description: "Оновлення в Scala 3 для інструменту генерації документації API."
+ - title: Scaladoc
+ url: "scaladoc/overview.html"
+ icon: book
+ description: "Інструмент Scala для генерації документації для API."
+ subdocs:
+ - title: Огляд
+ url: "scaladoc/overview.html"
+ - title: Scaladoc для авторів бібліотек
+ url: "scaladoc/for-library-authors.html"
+ - title: Використання інтерфейсу Scaladoc
+ url: "scaladoc/interface.html"
+
+- category: Компілятор
+ description: "Посібники та огляди компілятора Scala: плагіни компілятора, інструменти рефлексії та метапрограмування, такі як макроси."
+ overviews:
+ - title: "Посібник з внесення змін у Scala 3"
+ by: Jamie Thompson, Anatolii Kmetiuk
+ icon: cogs
+ root: "scala3/guides/"
+ url: "contribution/contribution-intro.html"
+ description: "Посібник з компілятора Scala 3 та вирішення проблем."
+ - title: Рефлексія в Scala 2
+ by: Heather Miller, Eugene Burmako та Philipp Haller
+ icon: binoculars
+ url: "reflection/overview.html"
+ description: Фреймворк Scala для рефлексії під час виконання/компіляції.
+ label-text: відсутнє в Scala 3
+ subdocs:
+ - title: Огляд
+ url: "reflection/overview.html"
+ - title: Environment, Universe та Mirror
+ url: "reflection/environment-universes-mirrors.html"
+ - title: Symbol, Tree та Type
+ url: "reflection/symbols-trees-types.html"
+ - title: Annotation, Name, Scope та More
+ url: "reflection/annotations-names-scopes.html"
+ - title: TypeTag та Manifest
+ url: "reflection/typetags-manifests.html"
+ - title: Безпека потоків
+ url: "reflection/thread-safety.html"
+ - title: Зміни в Scala 2.11
+ url: "reflection/changelog211.html"
+ - title: Макроси в Scala 2
+ by: Eugene Burmako
+ icon: magic
+ url: "macros/usecases.html"
+ description: "Фреймворк метапрограмування Scala."
+ label-text: відсутнє в Scala 3
+ subdocs:
+ - title: Випадки використання
+ url: "macros/usecases.html"
+ - title: Blackbox проти Whitebox
+ url: "macros/blackbox-whitebox.html"
+ - title: Макроси Def
+ url: "macros/overview.html"
+ - title: Квазіцитати
+ url: "quasiquotes/intro.html"
+ - title: Пакети макросів
+ url: "macros/bundles.html"
+ - title: Неявні макроси
+ url: "macros/implicits.html"
+ - title: Макроси-екстрактори
+ url: "macros/extractors.html"
+ - title: Провайдери типів
+ url: "macros/typeproviders.html"
+ - title: Анотації макросів
+ url: "macros/annotations.html"
+ - title: Макрос Paradise
+ url: "macros/paradise.html"
+ - title: Дорожня карта
+ url: "macros/roadmap.html"
+ - title: Зміни в 2.11
+ url: "macros/changelog211.html"
+ - title: Квазіцитати в Scala 2
+ by: Denys Shabalin
+ icon: quote-left
+ url: "quasiquotes/setup.html"
+ description: "Квазіцитати — це зручний спосіб маніпулювати синтаксичними деревами Scala."
+ label-text: відсутнє в Scala 3
+ subdocs:
+ - title: Залежності та налаштування
+ url: "quasiquotes/setup.html"
+ - title: Вступ
+ url: "quasiquotes/intro.html"
+ - title: Підіймання
+ url: "quasiquotes/lifting.html"
+ - title: Опускання
+ url: "quasiquotes/unlifting.html"
+ - title: Гігієна
+ url: "quasiquotes/hygiene.html"
+ - title: Випадки використання
+ url: "quasiquotes/usecases.html"
+ - title: Резюме синтаксису
+ url: "quasiquotes/syntax-summary.html"
+ - title: Деталі виразів
+ url: "quasiquotes/expression-details.html"
+ - title: Деталі типів
+ url: "quasiquotes/type-details.html"
+ - title: Деталі патернів
+ url: "quasiquotes/pattern-details.html"
+ - title: Деталі визначення та імпорту
+ url: "quasiquotes/definition-details.html"
+ - title: Резюме термінології
+ url: "quasiquotes/terminology.html"
+ - title: Майбутні перспективи
+ url: "quasiquotes/future.html"
+ - title: Плагіни компілятора
+ by: Lex Spoon та Seth Tisue
+ icon: puzzle-piece
+ url: "plugins/index.html"
+ description: "Плагіни компілятора дозволяють налаштовувати та розширювати компілятор Scala. У цьому підручнику описується функція плагіну та пояснюється, як створити простий плагін."
+ - title: Параметри компілятора
+ by: Community
+ icon: cog
+ url: "compiler-options/index.html"
+ description: "Різні параметри того як scalac компілює ваш код."
+ - title: Форматування помилок
+ by: Torsten Schmits
+ icon: cog
+ url: "compiler-options/errors.html"
+ description: "Новий механізм для більш зручних повідомлень про помилки, друку ланцюжків залежних неявних параметрів та кольорових відмінностей знайдених/потрібних типів."
+ - title: Оптимізатор
+ by: Lukas Rytz та Andrew Marki
+ icon: cog
+ url: "compiler-options/optimizer.html"
+ description: "Компілятор може виконувати різні оптимізації."
+
+- category: Спадщина (legacy)
+ description: "Посібники, що охоплюють функції, які більше не стосуються останніх версій Scala (2.12+)."
+ overviews:
+ - title: Колекції Scala з 2.8 до 2.12
+ by: Martin Odersky
+ icon: sitemap
+ url: "collections/introduction.html"
+ description: "Бібліотека колекцій Scala."
+ subdocs:
+ - title: Вступ
+ url: "collections/introduction.html"
+ - title: Змінювані та незмінювані колекції
+ url: "collections/overview.html"
+ - title: Трейт Traversable
+ url: "collections/trait-traversable.html"
+ - title: Трейт Iterable
+ url: "collections/trait-iterable.html"
+ - title: Трейти послідовностей. Seq, IndexedSeq та LinearSeq
+ url: "collections/seqs.html"
+ - title: Множини
+ url: "collections/sets.html"
+ - title: Асоціативні масиви
+ url: "collections/maps.html"
+ - title: Реалізація незмінюваних колекцій
+ url: "collections/concrete-immutable-collection-classes.html"
+ - title: Реалізація змінюваних колекцій
+ url: "collections/concrete-mutable-collection-classes.html"
+ - title: Масиви
+ url: "collections/arrays.html"
+ - title: Рядки
+ url: "collections/strings.html"
+ - title: Показники продуктивності
+ url: "collections/performance-characteristics.html"
+ - title: Рівність
+ url: "collections/equality.html"
+ - title: Відображення
+ url: "collections/views.html"
+ - title: Ітератори
+ url: "collections/iterators.html"
+ - title: Створення колекцій з нуля
+ url: "collections/creating-collections-from-scratch.html"
+ - title: Перетворення між колекціями Java та Scala
+ url: "collections/conversions-between-java-and-scala-collections.html"
+ - title: Міграція з версії Scala 2.7
+ url: "collections/migrating-from-scala-27.html"
+ - title: Архітектура колекцій Scala з 2.8 до 2.12
+ icon: building
+ url: "core/architecture-of-scala-collections.html"
+ by: Martin Odersky та Lex Spoon
+ description: "На цих сторінках детально описується архітектура фреймворку колекцій Scala. У порівнянні з Collections API ви дізнаєтеся більше про внутрішню роботу фреймворку. Ви також дізнаєтеся, як ця архітектура допомагає вам визначати власні колекції за допомогою кількох рядків коду, повторно використовуючи переважну частину функцій колекції з фреймворку."
diff --git a/_data/overviews-zh-cn.yml b/_data/overviews-zh-cn.yml
new file mode 100644
index 0000000000..1c48218eef
--- /dev/null
+++ b/_data/overviews-zh-cn.yml
@@ -0,0 +1,312 @@
+- category: 标准库
+ description: "涵盖 Scala 标准库的参考与概览"
+ overviews:
+ - title: Scala 容器
+ by: Martin Odersky and Julien Richard-Foy
+ icon: sitemap
+ url: "collections-2.13/introduction.html"
+ description: "Scala 的容器库"
+ subdocs:
+ - title: 简介
+ url: "collections-2.13/introduction.html"
+ - title: 可变与不可变容器
+ url: "collections-2.13/overview.html"
+ - title: Iterable 特质
+ url: "collections-2.13/trait-iterable.html"
+ - title: 序列特质 Seq, IndexedSeq, 和 LinearSeq
+ url: "collections-2.13/seqs.html"
+ - title: 具体不可变容器类
+ url: "collections-2.13/concrete-immutable-collection-classes.html"
+ - title: 具体可变容器类
+ url: "collections-2.13/concrete-mutable-collection-classes.html"
+ - title: 数组
+ url: "collections-2.13/arrays.html"
+ - title: 字符串
+ url: "collections-2.13/strings.html"
+ - title: 性能特点
+ url: "collections-2.13/performance-characteristics.html"
+ - title: 相等性
+ url: "collections-2.13/equality.html"
+ - title: 视图
+ url: "collections-2.13/views.html"
+ - title: 迭代器
+ url: "collections-2.13/iterators.html"
+ - title: 从头开始创建容器
+ url: "collections-2.13/creating-collections-from-scratch.html"
+ - title: Java 与 Scala 间的容器转换
+ url: "collections-2.13/conversions-between-java-and-scala-collections.html"
+ - title: 迁移项目容器至 Scala 2.13 的容器
+ icon: sitemap
+ url: "core/collections-migration-213.html"
+ description: "本篇向欲迁移至 Scala 2.13 的容器用户介绍了主要变更并展示了如何通过 Scala 2.11,2.12 和 2.13 进行交叉编译"
+ - title: Scala 容器架构
+ icon: sitemap
+ url: "core/architecture-of-scala-213-collections.html"
+ by: Julien Richard-Foy
+ description: "这几篇介绍了引进到 Scala 2.13 中的容器框架的架构,对照容器API就能知晓更多框架内部工作机制"
+ - title: 实现定制容器
+ icon: building
+ url: "core/custom-collections.html"
+ by: Martin Odersky, Lex Spoon and Julien Richard-Foy
+ description: "从本篇中你会了解到如何利用容器框架通过几行代码来定义自己的容器,来重用来自框架的绝大部分容器功能。"
+ - title: 新增定制的容器操作
+ icon: building
+ url: "core/custom-collection-operations.html"
+ by: Julien Richard-Foy
+ description: "本篇展示了如何定制可应用于任意容器类型并返回相同类型的操作,以及如何定制带有欲编译容器类型参数的操作"
+
+- category: 语言
+ description: "涵盖 Scala 语言特性的参考与概览"
+ overviews:
+ - title: 字符串内插
+ icon: dollar-sign
+ url: "core/string-interpolation.html"
+ description: >
+ 字符串内插允许用户在字符串字面插值中直接嵌入变量引用。这里有个例子:
+ String Interpolation allows users to embed variable references directly in processed string literals. Here’s an example:
+
val name = "James"
+ println(s"Hello, $name") // Hello, James
+ scala 命令会通过包装源脚本到一模板中来执行它,然后编译并执行结果程序
+ - title: Scaladoc
+ url: "scaladoc/overview.html"
+ icon: book
+ description: "Scala 的 API 文档生成工具"
+ subdocs:
+ - title: 概览
+ url: "scaladoc/overview.html"
+ - title: 针对库作者的 Scaladoc
+ url: "scaladoc/for-library-authors.html"
+ - title: 使用 Scaladoc 接口
+ url: "scaladoc/interface.html"
+
+- category: 编译器
+ description: "涵盖 Scala 编译器的参考和概览:编译器插件,反射,以及元编程工具比如宏"
+ overviews:
+ - title: 反射
+ by: Heather Miller, Eugene Burmako, and Philipp Haller
+ icon: binoculars
+ url: "reflection/overview.html"
+ description: Scala 的运行时和编译期的反射框架
+ label-text: 实验
+ subdocs:
+ - title: 概览
+ url: "reflection/overview.html"
+ - title: 环境,通用和镜像(Environment, Universes, and Mirrors)
+ url: "reflection/environment-universes-mirrors.html"
+ - title: 符号,树和类型(Symbols, Trees, and Types)
+ url: "reflection/symbols-trees-types.html"
+ - title: 标号,名称,作用域及其他(Annotations, Names, Scopes, and More)
+ url: "reflection/annotations-names-scopes.html"
+ - title: TypeTags 和 Manifests
+ url: "reflection/typetags-manifests.html"
+ - title: 线程安全
+ url: "reflection/thread-safety.html"
+ - title: Scala 2.11 中的变化
+ url: "reflection/changelog211.html"
+ - title: 宏
+ by: Eugene Burmako
+ icon: magic
+ url: "macros/usecases.html"
+ description: "Scala 的元编程框架"
+ label-text: 实验
+ subdocs:
+ - title: 用例
+ url: "macros/usecases.html"
+ - title: 黑盒与白盒
+ url: "macros/blackbox-whitebox.html"
+ - title: Def 宏
+ url: "macros/overview.html"
+ - title: 拟引号(Quasiquotes)
+ url: "quasiquotes/intro.html"
+ - title: 宏绑定
+ url: "macros/bundles.html"
+ - title: 隐式宏
+ url: "macros/implicits.html"
+ - title: Extractor 宏
+ url: "macros/extractors.html"
+ - title: 类型 Providers
+ url: "macros/typeproviders.html"
+ - title: 宏标号
+ url: "macros/annotations.html"
+ - title: 宏乐园
+ url: "macros/paradise.html"
+ - title: 路线图
+ url: "macros/roadmap.html"
+ - title: 2.11 中的变化
+ url: "macros/changelog211.html"
+ - title: 拟引号
+ by: Denys Shabalin
+ icon: quote-left
+ url: "quasiquotes/setup.html"
+ description: "拟引号是操作 Scala 语法树的便捷方式"
+ label-text: 实验
+ subdocs:
+ - title: 依赖和设置
+ url: "quasiquotes/setup.html"
+ - title: 简介
+ url: "quasiquotes/intro.html"
+ - title: 提升(Lifting)
+ url: "quasiquotes/lifting.html"
+ - title: 拉降(Unlifting)
+ url: "quasiquotes/unlifting.html"
+ - title: 卫生(Hygiene)
+ url: "quasiquotes/hygiene.html"
+ - title: 用例
+ url: "quasiquotes/usecases.html"
+ - title: 语法总结
+ url: "quasiquotes/syntax-summary.html"
+ - title: 表达式细节
+ url: "quasiquotes/expression-details.html"
+ - title: 类型细节
+ url: "quasiquotes/type-details.html"
+ - title: 模式细节
+ url: "quasiquotes/pattern-details.html"
+ - title: 定义和引用细节
+ url: "quasiquotes/definition-details.html"
+ - title: 属于总结
+ url: "quasiquotes/terminology.html"
+ - title: 未来展望
+ url: "quasiquotes/future.html"
+ - title: 编译器插件
+ by: Lex Spoon and Seth Tisue
+ icon: puzzle-piece
+ url: "plugins/index.html"
+ description: "编译器插件允许定制和扩展 Scala 编译器。本篇导引描述了插件设施并带你领略如何创作一个简单插件"
+ - title: 编译器选项
+ by: Community
+ icon: cog
+ url: "compiler-options/index.html"
+ description: "控制 scalac 如何编译代码的各种选项"
+ - title: 错误格式
+ by: Torsten Schmits
+ icon: cog
+ url: "compiler-options/errors.html"
+ description: "一个新的用户友好的错误消息引擎,可以打印依赖的隐式链,颜色区分找到的和所需的类型差异"
+
+
+- category: 遗留问题
+ description: "涵盖一些与最近的 Scala 版本(2.12+)不再相关的特性的参考"
+ overviews:
+ - title: Scala 2.8 到 2.12 的容器
+ by: Martin Odersky
+ icon: sitemap
+ url: "collections/introduction.html"
+ description: "Scala 的容器库"
+ subdocs:
+ - title: 简介
+ url: "collections/introduction.html"
+ - title: 可变和不可变容器
+ url: "collections/overview.html"
+ - title: Traversable 特质
+ url: "collections/trait-traversable.html"
+ - title: Iterable 特质
+ url: "collections/trait-iterable.html"
+ - title: 序列特质 Seq, IndexedSeq, 和 LinearSeq
+ url: "collections/seqs.html"
+ - title: 集合(Sets)
+ url: "collections/sets.html"
+ - title: 映射(Maps)
+ url: "collections/maps.html"
+ - title: 具体的不可变容器类
+ url: "collections/concrete-immutable-collection-classes.html"
+ - title: 具体的可变容器类
+ url: "collections/concrete-mutable-collection-classes.html"
+ - title: 数组
+ url: "collections/arrays.html"
+ - title: 字符串
+ url: "collections/strings.html"
+ - title: 性能特点
+ url: "collections/performance-characteristics.html"
+ - title: 相等性
+ url: "collections/equality.html"
+ - title: 视图
+ url: "collections/views.html"
+ - title: 迭代器
+ url: "collections/iterators.html"
+ - title: 从头开始创建容器
+ url: "collections/creating-collections-from-scratch.html"
+ - title: Java 和 Scala 间容器转换
+ url: "collections/conversions-between-java-and-scala-collections.html"
+ - title: 从 Scala 2.7 迁移
+ url: "collections/migrating-from-scala-27.html"
+ - title: Scala 2.8 到 2.12 的容器架构
+ icon: building
+ url: "core/architecture-of-scala-collections.html"
+ by: Martin Odersky and Lex Spoon
+ description: "本篇细致地描述了 Scala 容器框架的架构,对比容器 API 你会发现更多框架的内部工作机制。你也会学到该架构如何帮你通过几行代码定义自己的容器,来重用来自框架的绝大部分容器功能。"
diff --git a/_data/overviews.yml b/_data/overviews.yml
index bd12fb5844..5756db5e3e 100644
--- a/_data/overviews.yml
+++ b/_data/overviews.yml
@@ -1,4 +1,3 @@
-
- category: Standard Library
description: "Guides and overviews covering the Scala standard library."
overviews:
@@ -60,8 +59,33 @@
- category: Language
description: "Guides and overviews covering features in the Scala language."
overviews:
+ - title: "Migration from Scala 2 to Scala 3"
+ by: Adrien Piquerez
+ icon: suitcase
+ root: "scala3/guides/"
+ url: "migration/compatibility-intro.html"
+ description: "Everything you need to know about compatibility and migration to Scala 3."
+ - title: Scala 3 Macros
+ by: Nicolas Stucki
+ icon: magic
+ root: "scala3/guides/"
+ url: "macros"
+ description: "A detailed tutorial to cover all the features involved in writing macros in Scala 3."
+ label-text: new in Scala 3
+ - title: Value Classes and Universal Traits
+ by: Mark Harrah
+ description: "Value classes are a new mechanism in Scala to avoid allocating runtime objects. This is accomplished through the definition of new AnyVal subclasses."
+ icon: gem
+ url: "core/value-classes.html"
+ - title: An Overview of TASTy
+ by: Alvin Alexander
+ icon: birthday-cake
+ label-text: new in Scala 3
+ root: "scala3/guides/"
+ url: "tasty-overview.html"
+ description: "An overview over the TASTy format aimed at end-users of the Scala language."
- title: String Interpolation
- icon: usd
+ icon: dollar-sign
url: "core/string-interpolation.html"
description: >
String Interpolation allows users to embed variable references directly in processed string literals. Here’s an example:
@@ -72,11 +96,15 @@
by: Josh Suereth
description: "Scala 2.10 introduced a new feature called implicit classes. An implicit class is a class marked with the implicit keyword. This keyword makes the class’ primary constructor available for implicit conversions when the class is in scope."
url: "core/implicit-classes.html"
- - title: Value Classes and Universal Traits
- by: Mark Harrah
- description: "Value classes are a new mechanism in Scala to avoid allocating runtime objects. This is accomplished through the definition of new AnyVal subclasses."
- icon: diamond
- url: "core/value-classes.html"
+ - title: The Scala Book
+ by: Alvin Alexander
+ icon: book
+ label-color: "#899295"
+ label-text: archived
+ url: "scala-book/introduction.html"
+ description: >
+ A light introduction to the Scala language, focused on Scala 2.
+ Now updated for Scala 3, we are in the process of merging the two.
- category: Authoring Libraries
description: "Guides for contributing open source libraries to the Scala ecosystem."
@@ -133,17 +161,27 @@
description: "A diverse and comprehensive set of libraries is important to any productive software ecosystem. While it is easy to develop and distribute Scala libraries, good library authorship goes beyond just writing code and publishing it. In this guide, we cover the important topic of Binary Compatibility."
icon: puzzle-piece
url: "core/binary-compatibility-for-library-authors.html"
+ - title: Nightly Versions of Scala
+ description: "We regularly publish 'nightlies' of both Scala 3 and Scala 2 so that users can preview and test the contents of upcoming releases. Here's how to find and use these versions."
+ url: "core/nightlies.html"
- category: "Tools"
description: "Reference material on core Scala tools like the Scala REPL and Scaladoc generation."
overviews:
- - title: Scala REPL
+ - title: Scala 2 REPL
icon: terminal
url: "repl/overview.html"
description: |
The Scala REPL is a tool (scala) for evaluating expressions in Scala.
The scala command will execute a source script by wrapping it in a template and then compiling and executing the resulting program
+ - title: Scaladoc For Scala 3
+ by: Krzysztof Romanowski, Aleksander Boruch-Gruszecki, Andrzej Ratajczak, Kacper Korban, Filip Zybała
+ icon: book
+ root: "scala3/guides/"
+ url: "scaladoc"
+ description: "Updates in Scala 3 to Scala’s API documentation generation tool."
+ label-text: updated
- title: Scaladoc
url: "scaladoc/overview.html"
icon: book
@@ -159,12 +197,12 @@
- category: Compiler
description: "Guides and overviews covering the Scala compiler: compiler plugins, reflection, and metaprogramming tools such as macros."
overviews:
- - title: Reflection
+ - title: Scala 2 Reflection
by: Heather Miller, Eugene Burmako, and Philipp Haller
icon: binoculars
url: "reflection/overview.html"
description: Scala's runtime/compile-time reflection framework.
- label-text: experimental
+ label-text: removed in Scala 3
subdocs:
- title: Overview
url: "reflection/overview.html"
@@ -180,12 +218,12 @@
url: "reflection/thread-safety.html"
- title: Changes in Scala 2.11
url: "reflection/changelog211.html"
- - title: Macros
+ - title: Scala 2 Macros
by: Eugene Burmako
icon: magic
url: "macros/usecases.html"
description: "Scala's metaprogramming framework."
- label-text: experimental
+ label-text: removed in Scala 3
subdocs:
- title: Use Cases
url: "macros/usecases.html"
@@ -211,12 +249,12 @@
url: "macros/roadmap.html"
- title: Changes in 2.11
url: "macros/changelog211.html"
- - title: Quasiquotes
+ - title: Quasiquotes in Scala 2
by: Denys Shabalin
icon: quote-left
url: "quasiquotes/setup.html"
description: "Quasiquotes are a convenient way to manipulate Scala syntax trees."
- label-text: experimental
+ label-text: removed in Scala 3
subdocs:
- title: Dependencies and setup
url: "quasiquotes/setup.html"
@@ -244,33 +282,30 @@
url: "quasiquotes/terminology.html"
- title: Future prospects
url: "quasiquotes/future.html"
- - title: Compiler Plugins
+ - title: Scala 2 Compiler Plugins
by: Lex Spoon and Seth Tisue
icon: puzzle-piece
url: "plugins/index.html"
description: "Compiler plugins permit customizing and extending the Scala compiler. This tutorial describes the plugin facility and walks you through how to create a simple plugin."
- - title: Compiler Options
+ - title: Scala 2 Compiler Options
by: Community
icon: cog
url: "compiler-options/index.html"
description: "Various options to control how scalac compiles your code."
-
+ - title: Error Formatting
+ by: Torsten Schmits
+ icon: cog
+ url: "compiler-options/errors.html"
+ description: "A new engine for more user-friendly error messages, printing chains of dependent implicits and colored found/required type diffs."
+ - title: Optimizer
+ by: Lukas Rytz and Andrew Marki
+ icon: cog
+ url: "compiler-options/optimizer.html"
+ description: "The compiler can perform various optimizations."
- category: Legacy
description: "Guides covering features no longer relevant to recent Scala versions (2.12+)."
overviews:
- - title: The Scala Actors Migration Guide
- by: Vojin Jovanovic and Philipp Haller
- icon: truck
- url: "core/actors-migration-guide.html"
- description: "To ease the migration from Scala Actors to Akka we have provided the Actor Migration Kit (AMK). The AMK consists of an extension to Scala Actors which is enabled by including the scala-actors-migration.jar on a project’s classpath. In addition, Akka 2.1 includes features, such as the ActorDSL singleton, which enable a simpler conversion of code using Scala Actors to Akka. The purpose of this document is to guide users through the migration process and explain how to use the AMK."
- - title: The Scala Actors API
- by: Philipp Haller and Stephen Tu
- icon: users
- url: "core/actors.html"
- description: "This guide describes the API of the scala.actors package of Scala 2.8/2.9. The organization follows groups of types that logically belong together. The trait hierarchy is taken into account to structure the individual sections. The focus is on the run-time behavior of the various methods that these traits define, thereby complementing the existing Scaladoc-based API documentation."
- label-color: "#899295"
- label-text: deprecated
- title: Scala 2.8 to 2.12’s Collections
by: Martin Odersky
icon: sitemap
diff --git a/_data/setup-scala.yml b/_data/setup-scala.yml
new file mode 100644
index 0000000000..cda4c2361b
--- /dev/null
+++ b/_data/setup-scala.yml
@@ -0,0 +1,6 @@
+linux-x86-64: curl -fL https://github.com/coursier/coursier/releases/latest/download/cs-x86_64-pc-linux.gz | gzip -d > cs && chmod +x cs && ./cs setup
+linux-arm64: curl -fL https://github.com/VirtusLab/coursier-m1/releases/latest/download/cs-aarch64-pc-linux.gz | gzip -d > cs && chmod +x cs && ./cs setup
+macOS-x86-64: curl -fL https://github.com/coursier/coursier/releases/latest/download/cs-x86_64-apple-darwin.gz | gzip -d > cs && chmod +x cs && (xattr -d com.apple.quarantine cs || true) && ./cs setup
+macOS-arm64: curl -fL https://github.com/VirtusLab/coursier-m1/releases/latest/download/cs-aarch64-apple-darwin.gz | gzip -d > cs && chmod +x cs && (xattr -d com.apple.quarantine cs || true) && ./cs setup
+macOS-brew: brew install coursier && coursier setup
+windows-link: https://github.com/coursier/coursier/releases/latest/download/cs-x86_64-pc-win32.zip
diff --git a/_data/sip-data.yml b/_data/sip-data.yml
index 6a6b19fe68..0a351b24da 100644
--- a/_data/sip-data.yml
+++ b/_data/sip-data.yml
@@ -1,27 +1,47 @@
+design:
+ color: "#839496"
+ text: "Design"
+
+implementation:
+ color: "#839496"
+ text: "Implementation"
+
+submitted:
+ color: "#2aa198"
+ text: "Submitted"
+
under-review:
color: "#b58900"
text: "Under Review"
-pending:
+vote-requested:
color: "#b58900"
- text: "Pending"
-
-dormant:
- color: "#839496"
- text: "Dormant"
+ text: "Vote Requested"
-under-revision:
- color: "#2aa198"
- text: "Under Revision"
+waiting-for-implementation:
+ color: "#b58900"
+ text: "Waiting for Implementation"
accepted:
color: "#859900"
text: "Accepted"
-complete:
+shipped:
color: "#859900"
- text: "Complete"
+ text: "Shipped"
rejected:
color: "#dc322f"
text: "Rejected"
+
+withdrawn:
+ color: "#839496"
+ text: "Withdrawn"
+
+accept:
+ color: "#859900"
+ text: "Accept"
+
+reject:
+ color: "#dc322f"
+ text: "Reject"
diff --git a/_data/translations.yml b/_data/translations.yml
index 56d0fd59cf..80ab5afc1c 100644
--- a/_data/translations.yml
+++ b/_data/translations.yml
@@ -1,2 +1,2 @@
tour:
- languages: [ba, es, ko, pt-br, pl, zh-cn, th, ru, ja]
+ languages: [ba, es, fr, ko, pt-br, pl, zh-cn, th, ru, ja]
diff --git a/_de/tutorials/scala-for-java-programmers.md b/_de/tutorials/scala-for-java-programmers.md
index e4d64108b7..9055d7caea 100644
--- a/_de/tutorials/scala-for-java-programmers.md
+++ b/_de/tutorials/scala-for-java-programmers.md
@@ -23,7 +23,7 @@ einfach ist, eignet es sich sehr gut, Scalas Funktionsweise zu demonstrieren, oh
über die Sprache wissen muss.
object HalloWelt {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
println("Hallo, Welt!")
}
}
@@ -93,7 +93,7 @@ Klassen der Java-Pakete importieren:
import java.text.DateFormat._
object FrenchDate {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val now = new Date
val df = getDateInstance(LONG, Locale.FRANCE)
println(df format now)
@@ -183,7 +183,7 @@ einmal pro Sekunde aus.
println("Die Zeit vergeht wie im Flug.")
}
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
oncePerSecond(timeFlies)
}
}
@@ -209,7 +209,7 @@ Variante des obigen Timer-Programmes verwendet eine anonyme Funktion anstatt der
}
}
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
oncePerSecond(() => println("Die Zeit vergeht wie im Flug."))
}
}
@@ -256,7 +256,7 @@ Ein Problem der obigen Methoden `re` und `im` ist, dass man, um sie zu verwenden
Klammerpaar hinter ihren Namen anhängen muss:
object ComplexNumbers {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val c = new Complex(1.2, 3.4)
println("imaginary part: " + c.im())
}
@@ -433,7 +433,7 @@ noch aus. Zu diesem Zweck soll eine `main`-Methode dienen, die den Ausdruck `(x+
Beispiel verwendet: zuerst wird der Wert in der Umgebung `{ x -> 5, y -> 7 }` berechnet und darauf
die beiden partiellen Ableitungen gebildet:
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val exp: Tree = Sum(Sum(Var("x"),Var("x")),Sum(Const(7),Var("y")))
val env: Environment = {
case "x" => 5
@@ -597,7 +597,7 @@ Um diese Referenz-Klasse zu verwenden, muss der generische Typ bei der Erzeugung
angegeben werden. Für einen Ganzzahl-Container soll folgendes Beispiel dienen:
object IntegerReference {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val cell = new Reference[Int]
cell.set(13)
println("Reference contains the half of " + (cell.get * 2))
diff --git a/_es/overviews/core/actors.md b/_es/overviews/core/actors.md
deleted file mode 100644
index ef49675e1e..0000000000
--- a/_es/overviews/core/actors.md
+++ /dev/null
@@ -1,495 +0,0 @@
----
-layout: singlepage-overview
-title: API de actores en Scala
-
-partof: actors
-
-language: es
----
-
-**Philipp Haller and Stephen Tu**
-
-**Traducción e interpretación: Miguel Ángel Pastor Olivar**
-
-## Introducción
-
-La presente guía describe el API del paquete `scala.actors` de Scala 2.8/2.9. El documento se estructura en diferentes grupos lógicos. La jerarquía de "traits" es tenida en cuenta para llevar a cabo la estructuración de las secciones individuales. La atención se centra en el comportamiento exhibido en tiempo de ejecución por varios de los métodos presentes en los traits anteriores, complementando la documentación existente en el Scaladoc API.
-
-## Traits de actores: Reactor, ReplyReactor, y Actor
-
-### The Reactor trait
-
-`Reactor` es el padre de todos los traits relacionados con los actores. Heredando de este trait podremos definir actores con una funcionalidad básica de envío y recepción de mensajes.
-
-El comportamiento de un `Reactor` se define mediante la implementación de su método `act`. Este método es ejecutado una vez el `Reactor` haya sido iniciado mediante la invocación del método `start`, retornando el `Reactor`. El método `start`es *idempotente*, lo cual significa que la invocación del mismo sobre un actor que ya ha sido iniciado no surte ningún efecto.
-
-El trait `Reactor` tiene un parámetro de tipo `Msg` el cual determina el tipo de mensajes que un actor es capaz de recibir.
-
-La invocación del método `!` de un `Reactor` envía un mensaje al receptor. La operación de envío de un mensaje mediante el operador `!` es asíncrona por lo que el actor que envía el mensaje no se bloquea esperando a que el mensaje sea recibido sino que su ejecución continua de manera inmediata. Por ejemplo, `a ! msg` envia `msg` a `a`. Todos los actores disponen de un *buzón* encargado de regular los mensajes entrantes hasta que son procesados.
-
-El trait `Reactor` trait también define el método `forward`. Este método es heredado de `OutputChannel` y tiene el mismo efecto que el método `!`. Aquellos traits que hereden de `Reactor`, en particular el trait `ReplyActor`, sobreescriben este método para habilitar lo que comunmente se conocen como *"implicit reply destinations"* (ver a continuación)
-
-Un `Reactor` recibe mensajes utilizando el método `react`. Este método espera un argumento de tipo `PartialFunction[Msg, Unit]` el cual define cómo los mensajes de tipo `Msg` son tratados una vez llegan al buzón de un actor. En el siguiente ejemplo, el actor espera recibir la cadena "Hello", para posteriomente imprimir un saludo:
-
- react {
- case "Hello" => println("Hi there")
- }
-
-La invocación del método `react` nunca retorna. Por tanto, cualquier código que deba ejecutarse tras la recepción de un mensaje deberá ser incluido dentro de la función parcial pasada al método `react`. Por ejemplo, dos mensajes pueden ser recibidos secuencialmente mediante la anidación de dos llamadas a `react`:
-
- react {
- case Get(from) =>
- react {
- case Put(x) => from ! x
- }
- }
-
-El trait `Reactor` también ofrece una serie de estructuras de control que facilitan la programación utilizando el mecanismo de `react`.
-
-#### Terminación y estados de ejecución
-
-La ejecución de un `Reactor` finaliza cuando el cuerpo del método `act` ha sido completado. Un `Reactor` también pueden terminarse a si mismo de manera explícita mediante el uso del método `exit`. El tipo de retorno de `exit` es `Nothing`, dado que `exit` siempre dispara una excepción. Esta excepción únicamente se utiliza de manera interna y nunca debería ser capturada.
-
-Un `Reactor` finalizado pueden ser reiniciado mediante la invocación de su método `restart`. La invocación del método anterior sobre un `Reactor` que no ha terminado su ejecución lanza una excepción de tipo `IllegalStateException`. El reinicio de un actor que ya ha terminado provoca que el método `act` se ejecute nuevamente.
-
-El tipo `Reactor` define el método `getState`, el cual retorna, como un miembro de la enumeración `Actor.State`, el estado actual de la ejecución del actor. Un actor que todavía no ha sido iniciado se encuentra en el estado `Actor.State.New`. Si el actor se está ejecutando pero no está esperando por ningún mensaje su estado será `Actor.State.Runnable`. En caso de que el actor haya sido suspendido mientras espera por un mensaje estará en el estado `Actor.State.Suspended`. Por último, un actor ya terminado se encontrará en el estado `Actor.State.Terminated`.
-
-#### Manejo de excepciones
-
-El miembro `exceptionHandler` permite llevar a cabo la definición de un manejador de excepciones que estará habilitado durante toda la vida del `Reactor`:
-
- def exceptionHandler: PartialFunction[Exception, Unit]
-
-Este manejador de excepciones (`exceptionHandler`) retorna una función parcial que se utiliza para gestionar excepciones que no hayan sido tratadas de ninguna otra manera. Siempre que una excepción se propague fuera del método `act` de un `Reactor` el manejador anterior será aplicado a dicha excepción, permitiendo al actor ejecutar código de limpieza antes de que se termine. Nótese que la visibilidad de `exceptionHandler` es `protected`.
-
-El manejo de excepciones mediante el uso de `exceptionHandler` encaja a la perfección con las estructuras de control utilizadas para programas con el método `react`. Siempre que una excepción es manejada por la función parcial retornada por `excepctionHandler`, la ejecución continua con la "closure" actual:
-
- loop {
- react {
- case Msg(data) =>
- if (cond) // process data
- else throw new Exception("cannot process data")
- }
- }
-
-Assumiendo que `Reactor` sobreescribe el atributo `exceptionHandler`, tras el lanzamiento de una excepción en el cuerpo del método `react`, y una vez ésta ha sido gestionada, la ejecución continua con la siguiente iteración del bucle.
-
-### The ReplyReactor trait
-
-El trait `ReplyReactor` extiende `Reactor[Any]` y sobrescribe y/o añade los siguientes métodos:
-
-- El método `!` es sobrescrito para obtener una referencia al actor
- actual (el emisor). Junto al mensaje actual, la referencia a dicho
- emisor es enviada al buzón del actor receptor. Este último dispone de
- acceso al emisor del mensaje mediante el uso del método `sender` (véase más abajo).
-
-- El método `forward` es sobrescrito para obtener una referencia al emisor
- del mensaje que actualmente está siendo procesado. Junto con el mensaje
- actual, esta referencia es enviada como el emisor del mensaje actual.
- Como consuencia de este hecho, `forward` nos permite reenviar mensajes
- en nombre de actores diferentes al actual.
-
-- El método (añadido) `sender` retorna el emisor del mensaje que está siendo
- actualmente procesado. Puesto que un mensaje puede haber sido reenviado,
- `sender` podría retornar un actor diferente al que realmente envió el mensaje.
-
-- El método (añadido) `reply` envía una respuesta al emisor del último mensaje.
- `reply` también es utilizado para responder a mensajes síncronos o a mensajes
- que han sido enviados mediante un "future" (ver más adelante).
-
-- El método (añadido) `!?` ofrece un *mecanismo síncrono de envío de mensajes*.
- La invocación de `!?` provoca que el actor emisor del mensaje se bloquee hasta
- que se recibe una respuesta, momento en el cual retorna dicha respuesta. Existen
- dos variantes sobrecargadas. La versión con dos parámetros recibe un argumento
- adicional que representa el tiempo de espera (medido en milisegundos) y su tipo
- de retorno es `Option[Any]` en lugar de `Any`. En caso de que el emisor no
- reciba una respuesta en el periodo de espera establecido, el método `!?` retornará
- `None`; en otro caso retornará la respuesta recibida recubierta con `Some`.
-
-- Los métodos (añadidos) `!!` son similares al envío síncrono de mensajes en el sentido de
- que el receptor puede enviar una respuesta al emisor del mensaje. Sin embargo, en lugar
- de bloquear el actor emisor hasta que una respuesta es recibida, retornan una instancia de
- `Future`. Esta última puede ser utilizada para recuperar la respuesta del receptor una
- vez se encuentre disponible; asimismo puede ser utilizada para comprobar si la respuesta
- está disponible sin la necesidad de bloquear el emisor. Existen dos versiones sobrecargadas.
- La versión que acepta dos parámetros recibe un argumento adicional de tipo
- `PartialFunction[Any, A]`. Esta función parcial es utilizada para realizar el post-procesado de
- la respuesta del receptor. Básicamente, `!!` retorna un "future" que aplicará la anterior
- función parcial a la repuesta (una vez recibida). El resultado del "future" es el resultado
- de este post-procesado.
-
-- El método (añadido) `reactWithin` permite llevar a cabo la recepción de mensajes en un periodo
- determinado de tiempo. En comparación con el método `react`, recibe un parámetro adicional,
- `msec`, el cual representa el periodo de tiempo, expresado en milisegundos, hasta que el patrón `TIMEOUT`
- es satisfecho (`TIMEOUT` es un "case object" presente en el paquete `scala.actors`). Ejemplo:
-
- reactWithin(2000) {
- case Answer(text) => // process text
- case TIMEOUT => println("no answer within 2 seconds")
- }
-
-- El método `reactWithin` también permite realizar accesos no bloqueantes al buzón. Si
- especificamos un tiempo de espera de 0 milisegundos, primeramente el buzón será escaneado
- en busca de un mensaje que concuerde. En caso de que no exista ningún mensaje concordante
- tras el primer escaneo, el patrón `TIMEOUT` será satisfecho. Por ejemplo, esto nos permite
- recibir determinado tipo de mensajes donde unos tienen una prioridad mayor que otros:
-
- reactWithin(0) {
- case HighPriorityMsg => // ...
- case TIMEOUT =>
- react {
- case LowPriorityMsg => // ...
- }
- }
-
- En el ejemplo anterior, el actor procesa en primer lugar los mensajes `HighPriorityMsg` aunque
- exista un mensaje `LowPriorityMsg` más antiguo en el buzón. El actor sólo procesará mensajes
- `LowPriorityMsg` en primer lugar en aquella situación donde no exista ningún `HighProrityMsg`
- en el buzón.
-
-Adicionalmente, el tipo `ReplyActor` añade el estado de ejecución `Actor.State.TimedSuspended`. Un actor suspendido, esperando la recepción de un mensaje mediante el uso de `reactWithin` se encuentra en dicho estado.
-
-### El trait Actor
-
-El trait `Actor` extiende de `ReplyReactor` añadiendo y/o sobrescribiendo los siguientes miembros:
-
-- El método (añadido) `receive` se comporta del mismo modo que `react`, con la excepción
- de que puede retornar un resultado. Este hecho se ve reflejado en la definición del tipo,
- que es polimórfico en el tipo del resultado: `def receive[R](f: PartialFunction[Any, R]): R`.
- Sin embargo, la utilización de `receive` hace que el uso del actor
- sea más pesado, puesto que el hilo subyacente es bloqueado mientras
- el actor está esperando por la respuesta. El hilo bloqueado no está
- disponible para ejecutar otros actores hasta que la invocación del
- método `receive` haya retornado.
-
-- El método (añadido) `link` permite a un actor enlazarse y desenlazarse de otro
- actor respectivamente. El proceso de enlazado puede utilizarse para monitorizar
- y responder a la terminación de un actor. En particular, el proceso de enlazado
- afecta al comportamiento mostrado en la ejecución del método `exit` tal y como
- se escribe en el la documentación del API del trait `Actor`.
-
-- El atributo `trapExit` permite responder a la terminación de un actor enlazado,
- independientemente de los motivos de su terminación (es decir, carece de importancia
- si la terminación del actor es normal o no). Si `trapExit` toma el valor cierto en
- un actor, este nunca terminará por culpa de los actores enlazados. En cambio, siempre
- y cuando uno de sus actores enlazados finalice, recibirá un mensaje de tipo `Exit`.
- `Exit` es una "case class" que presenta dos atributos: `from` referenciando al actor
- que termina y `reason` conteniendo los motivos de la terminación.
-
-#### Terminación y estados de ejecución
-
-Cuando la ejecución de un actor finaliza, el motivo de dicha terminación puede ser
-establecida de manera explícita mediante la invocación de la siguiente variante
-del método `exit`:
-
- def exit(reason: AnyRef): Nothing
-
-Un actor cuyo estado de terminación es diferente del símbolo `'normal` propaga
-los motivos de su terminación a todos aquellos actores que se encuentren enlazados
-a él. Si el motivo de la terminación es una excepción no controlada, el motivo de
-finalización será una instancia de la "case class" `UncaughtException`.
-
-El trait `Actor` incluye dos nuevos estados de ejecución. Un actor que se encuentra
-esperando la recepción de un mensaje mediante la utilización del método `receive` se
-encuentra en el método `Actor.State.Blocked`. Un actor esperado la recepción de un
-mensaje mediante la utilización del método `receiveWithin` se encuentra en el estado
-`Actor.State.TimeBlocked`.
-
-## Estructuras de control
-
-El trait `Reactor` define una serie de estructuras de control que simplifican el mecanismo
-de programación con la función sin retorno `react`. Normalmente, una invocación al método
-`react` no retorna nunca. Si el actor necesita ejecutar código a continuación de la invocación
-anterior, tendrá que pasar, de manera explícita, dicho código al método `react` o utilizar
-algunas de las estructuras que encapsulan este comportamiento.
-
-La estructura de control más basica es `andThen`. Permite registrar una `closure` que será
-ejecutada una vez el actor haya terminado la ejecución de todo lo demas.
-
- actor {
- {
- react {
- case "hello" => // processing "hello"
- }: Unit
- } andThen {
- println("hi there")
- }
- }
-
-Por ejemplo, el actor anterior imprime un saludo tras realizar el procesado
-del mensaje `hello`. Aunque la invocación del método `react` no retorna,
-podemos utilizar `andThen` para registrar el código encargado de imprimir
-el saludo a continuación de la ejecución del actor.
-
-Nótese que existe una *atribución de tipo* a continuación de la invocación
-de `react` (`:Unit`). Básicamente, nos permite tratar el resultado de
-`react` como si fuese de tipo `Unit`, lo cual es legal, puesto que el resultado
-de una expresión siempre se puede eliminar. Es necesario llevar a cabo esta operación
-dado que `andThen` no puede ser un miembro del tipo `Unit`, que es el tipo del resultado
-retornado por `react`. Tratando el tipo de resultado retornado por `react` como
-`Unit` permite llevar a cabo la aplicación de una conversión implícita la cual
-hace que el miembro `andThen` esté disponible.
-
-El API ofrece unas cuantas estructuras de control adicionales:
-
-- `loop { ... }`. Itera de manera indefinidia, ejecutando el código entre
-las llaves en cada una de las iteraciones. La invocación de `react` en el
-cuerpo del bucle provoca que el actor se comporte de manera habitual ante
-la llegada de un nuevo mensaje. Posteriormente a la recepción del mensaje,
-la ejecución continua con la siguiente iteración del bucle actual.
-
-- `loopWhile (c) { ... }`. Ejecuta el código entre las llaves mientras la
-condición `c` tome el valor `true`. La invocación de `react` en el cuerpo
-del bucle ocasiona el mismo efecto que en el caso de `loop`.
-
-- `continue`. Continua con la ejecución de la closure actual. La invocación
-de `continue` en el cuerpo de un `loop`o `loopWhile` ocasionará que el actor
-termine la iteración en curso y continue con la siguiente. Si la iteración en
-curso ha sido registrada utilizando `andThen`, la ejecución continua con la
-segunda "closure" pasada como segundo argumento a `andThen`.
-
-Las estructuras de control pueden ser utilizadas en cualquier parte del cuerpo
-del método `act` y en los cuerpos de los métodos que, transitivamente, son
-llamados por `act`. Aquellos actores creados utilizando la sintáxis `actor { ... }`
-pueden importar las estructuras de control desde el objeto `Actor`.
-
-#### Futures
-
-Los traits `RepyActor` y `Actor` soportan operaciones de envío de mensajes
-(métodos `!!`) que, de manera inmediata, retornan un *future*. Un *future*,
-es una instancia del trait `Future` y actúa como un manejador que puede
-ser utilizado para recuperar la respuesta a un mensaje "send-with-future".
-
-El emisor de un mensaje "send-with-future" puede esperar por la respuesta del
-future *aplicando* dicha future. Por ejemplo, el envío de un mensaje mediante
-`val fut = a !! msg` permite al emisor esperar por el resultado del future
-del siguiente modo: `val res = fut()`.
-
-Adicionalmente, utilizando el método `isSet`, un `Future` puede ser consultado
-de manera no bloqueante para comprobar si el resultado está disponible.
-
-Un mensaje "send-with-future" no es el único modo de obtener una referencia a
-un future. Estos pueden ser creados utilizando el método `future`. En el siguiente
-ejemplo, `body` se ejecuta de manera concurrente, retornando un future como
-resultado.
-
- val fut = Future { body }
- // ...
- fut() // wait for future
-
-Lo que hace especial a los futures en el contexto de los actores es la posibilidad
-de recuperar su resultado utilizando las operaciones estándar de actores de
-recepción de mensajes como `receive`, etc. Además, es posible utilizar las operaciones
-basadas en eventos `react`y `reactWithin`. Esto permite a un actor esperar por el
-resultado de un future sin la necesidad de bloquear el hilo subyacente.
-
-Las operaciones de recepción basadas en actores están disponibles a través del
-atributo `inputChannel` del future. Dado un future de tipo `Future[T]`, el tipo
-de `inputChannel` es `InputChannel[T]`. Por ejemplo:
-
- val fut = a !! msg
- // ...
- fut.inputChannel.react {
- case Response => // ...
- }
-
-## Canales
-
-Los canales pueden ser utilizados para simplificar el manejo de mensajes
-que presentan tipos diferentes pero que son enviados al mismo actor. La
-jerarquía de canales se divide en `OutputChannel` e `InputChannel`.
-
-Los `OutputChannel` pueden ser utilizados para enviar mensajes. Un
-`OutputChannel` `out` soporta las siguientes operaciones:
-
-- `out ! msg`. Envía el mensaje `msg` a `out` de manera asíncrona. Cuando `msg`
- es enviado directamente a un actor se incluye un referencia al actor emisor
- del mensaje.
-
-- `out forward msg`. Reenvía el mensaje `msg` a `out` de manera asíncrona.
- El actor emisor se determina en el caso en el que `msg` es reenviado a
- un actor.
-
-- `out.receiver`. Retorna el único actor que está recibiendo mensajes que están
- siendo enviados al canal `out`.
-
-- `out.send(msg, from)`. Envía el mensaje `msg` a `out` de manera asíncrona,
- proporcionando a `from` como el emisor del mensaje.
-
-Nótese que el trait `OutputChannel` tiene un parámetro de tipo que especifica el
-tipo de los mensajes que pueden ser enviados al canal (utilizando `!`, `forward`,
-y `send`). Este parámetro de tipo es contra-variante:
-
- trait OutputChannel[-Msg]
-
-Los actores pueden recibir mensajes de un `InputChannel`. Del mismo modo que
-`OutputChannel`, el trait `InputChannel` presenta un parámetro de tipo que
-especifica el tipo de mensajes que pueden ser recibidos por el canal. En este caso,
-el parámetro de tipo es covariante:
-
- trait InputChannel[+Msg]
-
-Un `InputChannel[Msg]` `in` soportal las siguientes operaciones.
-
-- `in.receive { case Pat1 => ... ; case Patn => ... }` (y de manera similar,
- `in.receiveWithin`) recibe un mensaje proveniente de `in`. La invocación
- del método `receive` en un canal de entrada presenta la misma semántica
- que la operación estándar de actores `receive`. La única diferencia es que
- la función parcial pasada como argumento tiene tipo `PartialFunction[Msg, R]`
- donde `R` es el tipo de retorno de `receive`.
-
-- `in.react { case Pat1 => ... ; case Patn => ... }` (y de manera similar,
- `in.reactWithin`). Recibe un mensaje de `in` utilizando la operación basada en
- eventos `react`. Del mismo modo que la operación `react` en actores, el tipo
- de retorno es `Nothing`, indicando que las invocaciones de este método nunca
- retornan. Al igual que la operación `receive` anterior, la función parcial
- que se pasa como argumento presenta un tipo más específico:
-
- PartialFunction[Msg, Unit]
-
-### Creando y compartiendo canales
-
-Los canales son creados utilizando la clase concreta `Channel`. Esta clase extiende
-de `InputChannel` y `OutputChannel`. Un canal pueden ser compartido haciendo dicho
-canal visible en el ámbito de múltiples actores o enviándolo como mensaje.
-
-El siguiente ejemplo muestra la compartición mediante publicación en ámbitos:
-
- actor {
- var out: OutputChannel[String] = null
- val child = actor {
- react {
- case "go" => out ! "hello"
- }
- }
- val channel = new Channel[String]
- out = channel
- child ! "go"
- channel.receive {
- case msg => println(msg.length)
- }
- }
-
-La ejecución de este ejemplo imprime la cadena "5" en la consola. Nótese que el
-actor `child` únicamente tiene acceso a `out`, que es un `OutputChannel[String]`.
-La referencia al canal, la cual puede ser utilizada para llevar a cabo la recepción
-de mensajes, se encuentra oculta. Sin embargo, se deben tomar precauciones y
-asegurarse que el canal de salida es inicializado con un canal concreto antes de que
-`child` le envíe ningún mensaje. En el ejemplo que nos ocupa, esto es llevado a cabo
-mediante el mensaje "go". Cuando se está recibiendo de `channel` utilizando el método
-`channel.receive` podemos hacer uso del hecho que `msg` es de tipo `String`, y por
-lo tanto tiene un miembro `length`.
-
-Una alternativa a la compartición de canales es enviarlos a través de mensajes.
-El siguiente fragmento de código muestra un sencillo ejemplo de aplicación:
-
- case class ReplyTo(out: OutputChannel[String])
-
- val child = actor {
- react {
- case ReplyTo(out) => out ! "hello"
- }
- }
-
- actor {
- val channel = new Channel[String]
- child ! ReplyTo(channel)
- channel.receive {
- case msg => println(msg.length)
- }
- }
-
-La "case class" `ReplyTo` es un tipo de mensajes que utilizamos para distribuir
-una referencia a un `OutputChannel[String]`. Cuando el actor `child` recibe un
-mensaje de tipo `ReplyTo` éste envía una cadena a su canal de salida. El segundo
-actor recibe en el canal del mismo modo que anteriormente.
-
-## Planificadores
-
-Un `Reactor`(o una instancia de uno de sus subtipos) es ejecutado utilizando un
-*planificador*. El trait `Reactor` incluye el miembro `scheduler` el cual retorna el
-planificador utilizado para ejecutar sus instancias:
-
- def scheduler: IScheduler
-
-La plataforma de ejecución ejecuta los actores enviando tareas al planificador mediante
-el uso de los métodos `execute` definidos en el trait `IScheduler`. La mayor parte
-del resto de métodos definidos en este trait únicamente adquieren cierto protagonismo
-cuando se necesita implementar un nuevo planificador desde cero; algo que no es necesario
-en muchas ocasiones.
-
-Los planificadores por defecto utilizados para ejecutar instancias de `Reactor` y
-`Actor` detectan cuando los actores han finalizado su ejecución. En el momento que esto
-ocurre, el planificador se termina a si mismo (terminando con cualquier hilo que estuviera
-en uso por parte del planificador). Sin embargo, algunos planificadores como el
-`SingleThreadedScheduler` (definido en el paquete `scheduler`) necesita ser terminado de
-manera explícita mediante la invocación de su método `shutdown`).
-
-La manera más sencilla de crear un planificador personalizado consisten en extender la clase
-`SchedulerAdapter`, implementando el siguiente método abstracto:
-
- def execute(fun: => Unit): Unit
-
-Por norma general, una implementación concreata utilizaría un pool de hilos para llevar a cabo
-la ejecución del argumento por nombre `fun`.
-
-## Actores remotos
-
-Esta sección describe el API de los actores remotos. Su principal interfaz es el objecto
-[`RemoteActor`](https://www.scala-lang.org/api/2.9.1/scala/actors/remote/RemoteActor$.html) definido
-en el paquete `scala.actors.remote`. Este objeto facilita el conjunto de métodos necesarios para crear
-y establecer conexiones a instancias de actores remotos. En los fragmentos de código que se muestran a
-continuación se asume que todos los miembros de `RemoteActor` han sido importados; la lista completa
-de importaciones utilizadas es la siguiente:
-
- import scala.actors._
- import scala.actors.Actor._
- import scala.actors.remote._
- import scala.actors.remote.RemoteActor._
-
-### Iniciando actores remotos
-
-Un actore remot es identificado de manera unívoca por un
-[`Symbol`](https://www.scala-lang.org/api/2.9.1/scala/Symbol.html). Este símbolo es único para la instancia
-de la máquina virual en la que se está ejecutando un actor. Un actor remoto identificado con el nombre
-`myActor` puede ser creado del siguiente modo.
-
- class MyActor extends Actor {
- def act() {
- alive(9000)
- register('myActor, self)
- // ...
- }
- }
-
-Nótese que el nombre únicamente puede ser registrado con un único actor al mismo tiempo.
-Por ejemplo, para registrar el actor *A* como `'myActor` y posteriormente registrar otro
-actor *B* como `'myActor`, debería esperar hasta que *A* haya finalizado. Este requisito
-aplica a lo largo de todos los puertos, por lo que registrando a *B* en un puerto diferente
-no sería suficiente.
-
-### Connecting to remote actors
-
-Establecer la conexión con un actor remoto es un proceso simple. Para obtener una referencia remota
-a un actor remoto que está ejecutándose en la máquina `myMachine` en el puerto 8000 con el nombre
-`'anActor`, tendremos que utilizar `select`del siguiente modo:
-
- val myRemoteActor = select(Node("myMachine", 8000), 'anActor)
-
-El actor retornado por `select` es de tipo `AbstractActor`, que proporciona esencialmente el mismo
-interfaz que un actor normal, y por lo tanto es compatible con las habituales operaciones de envío
-de mensajes:
-
- myRemoteActor ! "Hello!"
- receive {
- case response => println("Response: " + response)
- }
- myRemoteActor !? "What is the meaning of life?" match {
- case 42 => println("Success")
- case oops => println("Failed: " + oops)
- }
- val future = myRemoteActor !! "What is the last digit of PI?"
-
-Nótese que la operación `select` es perezosa; no inicializa ninguna conexión de red. Simplemente crea
-una nueva instancia de `AbstractActor` que está preparada para iniciar una nueva conexión de red en el
-momento en que sea necesario (por ejemplo cuando el método '!' es invocado).
diff --git a/_es/overviews/parallel-collections/architecture.md b/_es/overviews/parallel-collections/architecture.md
index 8e60e87a59..138a5dee08 100644
--- a/_es/overviews/parallel-collections/architecture.md
+++ b/_es/overviews/parallel-collections/architecture.md
@@ -87,7 +87,7 @@ de la librería de colecciones secuenciales -- de hecho, "replican" los correspo
traits presentes en el framework de colecciones secuenciales, tal y como se muestra
a continuación.
-[]({{ site.baseurl }}/resources/images/parallel-collections-hierarchy.png)
+[]({{ site.baseurl }}/resources/images/parallel-collections-hierarchy.png)
Jerarquía de clases de las librerías de colecciones secuenciales y paralelas de Scala
diff --git a/_es/tour/abstract-type-members.md b/_es/tour/abstract-type-members.md
index ffcf7fd482..1e9afc50d7 100644
--- a/_es/tour/abstract-type-members.md
+++ b/_es/tour/abstract-type-members.md
@@ -14,56 +14,60 @@ previous-page: tour-of-scala
En Scala, las cases son parametrizadas con valores (los parámetros de construcción) y con tipos (si las clases son [genéricas](generic-classes.html)). Por razones de consistencia, no es posible tener solo valores como miembros de objetos; tanto los tipos como los valores son miembros de objetos. Además, ambos tipos de miembros pueden ser concretos y abstractos.
A continuación un ejemplo el cual define de forma conjunta una asignación de valor tardía y un tipo abstracto como miembros del [trait](traits.html) `Buffer`.
- trait Buffer {
- type T
- val element: T
- }
+```scala mdoc
+trait Buffer {
+ type T
+ val element: T
+}
+```
Los *tipos abstractos* son tipos los cuales su identidad no es precisamente conocida. En el ejemplo anterior, lo único que sabemos es que cada objeto de la clase `Buffer` tiene un miembro de tipo `T`, pero la definición de la clase `Buffer` no revela qué tipo concreto se corresponde con el tipo `T`. Tal como las definiciones de valores, es posible sobrescribir las definiciones de tipos en subclases. Esto permite revelar más información acerca de un tipo abstracto al acotar el tipo ligado (el cual describe las posibles instancias concretas del tipo abstracto).
En el siguiente programa derivamos la clase `SeqBuffer` la cual nos permite almacenar solamente sequencias en el buffer al estipular que el tipo `T` tiene que ser un subtipo de `Seq[U]` para un nuevo tipo abstracto `U`:
- abstract class SeqBuffer extends Buffer {
- type U
- type T <: Seq[U]
- def length = element.length
- }
+```scala mdoc
+abstract class SeqBuffer extends Buffer {
+ type U
+ type T <: Seq[U]
+ def length = element.length
+}
+```
Traits o [clases](classes.html) con miembros de tipos abstractos son generalmente usados en combinación con instancias de clases anónimas. Para ilustrar este concepto veremos un programa el cual trata con un buffer de sequencia que se remite a una lista de enteros.
- abstract class IntSeqBuffer extends SeqBuffer {
- type U = Int
- }
+```scala mdoc
+abstract class IntSeqBuffer extends SeqBuffer {
+ type U = Int
+}
- object AbstractTypeTest1 extends App {
- def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
- new IntSeqBuffer {
- type T = List[U]
- val element = List(elem1, elem2)
- }
- val buf = newIntSeqBuf(7, 8)
- println("length = " + buf.length)
- println("content = " + buf.element)
- }
+def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
+ new IntSeqBuffer {
+ type T = List[U]
+ val element = List(elem1, elem2)
+ }
+val buf = newIntSeqBuf(7, 8)
+println("length = " + buf.length)
+println("content = " + buf.element)
+```
El tipo retornado por el método `newIntSeqBuf` está ligado a la especialización del trait `Buffer` en el cual el tipo `U` es ahora equivalente a `Int`. Existe un tipo alias similar en la instancia de la clase anónima dentro del cuerpo del método `newIntSeqBuf`. En ese lugar se crea una nueva instancia de `IntSeqBuffer` en la cual el tipo `T` está ligado a `List[Int]`.
Es necesario notar que generalmente es posible transformar un tipo abstracto en un tipo paramétrico de una clase y viceversa. A continuación se muestra una versión del código anterior el cual solo usa tipos paramétricos.
- abstract class Buffer[+T] {
- val element: T
- }
- abstract class SeqBuffer[U, +T <: Seq[U]] extends Buffer[T] {
- def length = element.length
- }
- object AbstractTypeTest2 extends App {
- def newIntSeqBuf(e1: Int, e2: Int): SeqBuffer[Int, Seq[Int]] =
- new SeqBuffer[Int, List[Int]] {
- val element = List(e1, e2)
- }
- val buf = newIntSeqBuf(7, 8)
- println("length = " + buf.length)
- println("content = " + buf.element)
- }
+```scala mdoc:reset
+abstract class Buffer[+T] {
+ val element: T
+}
+abstract class SeqBuffer[U, +T <: Seq[U]] extends Buffer[T] {
+ def length = element.length
+}
+def newIntSeqBuf(e1: Int, e2: Int): SeqBuffer[Int, Seq[Int]] =
+ new SeqBuffer[Int, List[Int]] {
+ val element = List(e1, e2)
+ }
+val buf = newIntSeqBuf(7, 8)
+println("length = " + buf.length)
+println("content = " + buf.element)
+```
Nótese que es necesario usar [variance annotations](variances.html) aquí; de otra manera no sería posible ocultar el tipo implementado por la secuencia concreta del objeto retornado por `newIntSeqBuf`. Además, existen casos en los cuales no es posible remplazar tipos abstractos con tipos parametrizados.
diff --git a/_es/tour/annotations.md b/_es/tour/annotations.md
index c49cbe3e8c..37dd912f97 100644
--- a/_es/tour/annotations.md
+++ b/_es/tour/annotations.md
@@ -6,7 +6,7 @@ partof: scala-tour
num: 3
language: es
-next-page: classes
+next-page: packages-and-imports
previous-page: abstract-type-members
---
diff --git a/_es/tour/automatic-closures.md b/_es/tour/automatic-closures.md
deleted file mode 100644
index bb26c5a665..0000000000
--- a/_es/tour/automatic-closures.md
+++ /dev/null
@@ -1,65 +0,0 @@
----
-layout: tour
-title: Construcción de closures automáticas
-partof: scala-tour
-
-num: 16
-language: es
-
-next-page: operators
-previous-page: multiple-parameter-lists
----
-
-Scala permite pasar funciones sin parámetros como parámetros de un método. Cuando un método así es invocado, los parámetros reales de la función enviada sin parámetros no son evaluados y una función "nularia" (de aridad cero, 0-aria, o sin parámetros) es pasada en su lugar. Esta función encapsula el comportamiento del parámetro correspondiente (comunmente conocido como "llamada por nombre").
-
-Para aclarar un poco esto aquí se muestra un ejemplo:
-
- object TargetTest1 extends App {
- def whileLoop(cond: => Boolean)(body: => Unit): Unit =
- if (cond) {
- body
- whileLoop(cond)(body)
- }
- var i = 10
- whileLoop (i > 0) {
- println(i)
- i -= 1
- }
- }
-
-La función `whileLoop` recibe dos parámetros `cond` y `body`. Cuando la función es llamada, los parámetros reales no son evaluados en ese momento. Pero cuando los parámetros son utilizados en el cuerpo de la función `whileLoop`, las funciones nularias creadas implícitamente serán evaluadas en su lugar. Así, nuestro método `whileLoop` implementa un bucle tipo Java mediante una implementación recursiva.
-
-Es posible combinar el uso de [operadores de infijo y postfijo (infix/postfix)](operators.html) con este mecanismo para crear declaraciones más complejas (con una sintaxis agradadable).
-
-Aquí mostramos la implementación de una declaración tipo repetir-a-menos-que (repetir el bucle a no ser que se cumpla X condición):
-
- object TargetTest2 extends App {
- def loop(body: => Unit): LoopUnlessCond =
- new LoopUnlessCond(body)
- protected class LoopUnlessCond(body: => Unit) {
- def unless(cond: => Boolean) {
- body
- if (!cond) unless(cond)
- }
- }
- var i = 10
- loop {
- println("i = " + i)
- i -= 1
- } unless (i == 0)
- }
-
-La función `loop` solo acepta el cuerpo de un bucle y retorna una instancia de la clase `LoopUnlessCond` (la cual encapsula el cuerpo del objeto). Es importante notar que en este punto el cuerpo del bucle no ha sido evaluado aún. La clase `LoopUnlessCond` tiene un método `unless` el cual puede ser usado como un *operador de infijo (infix)*. De esta manera podemos lograr una sintaxis muy natural para nuestro nuevo bucle `repetir { a_menos_que ( )`.
-
-A continuación se expone el resultado de la ejecución de `TargetTest2`:
-
- i = 10
- i = 9
- i = 8
- i = 7
- i = 6
- i = 5
- i = 4
- i = 3
- i = 2
- i = 1
diff --git a/_es/tour/basics.md b/_es/tour/basics.md
index 998ddbe544..484470a508 100644
--- a/_es/tour/basics.md
+++ b/_es/tour/basics.md
@@ -13,40 +13,36 @@ En esta página, practicaremos conceptos básicos de Scala.
## Probando Scala en el navegador
-Puedes ejecutar Scala en tu navegador con ScalaFiddle.
+Puedes ejecutar Scala en tu navegador con Scastie.
-1. Ve a [https://scalafiddle.io](https://scalafiddle.io).
+1. Ve a [Scastie](https://scastie.scala-lang.org/).
2. Escribe `println("Hello, world!")` en el panel a la izquierda.
3. Presiona el botón "Run". En el panel de la derecha aparecerá el resultado.
Así, de manera fácil y sin preparación, puedes probar fragmentos de código Scala.
-Muchos ejemplos de código en esta documentación están integrados con ScalaFiddle, y así puedes probarlos directamente solo con pulsar el botón "Run".
-
## Expresiones
Las expresiones son sentencias computables.
-```tut
+```scala mdoc
1 + 1
```
Se puede ver el resultado de evaluar expresiones usando `println`.
-{% scalafiddle %}
-```tut
+```scala mdoc
println(1) // 1
println(1 + 1) // 2
println("Hello!") // Hello!
println("Hello," + " world!") // Hello, world!
```
-{% endscalafiddle %}
## Valores
Se puede dar un nombre al resultado de una expresión usando la palabra reservada `val`.
-```tut
+```scala mdoc
val x = 1 + 1
println(x) // 2
```
@@ -55,13 +51,13 @@ Los resultados con nombre, como `x` en el ejemplo, son llamados valores. Referen
Los valores no pueden ser reasignados.
-```tut:fail
+```scala mdoc:fail
x = 3 // This does not compile.
```
Scala es capaz de inferir el tipo de un valor. Aun así, también se puede indicar el tipo usando una anotación:
-```tut
+```scala mdoc:nest
val x: Int = 1 + 1
```
@@ -71,7 +67,7 @@ Nótese que la anotación del tipo `Int` sigue al identificador `x` de la variab
Una variable es como un valor, excepto que a una variable se le puede re-asignar un valor después de declararla. Una variable se declara con la palabra reservada `var`.
-```tut
+```scala mdoc:nest
var x = 1 + 1
x = 3 // This compiles because "x" is declared with the "var" keyword.
println(x * x) // 9
@@ -79,7 +75,7 @@ println(x * x) // 9
Como con los valores, si se quiere se puede especificar el tipo de una variable mutable:
-```tut
+```scala mdoc:nest
var x: Int = 1 + 1
```
@@ -89,7 +85,7 @@ Se pueden combinar expresiones rodeándolas con `{}` . A esto le llamamos un blo
El resultado de la última expresión del bloque es también el resultado total del bloque.
-```tut
+```scala mdoc
println({
val x = 1 + 1
x + 1
@@ -102,7 +98,7 @@ Una función es una expresión que acepta parámetros.
Una función se puede declarar anónima, sin nombre. Por ejemplo, ésta es una función que acepta un número entero `x`, y devuelve el resultado de incrementarlo:
-```tut
+```scala mdoc
(x: Int) => x + 1
```
@@ -110,56 +106,48 @@ La lista de parámetros de la función está a la izquierda de la flecha `=>`, y
También podemos asignarle un nombre a la función.
-{% scalafiddle %}
-```tut
+```scala mdoc
val addOne = (x: Int) => x + 1
println(addOne(1)) // 2
```
-{% endscalafiddle %}
Las funciones pueden tomar varios parámetros.
-{% scalafiddle %}
-```tut
+```scala mdoc
val add = (x: Int, y: Int) => x + y
println(add(1, 2)) // 3
```
-{% endscalafiddle %}
O ninguno.
-```tut
+```scala mdoc
val getTheAnswer = () => 42
println(getTheAnswer()) // 42
```
## Métodos
-Los métodos se parecen y comportan casi como a las funciones, pero se diferencian en dos aspectos clave:
+Los métodos se parecen y comportan casi como a las funciones, pero se diferencian en dos aspectos clave:
Un método se define con la palabra reservada `def`, seguida por el nombre del método, la lista de parámetros, el tipo de valores que el método devuelve, y el cuerpo del método.
-{% scalafiddle %}
-```tut
+```scala mdoc:nest
def add(x: Int, y: Int): Int = x + y
println(add(1, 2)) // 3
```
-{% endscalafiddle %}
Observe que el tipo de retorno se declara _después_ de la lista de parámetros, y separado con dos puntos, p.ej. `: Int`.
Un método puede tener varias listas de parámetros.
-{% scalafiddle %}
-```tut
+```scala mdoc
def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier
println(addThenMultiply(1, 2)(3)) // 9
```
-{% endscalafiddle %}
O ninguna lista de parámetros.
-```tut
+```scala mdoc
def name: String = System.getProperty("user.name")
println("Hello, " + name + "!")
```
@@ -168,15 +156,13 @@ Hay otras diferencias, pero para simplificar, podemos pensar que son similares a
Los métodos también pueden tener expresiones de varias lineas.
-{% scalafiddle %}
-```tut
+```scala mdoc
def getSquareString(input: Double): String = {
val square = input * input
square.toString
}
println(getSquareString(2.5)) // 6.25
```
-{% endscalafiddle %}
La ultima expresión en el cuerpo del método es el valor de retorno del mismo.
(Scala tiene una palabra reservada `return`, pero se usa raramente y no se aconseja usarla)
@@ -185,7 +171,7 @@ La ultima expresión en el cuerpo del método es el valor de retorno del mismo.
Una clase se define con la palabra reservada `class`, seguida del nombre, y la lista de parámetros del constructor.
-```tut
+```scala mdoc
class Greeter(prefix: String, suffix: String) {
def greet(name: String): Unit =
println(prefix + name + suffix)
@@ -196,7 +182,7 @@ El método `greet` tiene un tipo de retorno `Unit`, que indica que el método no
Se puede crear una instancia de una clase con la palabra reservada *new*.
-```tut
+```scala mdoc
val greeter = new Greeter("Hello, ", "!")
greeter.greet("Scala developer") // Hello, Scala developer!
```
@@ -208,13 +194,13 @@ Las clases se tratan en profundidad [más adelante](classes.html).
Hay un tipo especial de clases en Scala, las llamadas "case" classes. Por defecto, las instancias de una case class son inmutables, y se comparan con otras solo por los valores que contienen en cada campo.
Una case class se define con las palabras reservadas `case class`:
-```tut
+```scala mdoc
case class Point(x: Int, y: Int)
```
-Se puede crear una instancia de una `case class`, sin usar la palabra reservada `new`.
+Se puede crear una instancia de una `case class`, sin usar la palabra reservada `new`.
-```tut
+```scala mdoc
val point = Point(1, 2)
val anotherPoint = Point(1, 2)
val yetAnotherPoint = Point(2, 2)
@@ -222,17 +208,17 @@ val yetAnotherPoint = Point(2, 2)
Y son comparadas por valor.
-```tut
+```scala mdoc
if (point == anotherPoint) {
- println(point + " and " + anotherPoint + " are the same.")
+ println(s"$point and $anotherPoint are the same.")
} else {
- println(point + " and " + anotherPoint + " are different.")
+ println(s"$point and $anotherPoint are different.")
} // Point(1,2) and Point(1,2) are the same.
if (point == yetAnotherPoint) {
- println(point + " and " + yetAnotherPoint + " are the same.")
+ println(s"$point and $yetAnotherPoint are the same.")
} else {
- println(point + " and " + yetAnotherPoint + " are different.")
+ println(s"$point and $yetAnotherPoint are different.")
} // Point(1,2) and Point(2,2) are different.
```
@@ -244,7 +230,7 @@ Los objetos son instancias de una sola clase de su propia definición. Puedes pe
Un objeto se define usando la palabra reservada `object`.
-```tut
+```scala mdoc
object IdFactory {
private var counter = 0
def create(): Int = {
@@ -256,7 +242,7 @@ object IdFactory {
Para acceder al objeto, lo referencias por su nombre.
-```tut
+```scala mdoc
val newId: Int = IdFactory.create()
println(newId) // 1
val newerId: Int = IdFactory.create()
@@ -271,7 +257,7 @@ Los traits son tipos que contienen campos y métodos. Se pueden combinar múltip
Un trait se define usando la palabra reservada `trait`.
-```tut
+```scala mdoc:nest
trait Greeter {
def greet(name: String): Unit
}
@@ -279,8 +265,7 @@ trait Greeter {
Un `trait` también puede definir un método, o un valor, con una implementación por defecto.
-{% scalafiddle %}
-```tut
+```scala mdoc:reset
trait Greeter {
def greet(name: String): Unit =
println("Hello, " + name + "!")
@@ -289,7 +274,7 @@ trait Greeter {
Un `trait` también puede extender otros traits, usando la palabra clave `extends`. Asimismo, en un `trait` se puede redefinir la implementación de un método heredado, usando la palabra reservada `override`.
-```tut
+```scala mdoc
class DefaultGreeter extends Greeter
class CustomizableGreeter(prefix: String, postfix: String) extends Greeter {
@@ -304,7 +289,6 @@ greeter.greet("Scala developer") // Hello, Scala developer!
val customGreeter = new CustomizableGreeter("How are you, ", "?")
customGreeter.greet("Scala developer") // How are you, Scala developer?
```
-{% endscalafiddle %}
Aquí, `DefaultGreeter` extiende un solo trait, pero puede extender múltiples traits.
@@ -316,7 +300,7 @@ El método principal (main) es el punto donde comienza la ejecución de un progr
Usando un objeto, puedes definir el método principal de la siguiente forma:
-```tut
+```scala mdoc
object Main {
def main(args: Array[String]): Unit =
println("Hello, Scala developer!")
diff --git a/_es/tour/case-classes.md b/_es/tour/case-classes.md
index c47a3b9428..7a4989bde5 100644
--- a/_es/tour/case-classes.md
+++ b/_es/tour/case-classes.md
@@ -19,7 +19,7 @@ A continuación se muestra un ejemplo para una jerarquía de clases la cual cons
case class Fun(arg: String, body: Term) extends Term
case class App(f: Term, v: Term) extends Term
-Esta jerarquía de clases puede ser usada para representar términos de [cálculo lambda no tipado](https://www.ezresult.com/article/Lambda_calculus). Para facilitar la construcción de instancias de clases Case, Scala no requiere que se utilice la primitiva `new`. Simplemente es posible utilizar el nombre de la clase como una llamada a una función.
+Esta jerarquía de clases puede ser usada para representar términos de [cálculo lambda no tipado](https://es.wikipedia.org/wiki/C%C3%A1lculo_lambda). Para facilitar la construcción de instancias de clases Case, Scala no requiere que se utilice la primitiva `new`. Simplemente es posible utilizar el nombre de la clase como una llamada a una función.
Aquí un ejemplo:
diff --git a/_es/tour/classes.md b/_es/tour/classes.md
index 90bd399be0..3f3939b3bc 100644
--- a/_es/tour/classes.md
+++ b/_es/tour/classes.md
@@ -29,7 +29,7 @@ Las clases en Scala son parametrizadas con argumentos constructores (inicializad
Para instanciar una clase es necesario usar la primitiva `new`, como se muestra en el siguiente ejemplo:
object Classes {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val pt = new Point(1, 2)
println(pt)
pt.move(10, 10)
diff --git a/_es/tour/generic-classes.md b/_es/tour/generic-classes.md
index 60d7626cab..b89b603ae3 100644
--- a/_es/tour/generic-classes.md
+++ b/_es/tour/generic-classes.md
@@ -14,12 +14,15 @@ Tal como en Java 5, Scala provee soporte nativo para clases parametrizados con t
A continuación se muestra un ejemplo:
- 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 }
- }
+```scala mdoc
+class Stack[T] {
+ var elems: List[T] = Nil
+ def push(x: T): Unit =
+ elems = x :: elems
+ def top: T = elems.head
+ def pop(): Unit = { elems = elems.tail }
+}
+```
La clase `Stack` modela una pila mutable que contiene elementos de un tipo arbitrario `T` (se dice, "una pila de elementos `T`). Los parámetros de tipos nos aseguran que solo elementos legales (o sea, del tipo `T`) sean insertados en la pila (apilados). De forma similar, con los parámetros de tipo podemos expresar que el método `top` solo devolverá elementos de un tipo dado (en este caso `T`).
diff --git a/_es/tour/inner-classes.md b/_es/tour/inner-classes.md
index 461c72eeb1..9b04862d27 100644
--- a/_es/tour/inner-classes.md
+++ b/_es/tour/inner-classes.md
@@ -12,44 +12,50 @@ previous-page: implicit-parameters
En Scala es posible que las clases tengan como miembro otras clases. A diferencia de lenguajes similares a Java donde ese tipo de clases internas son miembros de las clases que las envuelven, en Scala esas clases internas están ligadas al objeto externo. Para ilustrar esta diferencia, vamos a mostrar rápidamente una implementación del tipo grafo:
- class Graph {
- class Node {
- var connectedNodes: List[Node] = Nil
- def connectTo(node: Node) {
- if (!connectedNodes.exists(node.equals)) {
- connectedNodes = node :: connectedNodes
- }
- }
- }
- var nodes: List[Node] = Nil
- def newNode: Node = {
- val res = new Node
- nodes = res :: nodes
- res
+```scala mdoc
+class Graph {
+ class Node {
+ var connectedNodes: List[Node] = Nil
+ def connectTo(node: Node): Unit = {
+ if (!connectedNodes.exists(node.equals)) {
+ connectedNodes = node :: connectedNodes
}
}
+ }
+ var nodes: List[Node] = Nil
+ def newNode: Node = {
+ val res = new Node
+ nodes = res :: nodes
+ res
+ }
+}
+```
En nuestro programa, los grafos son representados mediante una lista de nodos. Estos nodos son objetos de la clase interna `Node`. Cada nodo tiene una lista de vecinos que se almacena en la lista `connectedNodes`. Ahora podemos crear un grafo con algunos nodos y conectarlos incrementalmente:
- object GraphTest extends App {
- val g = new Graph
- val n1 = g.newNode
- val n2 = g.newNode
- val n3 = g.newNode
- n1.connectTo(n2)
- n3.connectTo(n1)
- }
+```scala mdoc:nest
+def graphTest: Unit = {
+ val g = new Graph
+ val n1 = g.newNode
+ val n2 = g.newNode
+ val n3 = g.newNode
+ n1.connectTo(n2)
+ n3.connectTo(n1)
+}
+```
Ahora vamos a completar el ejemplo con información relacionada al tipado para definir explicitamente de qué tipo son las entidades anteriormente definidas:
- object GraphTest extends App {
- val g: Graph = new Graph
- val n1: g.Node = g.newNode
- val n2: g.Node = g.newNode
- val n3: g.Node = g.newNode
- n1.connectTo(n2)
- n3.connectTo(n1)
- }
+```scala mdoc:nest
+def graphTest: Unit = {
+ val g: Graph = new Graph
+ val n1: g.Node = g.newNode
+ val n2: g.Node = g.newNode
+ val n3: g.Node = g.newNode
+ n1.connectTo(n2)
+ n3.connectTo(n1)
+}
+```
El código anterior muestra que al tipo del nodo le es prefijado con la instancia superior (que en nuestro ejemplo es `g`). Si ahora tenemos dos grafos, el sistema de tipado de Scala no nos permite mezclar nodos definidos en un grafo con nodos definidos en otro, ya que los nodos del otro grafo tienen un tipo diferente.
@@ -70,7 +76,7 @@ Por favor note que en Java la última linea del ejemplo anterior hubiese sido co
class Graph {
class Node {
var connectedNodes: List[Graph#Node] = Nil // Graph#Node en lugar de Node
- def connectTo(node: Graph#Node) {
+ def connectTo(node: Graph#Node): Unit = {
if (!connectedNodes.exists(node.equals)) {
connectedNodes = node :: connectedNodes
}
diff --git a/_es/tour/mixin-class-composition.md b/_es/tour/mixin-class-composition.md
index 9221859891..bd53274158 100644
--- a/_es/tour/mixin-class-composition.md
+++ b/_es/tour/mixin-class-composition.md
@@ -22,7 +22,7 @@ A diferencia de lenguajes que solo soportan _herencia simple_, Scala tiene una n
A continuación, considere una clase mezcla la cual extiende `AbsIterator` con un método `foreach` el cual aplica una función dada a cada elemento retornado por el iterador. Para definir una clase que puede usarse como una clase mezcla usamos la palabra clave `trait`.
trait RichIterator extends AbsIterator {
- def foreach(f: T => Unit) { while (hasNext) f(next()) }
+ def foreach(f: T => Unit): Unit = { while (hasNext) f(next()) }
}
Aquí se muestra una clase iterador concreta, la cual retorna caracteres sucesivos de una cadena de caracteres dada:
@@ -37,7 +37,7 @@ Aquí se muestra una clase iterador concreta, la cual retorna caracteres sucesiv
Nos gustaría combinar la funcionalidad de `StringIterator` y `RichIterator` en una sola clase. Solo con herencia simple e interfaces esto es imposible, ya que ambas clases contienen implementaciones para sus miembros. Scala nos ayuda con sus _compisiciones de clases mezcladas_. Permite a los programadores reutilizar el delta de la definición de una clase, esto es, todas las nuevas definiciones que no son heredadas. Este mecanismo hace posible combinar `StringIterator` con `RichIterator`, como es hecho en el siguiente programa, el cual imprime una columna de todos los caracteres de una cadena de caracteres dada.
object StringIteratorTest {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
class Iter extends StringIterator("Scala") with RichIterator
val iter = new Iter
iter foreach println
diff --git a/_es/tour/multiple-parameter-lists.md b/_es/tour/multiple-parameter-lists.md
index 79d2318e3e..83b7218c0b 100644
--- a/_es/tour/multiple-parameter-lists.md
+++ b/_es/tour/multiple-parameter-lists.md
@@ -6,7 +6,7 @@ partof: scala-tour
num: 15
language: es
-next-page: automatic-closures
+next-page: operators
previous-page: nested-functions
---
@@ -18,7 +18,7 @@ Los métodos pueden definir múltiples listas de parámetros. Cuando un método
A continuación hay un ejemplo, tal y como se define en el trait `TraversableOnce` en el API de colecciones de Scala:
-```
+```scala mdoc:fail
def foldLeft[B](z: B)(op: (B, A) => B): B
```
@@ -26,19 +26,16 @@ def foldLeft[B](z: B)(op: (B, A) => B): B
Comenzando con un valor inicial 0, `foldLeft` aplica la función `(m, n) => m + n` a cada uno de los elementos de la lista y al valor acumulado previo.
-{% scalafiddle %}
-```tut
+```scala mdoc
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val res = numbers.foldLeft(0)((m, n) => m + n)
println(res) // 55
```
-{% endscalafiddle %}
A continuación se muestra otro ejemplo:
-{% scalafiddle %}
-```tut
+```scala mdoc
object CurryTest extends App {
def filter(xs: List[Int], p: Int => Boolean): List[Int] =
@@ -53,15 +50,15 @@ A continuación se muestra otro ejemplo:
println(filter(nums, modN(3)))
}
```
-{% endscalafiddle %}
_Nota: el método `modN` está parcialmente aplicado en las dos llamadas a `filter`; esto significa que solo su primer argumento es realmente aplicado. El término `modN(2)` devuelve una función de tipo `Int => Boolean` y es por eso un posible candidato para el segundo argumento de la función `filter`._
Aquí se muestra la salida del programa anterior:
- List(2,4,6,8)
- List(3,6)
-
+```scala mdoc
+List(2,4,6,8)
+List(3,6)
+```
### Casos de uso
@@ -72,19 +69,19 @@ Casos de uso sugeridos para múltiples listas de parámetros incluyen:
En Scala, la inferencia de tipos se realiza parámetro a parámetro.
Suponer que se dispone del siguiente método:
-```tut
+```scala mdoc
def foldLeft1[A, B](as: List[A], b0: B, op: (B, A) => B) = ???
```
Si se invoca de la siguiente manera, se puede comprobar que no compila correctamente:
-```tut:fail
+```scala mdoc:fail
def notPossible = foldLeft1(numbers, 0, _ + _)
```
Debes invocarlo de alguna de las maneras propuestas a continuación:
-```tut
+```scala mdoc
def firstWay = foldLeft1[Int, Int](numbers, 0, _ + _)
def secondWay = foldLeft1(numbers, 0, (a: Int, b: Int) => a + b)
```
@@ -93,7 +90,7 @@ Esto se debe a que Scala no será capaz de inferir el tipo de la función `_ + _
Moviéndo el parámetro `op` a su propia lista de parámetros, los tipos de `A` y `B` son inferidos en la primera lista de parámetros.
Una vez se han inferido sus tipos, estos están disponibles para la segunda lista de parámetros y `_ + _ ` podrá casar con los tipos inferidos `(Int, Int) => Int`
-```tut
+```scala mdoc
def foldLeft2[A, B](as: List[A], b0: B)(op: (B, A) => B) = ???
def possible = foldLeft2(numbers, 0)(_ + _)
```
@@ -107,7 +104,7 @@ Para especificar solamente ciertos parámetros como [`implicit`](https://docs.sc
Un ejemplo de esto se muestra a continuación:
-```
+```scala mdoc
def execute(arg: Int)(implicit ec: scala.concurrent.ExecutionContext) = ???
```
@@ -117,7 +114,7 @@ Cuando un método es invocado con menos parámetros que los que están declarado
Por ejemplo,
-```tut
+```scala mdoc:nest
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val numberFunc = numbers.foldLeft(List[Int]()) _
diff --git a/_es/tour/named-arguments.md b/_es/tour/named-arguments.md
index 38dd0574d4..fe38fe15d4 100644
--- a/_es/tour/named-arguments.md
+++ b/_es/tour/named-arguments.md
@@ -11,24 +11,24 @@ previous-page: default-parameter-values
En la invocación de métodos y funciones se puede usar el nombre de las variables explícitamente en la llamada, de la siguiente manera:
- def imprimirNombre(nombre:String, apellido:String) = {
+ def imprimirNombre(nombre: String, apellido: String) = {
println(nombre + " " + apellido)
}
imprimirNombre("John","Smith")
// Imprime "John Smith"
- imprimirNombre(first = "John",last = "Smith")
+ imprimirNombre(nombre = "John", apellido = "Smith")
// Imprime "John Smith"
- imprimirNombre(last = "Smith",first = "John")
+ imprimirNombre(apellido = "Smith", nombre = "John")
// Imprime "John Smith"
Note que una vez que se utilizan parámetros nombrados en la llamada, el orden no importa, mientras todos los parámetros sean nombrados. Esta característica funciona bien en conjunción con valores de parámetros por defecto:
- def imprimirNombre(nombre:String = "John", apellido:String = "Smith") = {
+ def imprimirNombre(nombre: String = "John", apellido: String = "Smith") = {
println(nombre + " " + apellido)
}
- printName(apellido = "Jones")
+ imprimirNombre(apellido = "Jones")
// Imprime "John Jones"
language: es
diff --git a/_es/tour/operators.md b/_es/tour/operators.md
index a2d3b5e4be..6aeb98e046 100644
--- a/_es/tour/operators.md
+++ b/_es/tour/operators.md
@@ -7,7 +7,7 @@ num: 17
language: es
next-page: higher-order-functions
-previous-page: automatic-closures
+previous-page: multiple-parameter-lists
---
En Scala, cualquier método el cual reciba un solo parámetro puede ser usado como un *operador de infijo (infix)*. Aquí se muestra la definición de la clase `MyBool`, la cual define tres métodos `and`, `or`, y `negate`.
diff --git a/_es/tour/self-types.md b/_es/tour/self-types.md
index 79714212a7..df02b7dc0a 100644
--- a/_es/tour/self-types.md
+++ b/_es/tour/self-types.md
@@ -91,7 +91,7 @@ Por favor nótese que en esta clase nos es posible instanciar `NodoImpl` porque
Aquí hay un ejemplo de uso de la clase `GrafoDirigidoConcreto`:
- object GraphTest extends App {
+ def graphTest: Unit = {
val g: Grafo = new GrafoDirigidoConcreto
val n1 = g.agregarNodo
val n2 = g.agregarNodo
diff --git a/_es/tour/singleton-objects.md b/_es/tour/singleton-objects.md
index 83aa22ef9b..dceed2d7ad 100644
--- a/_es/tour/singleton-objects.md
+++ b/_es/tour/singleton-objects.md
@@ -26,7 +26,7 @@ Un objeto singleton puede extender clases y _traits_. De hecho, una [clase Case]
## Acompañantes ##
-La mayoría de los objetos singleton no están solos, sino que en realidad están asociados con clases del mismo nombre. El "objeto singleton del mismo nombre" de una case Case, mencionada anteriormente es un ejemplo de esto. Cuando esto sucede, el objeto singleton es llamado el *objeto acompañante* de la clase, y la clase es a su vez llamada la *clase acompañante* del objeto.
+La mayoría de los objetos singleton no están solos, sino que en realidad están asociados con clases del mismo nombre. El "objeto singleton del mismo nombre" de una clase Case, mencionada anteriormente es un ejemplo de esto. Cuando esto sucede, el objeto singleton es llamado el *objeto acompañante* de la clase, y la clase es a su vez llamada la *clase acompañante* del objeto.
[Scaladoc](/style/scaladoc.html) proporciona un soporte especial para ir y venir entre una clase y su acompañante: Si el gran círculo conteniendo la “C” u la “O” tiene su borde inferior doblado hacia adentro, es posible hacer click en el círculo para ir a su acompañante.
diff --git a/_es/tour/tour-of-scala.md b/_es/tour/tour-of-scala.md
index 19b4f60af8..b742b271ab 100644
--- a/_es/tour/tour-of-scala.md
+++ b/_es/tour/tour-of-scala.md
@@ -37,7 +37,6 @@ El [mecanismo de inferencia de tipos locales](type-inference.html) se encarga de
En la práctica, el desarrollo de aplicaciones específicas para un dominio generalmente requiere de "Lenguajes de dominio específico" (DSL). Scala provee una única combinación de mecanismos del lenguaje que simplifican la creación de construcciones propias del lenguaje en forma de bibliotecas:
* cualquier método puede ser usado como un operador de [infijo o postfijo](operators.html)
-* [las closures son construidas automáticamente dependiendo del tipo esperado](automatic-closures.html) (tipos objetivo).
El uso conjunto de ambas características facilita la definición de nuevas sentencias sin tener que extender la sintaxis y sin usar facciones de meta-programación como tipo macros.
diff --git a/_es/tour/tuples.md b/_es/tour/tuples.md
index 004b06beac..27ba0d9819 100644
--- a/_es/tour/tuples.md
+++ b/_es/tour/tuples.md
@@ -18,7 +18,7 @@ un método.
Una tupla con dos elementos puede ser creada del siguiente modo:
-```tut
+```scala mdoc
val ingredient = ("Sugar", 25)
```
@@ -37,7 +37,7 @@ Cada clase tiene tantos parámetros como número de elementos.
Una forma de acceder a los elementos de una tupla es por posición.
Los elementos concretos se llaman `_1`, `_2`, y así sucesivamente.
-```tut
+```scala mdoc
println(ingredient._1) // Sugar
println(ingredient._2) // 25
```
@@ -46,7 +46,7 @@ println(ingredient._2) // 25
Una tupla también puede ser dividida/expandida usando reconocimiento de patrones (pattern matching):
-```tut
+```scala mdoc
val (name, quantity) = ingredient
println(name) // Sugar
println(quantity) // 25
@@ -57,7 +57,7 @@ En esta ocasión el tipo de `name` es inferido como `String` y el de
A continuación otro ejemplo de reconocimiento de patrones con tuplas:
-```tut
+```scala mdoc
val planets =
List(("Mercury", 57.9), ("Venus", 108.2), ("Earth", 149.6),
("Mars", 227.9), ("Jupiter", 778.3))
@@ -70,7 +70,7 @@ planets.foreach{
O en compresión de bucles `for`:
-```tut
+```scala mdoc
val numPairs = List((2, 5), (3, -7), (20, 56))
for ((a, b) <- numPairs) {
println(a * b)
diff --git a/_es/tour/unified-types.md b/_es/tour/unified-types.md
index 5f37f7b47d..3a1db1e651 100644
--- a/_es/tour/unified-types.md
+++ b/_es/tour/unified-types.md
@@ -17,7 +17,7 @@ A diferencia de Java, todos los valores en Scala son objetos (incluyendo valores
## Jerarquía de clases en Scala ##
La superclase de todas las clases, `scala.Any`, tiene dos subclases directas, `scala.AnyVal` y `scala.AnyRef` que representan dos mundos de clases muy distintos: clases para valores y clases para referencias. Todas las clases para valores están predefinidas; se corresponden con los tipos primitivos de los lenguajes tipo Java. Todas las otras clases definen tipos referenciables. Las clases definidas por el usuario son definidas como tipos referenciables por defecto, es decir, siempre (indirectamente) extienden de `scala.AnyRef`. Toda clase definida por usuario en Scala extiende implicitamente el trait `scala.ScalaObject`. Clases pertenecientes a la infraestructura en la cual Scala esté corriendo (ejemplo, el ambiente de ejecución de Java) no extienden de `scala.ScalaObject`. Si Scala es usado en el contexto de un ambiente de ejecución de Java, entonces `scala.AnyRef` corresponde a `java.lang.Object`.
-Por favor note que el diagrama superior también muestra conversiones implícitas llamadas viestas entre las clases para valores.
+Por favor note que el diagrama superior también muestra conversiones implícitas llamadas vistas entre las clases para valores.
Aquí se muestra un ejemplo que demuestra que tanto valores numéricos, de caracteres, buleanos y funciones son objetos, tal como cualquier otro objeto:
diff --git a/_es/tour/variances.md b/_es/tour/variances.md
index feedee8fbb..eb961061a8 100644
--- a/_es/tour/variances.md
+++ b/_es/tour/variances.md
@@ -14,7 +14,7 @@ Scala soporta anotaciones de varianza para parámetros de tipo para [clases gen
En el artículo sobre clases genéricas dimos un ejemplo de una pila mutable. Explicamos que el tipo definido por la clase `Stack[T]` es objeto de subtipos invariantes con respecto al parámetro de tipo. Esto puede restringir el reuso de la abstracción (la clase). Ahora derivaremos una implementación funcional (es decir, inmutable) para pilas que no tienen esta restricción. Nótese que este es un ejemplo avanzado que combina el uso de [métodos polimórficos](polymorphic-methods.html), [límites de tipado inferiores](lower-type-bounds.html), y anotaciones de parámetros de tipo covariante de una forma no trivial. Además hacemos uso de [clases internas](inner-classes.html) para encadenar los elementos de la pila sin enlaces explícitos.
-```tut
+```scala mdoc
class Stack[+T] {
def push[S >: T](elem: S): Stack[S] = new Stack[S] {
override def top: S = elem
diff --git a/_es/tutorials/scala-for-java-programmers.md b/_es/tutorials/scala-for-java-programmers.md
index f4cc568f84..120d93d316 100644
--- a/_es/tutorials/scala-for-java-programmers.md
+++ b/_es/tutorials/scala-for-java-programmers.md
@@ -18,7 +18,7 @@ Este documento provee una rápida introducción al lenguaje Scala como también
Como primer ejemplo, usaremos el programa *Hola mundo* estándar. No es muy fascinante, pero de esta manera resulta fácil demostrar el uso de herramientas de Scala sin saber demasiado acerca del lenguaje. Veamos como luce:
object HolaMundo {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
println("¡Hola, mundo!")
}
}
@@ -59,7 +59,7 @@ Las librerías de clases de Java definen clases de utilería poderosas, como `Da
import java.text.DateFormat._
object FrenchDate {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val ahora = new Date
val df = getDateInstance(LONG, Locale.FRANCE)
println(df format ahora)
@@ -116,7 +116,7 @@ En el siguiente programa, la función del temporizador se llama `unaVezPorSegund
def tiempoVuela() {
println("El tiempo vuela como una flecha...")
}
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
unaVezPorSegundo(tiempoVuela)
}
}
@@ -134,7 +134,7 @@ El programa anterior es fácil de entender, pero puede ser refinado aún más. P
Thread sleep 1000
}
}
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
unaVezPorSegundo(
() => println("El tiempo vuela como una flecha...")
)
@@ -167,7 +167,7 @@ El compilador no es siempre capaz de inferir los tipos como lo hace aquí, y des
Un pequeño problema de los métodos `re` e `im` es que para poder llamarlos es necesario agregar un par de paréntesis vacíos después de sus nombres, como muestra el siguiente ejemplo:
object NumerosComplejos {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val c = new Complejo(1.2, 3.4)
println("Parte imaginaria: " + c.im())
}
@@ -282,7 +282,7 @@ Esta función introduce dos nuevos conceptos relacionados al pattern matching. P
No hemos explorado el completo poder del pattern matching aún, pero nos detendremos aquí para mantener este documento corto. Todavía nos queda pendiente ver cómo funcionan las dos funciones de arriba en un ejemplo real. Para ese propósito, escribamos una función main simple que realice algunas operaciones sobre la expresión `(x+x)+(7+y)`: primero computa su valor en el entorno `{ x -> 5, y -> 7 }` y después computa su derivada con respecto a `x` y después a `y`.
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val exp: Arbol = Sum(Sum(Var("x"),Var("x")),Sum(Const(7),Var("y")))
val ent: Entonrno = { case "x" => 5 case "y" => 7 }
println("Expresión: " + exp)
@@ -386,7 +386,7 @@ El ejemplo anterior introduce a las variables en Scala, que no deberían requeri
Para utilizar esta clase `Referencia`, uno necesita especificar qué tipo utilizar por el parámetro `T`, es decir, el tipo del elemento contenido por la referencia. Por ejemplo, para crear y utilizar una referencia que contenga un entero, podríamos escribir lo siguiente:
object ReferenciaEntero {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val ref = new Referencia[Int]
ref.set(13)
println("La referencia tiene la mitad de " + (ref.get * 2))
diff --git a/_fr/getting-started/install-scala.md b/_fr/getting-started/install-scala.md
new file mode 100644
index 0000000000..76f7c537f9
--- /dev/null
+++ b/_fr/getting-started/install-scala.md
@@ -0,0 +1,198 @@
+---
+layout: singlepage-overview
+title: Démarrage
+partof: getting-started
+language: fr
+includeTOC: true
+---
+
+Les instructions ci-dessous couvrent à la fois Scala 2 et Scala 3.
+
+## Essayer Scala sans installation
+
+Pour commencer à expérimenter Scala sans plus attendre, utilisez “Scastie” dans votre navigateur _Scastie_ est un environnement "bac à sable" en ligne, où vous pouvez tester Scala, afin de comprendre comment fonctionne le langage et avec un accès à tous les compilateurs Scala et les librairies publiées.
+
+> Scastie supporte à la fois Scala 2 et Scala 3, en proposant Scala 3 par défaut.
+> Si vous cherchez à tester un morceau de code avec Scala 2
+> [cliquez ici](https://scastie.scala-lang.org/MHc7C9iiTbGfeSAvg8CKAA).
+
+## Installer Scala sur votre ordinateur
+
+Installer Scala veut dire installer différents outils en ligne de commande, comme le compilateur Scala et les outils de build.
+Nous recommandons l'utilisation de l'outil d'installation "Coursier" qui va automatiquement installer toutes les dépendances, mais vous pouvez aussi installer chaque outil à la main.
+
+### Utilisation de l'installateur Scala (recommandé)
+
+L'installateur Scala est un outil nommé [Coursier](https://get-coursier.io/docs/cli-overview), la commande principale de l'outil est `cs`.
+Il s'assure que la JVM est les outils standards de Scala sont installés sur votre système.
+Installez-le sur votre système avec les instructions suivantes.
+
+
+{% tabs install-cs-setup-tabs class=platform-os-options %}
+
+
+{% tab macOS for=install-cs-setup-tabs %}
+{% include code-snippet.html language='bash' codeSnippet=site.data.setup-scala.macOS-brew %}
+{% altDetails cs-setup-macos-nobrew "Alternativement, si vous n'utilisez pas Homebrew:" %}
+ {% include code-snippet.html language='bash' codeSnippet=site.data.setup-scala.macOS-x86-64 %}
+{% endaltDetails %}
+{% endtab %}
+
+
+
+{% tab Linux for=install-cs-setup-tabs %}
+ {% include code-snippet.html language='bash' codeSnippet=site.data.setup-scala.linux-x86-64 %}
+{% endtab %}
+
+
+
+{% tab Windows for=install-cs-setup-tabs %}
+ Téléchargez et exécutez [l'intallateur Scala pour Windows]({{site.data.setup-scala.windows-link}}) basé sur Coursier.
+{% endtab %}
+
+
+
+{% tab Other for=install-cs-setup-tabs defaultTab %}
+
+ Suivez
+ [les instructions pour installer la commande `cs`](https://get-coursier.io/docs/cli-installation)
+ puis exécutez `./cs setup`.
+{% endtab %}
+
+
+{% endtabs %}
+
+
+En plus de gérer les JVMs, `cs setup` installe aussi des utilitaires en ligne de commande :
+
+- Un JDK (si vous n'en avez pas déjà un)
+- L'outil de construction de package [sbt](https://www.scala-sbt.org/)
+- [Ammonite](https://ammonite.io/), un REPL amélioré
+- [scalafmt](https://scalameta.org/scalafmt/), le formatteur de code Scala
+- `scalac` (le compilateur Scala 2)
+- `scala` (le REPL et le lanceur de script Scala 2).
+
+Pour plus d'informations à propos de `cs`, vous pouvez lire la page suivante :
+[coursier-cli documentation](https://get-coursier.io/docs/cli-overview).
+
+> Actuellement, `cs setup` installe le compilateur Scala 2 et le lanceur
+> (les commandes `scalac` et `scala` respectivement). Ce n'est pas un problème,
+> car la plupart des projets utilisent un outil de contruction
+> de package qui fonctionne à la fois pour Scala 2 et Scala 3.
+> Cependant, vous pouvez installer le compilateur et le lanceur Scala 3 en ligne de commande,
+> en exécutant les commandes suivantes :
+> ```
+> $ cs install scala3-compiler
+> $ cs install scala3
+> ```
+
+### ...ou manuellement
+
+Vous avez seulement besoin de deux outils pour compiler, lancer, tester et packager un projet Scala: Java 8 ou 11, et sbt.
+Pour les installer manuellement :
+
+1. Si vous n'avez pas Java 8 ou 11 installé, téléchargez
+ Java depuis [Oracle Java 8](https://www.oracle.com/java/technologies/javase-jdk8-downloads.html), [Oracle Java 11](https://www.oracle.com/java/technologies/javase-jdk11-downloads.html),
+ ou [AdoptOpenJDK 8/11](https://adoptopenjdk.net/). Référez-vous à la page [JDK Compatibility](/overviews/jdk-compatibility/overview.html) pour les détails de compatibilité entre Java et Scala.
+1. Installez [sbt](https://www.scala-sbt.org/download.html)
+
+## Créer un projet "Hello World" avec sbt
+
+Une fois que vous avez installé sbt, vous pouvez créer un projet Scala, comme expliqué dans la section suivante.
+
+Pour créer un projet, vous pouvez soit utiliser la ligne de commande, soit un IDE.
+Si vous êtes habitué à la ligne de commande, nous recommandons cette approche.
+
+### Utiliser la ligne de commande
+
+sbt est un outil de construction de package pour Scala, sbt compile, lance et teste votre code Scala.
+(Il peut aussi publier les librairies et faire beaucoup d'autres tâches.)
+
+Pour créer un nouveau projet Scala avec sbt :
+
+1. `cd` dans un répertoire vide.
+1. Lancez la commande `sbt new scala/scala3.g8` pour créer un projet Scala 3, ou `sbt new scala/hello-world.g8` pour créer un projet Scala 2.
+ Cela va télécharger un projet modèle depuis Github.
+ Cela va aussi créer un dossier `target`, que vous pouvez ignorer.
+1. Quand cela vous est demandé, nommez votre application `hello-world`. Cela va créer un projet appelé "hello-world".
+1. Voyons ce que nous vennons de générer :
+
+```
+- hello-world
+ - project (sbt utilise ce dossier pour ses propres fichiers)
+ - build.properties
+ - build.sbt (fichier de définition de la construction du package pour sbt)
+ - src
+ - main
+ - scala (tout votre code Scala doit être placé ici)
+ - Main.scala (Point d'entrée du programme) <-- c'est tout ce dont nous avons besoin pour le moment
+```
+
+Vous pouvez trouver plus de documentation à propos de sbt dans le [Scala Book](/scala3/book/tools-sbt.html) ([Lien](/overviews/scala-book/scala-build-tool-sbt.html) vers la version Scala 2) et sur la [documentation](https://www.scala-sbt.org/1.x/docs/index.html) officielle de sbt.
+
+### Avec un IDE
+
+Vous pouvez ignorer le reste de cette page et aller directement sur [Building a Scala Project with IntelliJ and sbt](/getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.html).
+
+
+## Ouvrir le projet hello-world
+
+Utilisons un IDE pour ouvrir le projet. Les plus populaires sont IntelliJ et VSCode.
+Il proposent tout deux des fonctionnalités avancées. D'[autres éditeurs](https://scalameta.org/metals/docs/editors/overview.html) sont également disponibles.
+
+### Avec IntelliJ
+
+1. Téléchargez et installez [IntelliJ Community Edition](https://www.jetbrains.com/idea/download/)
+1. Installez l'extension Scala en suivant [les instruction IntelliJ pour installer des extensions](https://www.jetbrains.com/help/idea/managing-plugins.html)
+1. Ouvrez le fichier `build.sbt` puis choisissez *Open as a project*
+
+### Avec VSCode et metals
+
+1. Téléchargez [VSCode](https://code.visualstudio.com/Download)
+1. Installez l'extension Metals depuis [la marketplace](https://marketplace.visualstudio.com/items?itemName=scalameta.metals)
+1. Ensuite, ouvrez le répertoire contenant le fichier `build.sbt` (cela doit être le dossier `hello-world` si vous avez suivi les instructions précédentes). Choisissez *Import build* lorsque cela vous est demandé.
+
+> [Metals](https://scalameta.org/metals) est un "Serveur de langage Scala" qui fournit une aide pour écrire du code Scala dans VSCode et d'autres éditeurs [Atom, Sublime Text, autres ...](https://scalameta.org/metals/docs/editors/overview.html), en utilisant le [Language Server Protocol (LSP)](https://microsoft.github.io/language-server-protocol/).
+> En arrière plan, Metals communique avec l'outil de construction de package en utilisant
+> le [Build Server Protocol (BSP)](https://build-server-protocol.github.io/).
+> Pour plus de détails sur le fonctionnement de Metals, suivez [“Write Scala in VS Code, Vim, Emacs, Atom and Sublime Text with Metals”](https://www.scala-lang.org/2019/04/16/metals.html).
+
+### Essayer avec le code source
+
+Ouvrez ces deux fichiers dans votre IDE :
+
+- _build.sbt_
+- _src/main/scala/Main.scala_
+
+Quand vous lancerez votre projet à l'étape suivante, la configuration dans _build.sbt_ sera utilisée pour lancer le code dans _src/main/scala/Main.scala_.
+
+## Lancer Hello Word
+
+Si vous êtes habitué à votre IDE, vous pouvez lancer le code dans _Main.scala_ depuis celui-ci.
+
+Sinon, vous pouvez lancer l'application depuis le terminal avec ces étapes :
+
+1. `cd` vers `hello-world`.
+1. Lancez `sbt`. Cela va ouvrir la console sbt.
+1. Ecrivez `~run`. Le symbole `~` est optionnel, il va relancer l'application à chaque sauvegarde de fichier.
+ Cela permet un cyle rapide de modification/relance/debug. sbt va aussi générer un dossier `target` que vous pouvez ignorer.
+
+Quand vous avez fini d'expérimenter avec ce projet, appuyez sur `[Entrée]` pour interrompre la commande `run`.
+Puis saisissez `exit` ou appuyez sur `[Ctrl+D]` pour quitter sbt et revenir à votre invite de commande.
+
+## Prochaines étapes
+
+Une fois que vous avez terminé le tutoriel ce dessus, vous pouvez consulter :
+
+* [The Scala Book](/scala3/book/introduction.html) ([Lien](/overviews/scala-book/introduction.html) vers la version Scala 2), qui fournit un ensemble de courtes leçons et introduit les fonctionnalités principales de Scala.
+* [The Tour of Scala](/tour/tour-of-scala.html) pour une introduction des fonctionnalités Scala.
+* [Learning Courses](/online-courses.html), qui contient des tutoriels et des cours interactifs.
+* [Our list of some popular Scala books](/books.html).
+* [The migration guide](/scala3/guides/migration/compatibility-intro.html) pour vous aider à migrer votre code Scala 2 vers Scala 3.
+
+## Obtenir de l'aide
+Il y a plusieurs listes de diffusion et canaux de discussions instantanés si vous souhaitez rencontrer rapidement d'autres utilisateurs de Scala. Allez faire un tour sur notre page [community](https://scala-lang.org/community/) pour consulter la liste des ces ressources et obtenir de l'aide.
+
+Traduction par Antoine Pointeau.
diff --git a/_fr/tour/abstract-type-members.md b/_fr/tour/abstract-type-members.md
new file mode 100644
index 0000000000..68f1cdfd1e
--- /dev/null
+++ b/_fr/tour/abstract-type-members.md
@@ -0,0 +1,76 @@
+---
+layout: tour
+title: Abstract Type Members
+partof: scala-tour
+num: 25
+language: fr
+next-page: compound-types
+previous-page: inner-classes
+topics: abstract type members
+prerequisite-knowledge: variance, upper-type-bound
+---
+
+Les types abstraits, tels que les traits et les classes abstraites, peuvent avoir des membres type abstrait.
+Cela signifie que les implémentations concrètes définissent les types réels.
+Voici un exemple :
+
+```scala mdoc
+trait Buffer {
+ type T
+ val element: T
+}
+```
+
+Ici, nous avons défini un `type T` abstrait. Il est utilisé pour décrire le type de `element`. Nous pouvons étendre ce trait dans une classe abstraite, en ajoutant une borne de type supérieure à `T` pour le rendre plus spécifique.
+
+```scala mdoc
+abstract class SeqBuffer extends Buffer {
+ type U
+ type T <: Seq[U]
+ def length = element.length
+}
+```
+
+Remarquez comment nous pouvons utiliser un autre type abstrait `U` dans la spécification d'une borne supérieure pour `T`. Cette `class SeqBuffer` nous permet de stocker uniquement des séquences dans le tampon en indiquant que le type `T` doit être un sous-type de `Seq[U]` pour un nouveau type abstrait `U`.
+
+Les traits ou [classes](classes.html) avec des membres type abstrait sont souvent utilisés en combinaison avec des instanciations de classes anonymes. Pour illustrer cela, regardons maintenant un programme qui traite un "sequence buffer" qui fait référence à une liste d'entiers :
+
+```scala mdoc
+abstract class IntSeqBuffer extends SeqBuffer {
+ type U = Int
+}
+
+
+def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
+ new IntSeqBuffer {
+ type T = List[U]
+ val element = List(elem1, elem2)
+ }
+val buf = newIntSeqBuf(7, 8)
+println("length = " + buf.length)
+println("content = " + buf.element)
+```
+
+Ici, la factory `newIntSeqBuf` utilise une implémentation de classe anonyme de `IntSeqBuffer` (c'est-à-dire `new IntSeqBuffer`) pour définir le type abstrait `T` comme étant le type concret `List[Int]`.
+
+Il est également possible de transformer des membres type abstrait en paramètres de type de classes et *vice versa*. Voici une version du code ci-dessous qui n'utilise que des paramètres de type :
+
+```scala mdoc:nest
+abstract class Buffer[+T] {
+ val element: T
+}
+abstract class SeqBuffer[U, +T <: Seq[U]] extends Buffer[T] {
+ def length = element.length
+}
+
+def newIntSeqBuf(e1: Int, e2: Int): SeqBuffer[Int, Seq[Int]] =
+ new SeqBuffer[Int, List[Int]] {
+ val element = List(e1, e2)
+ }
+
+val buf = newIntSeqBuf(7, 8)
+println("length = " + buf.length)
+println("content = " + buf.element)
+```
+
+Notez que nous devons utiliser ici [les annotaions de variance](variances.html) (`+T <: Seq[U]`) afin de masquer le type concret d'implémentation de séquence dans l'objet renvoyé par la méthode `newIntSeqBuf`. De plus, il existe des cas où il n'est pas possible de remplacer les membres de type abstrait par des paramètres de type.
diff --git a/_fr/tour/annotations.md b/_fr/tour/annotations.md
new file mode 100644
index 0000000000..5f2b4cbf55
--- /dev/null
+++ b/_fr/tour/annotations.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Annotations
+partof: scala-tour
+
+num: 30
+
+language: fr
+
+next-page: packages-and-imports
+previous-page: by-name-parameters
+---
diff --git a/_fr/tour/basics.md b/_fr/tour/basics.md
new file mode 100644
index 0000000000..a16e3c7970
--- /dev/null
+++ b/_fr/tour/basics.md
@@ -0,0 +1,11 @@
+---
+layout: tour
+title: Basics
+partof: scala-tour
+
+num: 2
+language: fr
+
+next-page: unified-types
+previous-page: tour-of-scala
+---
diff --git a/_fr/tour/by-name-parameters.md b/_fr/tour/by-name-parameters.md
new file mode 100644
index 0000000000..917e78aede
--- /dev/null
+++ b/_fr/tour/by-name-parameters.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: By-name Parameters
+partof: scala-tour
+
+num: 29
+
+language: fr
+
+next-page: annotations
+previous-page: operators
+---
diff --git a/_fr/tour/case-classes.md b/_fr/tour/case-classes.md
new file mode 100644
index 0000000000..66debb53f4
--- /dev/null
+++ b/_fr/tour/case-classes.md
@@ -0,0 +1,73 @@
+---
+layout: tour
+title: Case Classes
+partof: scala-tour
+
+num: 13
+
+language: fr
+
+next-page: pattern-matching
+previous-page: multiple-parameter-lists
+---
+
+Les classes de cas sont comme les autres classes avec quelques différences que nous allons présenter. Les classes de cas sont pratiques pour modéliser des données immuables. Dans la prochaine étape du tour, nous verrons comment elles peuvent être utilisées avec le [pattern matching](pattern-matching.html).
+
+## Définir une classe de cas
+
+Une classe de cas requiert au minimum le mot clef `case class`, un identifiant, et une liste de paramètres (qui peut être vide) :
+
+```scala mdoc
+case class Book(isbn: String)
+
+val frankenstein = Book("978-0486282114")
+```
+
+Notez que le mot clef `new` n'a pas été utilisé pour instancier la classe de cas `Book`. C'est parce que la classe de cas a une méthode `apply` par défaut qui prend en charge la construction de l'objet.
+
+Quand vous créez une classe de cas avec des paramètres, les paramètres sont des `val` publiques.
+
+```
+case class Message(sender: String, recipient: String, body: String)
+val message1 = Message("guillaume@quebec.ca", "jorge@catalonia.es", "Ça va ?")
+
+println(message1.sender) // prints guillaume@quebec.ca
+message1.sender = "travis@washington.us" // cette ligne ne compile pas
+```
+
+Vous ne pouvez pas réaffecter `message1.sender` parce que c'est une `val` (càd. une valeur immuable). Il est possible d'utiliser des `var` dans les classes de cas mais ce n'est pas recommandé.
+
+## Comparaison
+
+Les instances des classes de cas sont comparées structurellement et non par référence :
+
+```scala mdoc
+case class Message(sender: String, recipient: String, body: String)
+
+val message2 = Message("jorge@catalonia.es", "guillaume@quebec.ca", "Com va?")
+val message3 = Message("jorge@catalonia.es", "guillaume@quebec.ca", "Com va?")
+val messagesAreTheSame = message2 == message3 // true
+```
+
+Même si `message2` et `message3` font référence à des objets différents, les valeurs de chaque objet sont égales.
+
+## Copier
+
+Vous pouvez créer une copie (superficielle) d'une instance de classe de cas simplement en utlisant la méthode `copy`. Vous pouvez optionnellement changer les arguments du constructeur.
+
+```scala mdoc:nest
+case class Message(sender: String, recipient: String, body: String)
+val message4 = Message("julien@bretagne.fr", "travis@washington.us", "Me zo o komz gant ma amezeg")
+val message5 = message4.copy(sender = message4.recipient, recipient = "claire@bourgogne.fr")
+message5.sender // travis@washington.us
+message5.recipient // claire@bourgogne.fr
+message5.body // "Me zo o komz gant ma amezeg"
+```
+
+Le destinataire (recipient) de `message4` est utilisé comment expéditeur (sender) du message `message5` mais le `body` du `message4` a été directement copié.
+
+## Plus d'informations
+
+* Apprennez-en plus sur les classes de cas dans [Scala Book](/overviews/scala-book/case-classes.html)
+
+Traduit par Antoine Pointeau.
diff --git a/_fr/tour/classes.md b/_fr/tour/classes.md
new file mode 100644
index 0000000000..40f56d0513
--- /dev/null
+++ b/_fr/tour/classes.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Classes
+partof: scala-tour
+
+num: 4
+
+language: fr
+
+next-page: traits
+previous-page: unified-types
+---
diff --git a/_fr/tour/compound-types.md b/_fr/tour/compound-types.md
new file mode 100644
index 0000000000..db813518b1
--- /dev/null
+++ b/_fr/tour/compound-types.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Compound Types
+partof: scala-tour
+
+num: 22
+
+language: fr
+
+next-page: self-types
+previous-page: abstract-type-members
+---
diff --git a/_fr/tour/default-parameter-values.md b/_fr/tour/default-parameter-values.md
new file mode 100644
index 0000000000..0f73ab1653
--- /dev/null
+++ b/_fr/tour/default-parameter-values.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Default Parameter Values
+partof: scala-tour
+
+num: 31
+
+language: fr
+
+next-page: named-arguments
+previous-page: annotations
+---
diff --git a/_fr/tour/extractor-objects.md b/_fr/tour/extractor-objects.md
new file mode 100644
index 0000000000..1f864b7f39
--- /dev/null
+++ b/_fr/tour/extractor-objects.md
@@ -0,0 +1,66 @@
+---
+layout: tour
+title: Extractor Objects
+partof: scala-tour
+
+num: 18
+
+language: fr
+
+next-page: for-comprehensions
+previous-page: regular-expression-patterns
+---
+
+Un objet extracteur est un objet avec une méthode `unapply`. Tandis que la méthode `apply` ressemble à un constructeur qui prend des arguments et crée un objet, `unapply` prend un object et essaye de retourner ses arguments. Il est utilisé le plus souvent en filtrage par motif (*pattern matching*) ou avec les fonctions partielles.
+
+```scala mdoc
+import scala.util.Random
+
+object CustomerID {
+
+ def apply(name: String) = s"$name--${Random.nextLong()}"
+
+ def unapply(customerID: String): Option[String] = {
+ val stringArray: Array[String] = customerID.split("--")
+ if (stringArray.tail.nonEmpty) Some(stringArray.head) else None
+ }
+}
+
+val customer1ID = CustomerID("Sukyoung") // Sukyoung--23098234908
+customer1ID match {
+ case CustomerID(name) => println(name) // prints Sukyoung
+ case _ => println("Could not extract a CustomerID")
+}
+```
+
+La méthode `apply` crée une chaîne de caractères `CustomerID` depuis `name`. La méthode `unapply` fait l'inverse pour retrouver le `name`. Lorsqu'on appelle `CustomerID("Sukyoung")`, c'est un raccourci pour `CustomerID.apply("Sukyoung")`. Lorsqu'on appelle `case CustomerID(name) => println(name)`, on appelle la méthode `unapply` avec `CustomerID.unapply(customer1ID)`.
+
+Sachant qu'une définition de valeur peut utiliser une décomposition pour introduire une nouvelle variable, un extracteur peut être utilisé pour initialiser la variable, avec la méthode `unapply` pour fournir la valeur.
+
+```scala mdoc
+val customer2ID = CustomerID("Nico")
+val CustomerID(name) = customer2ID
+println(name) // prints Nico
+```
+
+C'est équivalent à `val name = CustomerID.unapply(customer2ID).get`.
+
+```scala mdoc
+val CustomerID(name2) = "--asdfasdfasdf"
+```
+
+S'il n'y a pas de correspondance, une `scala.MatchError` est levée :
+
+```scala
+val CustomerID(name3) = "-asdfasdfasdf"
+```
+
+Le type de retour de `unapply` doit être choisi comme suit :
+
+* Si c'est juste un test, retourner un `Boolean`. Par exemple, `case even()`.
+* Si cela retourne une seule sous-valeur de type T, retourner un `Option[T]`.
+* Si vous souhaitez retourner plusieurs sous-valeurs `T1,...,Tn`, groupez-les dans un tuple optionnel `Option[(T1,...,Tn)]`.
+
+Parfois, le nombre de valeurs à extraire n'est pas fixe et on souhaiterait retourner un nombre arbitraire de valeurs, en fonction des données d'entrée. Pour ce cas, vous pouvez définir des extracteurs avec la méthode `unapplySeq` qui retourne un `Option[Seq[T]]`. Un exemple commun d'utilisation est la déconstruction d'une liste en utilisant `case List(x, y, z) =>`. Un autre est la décomposition d'une `String` en utilisant une expression régulière `Regex`, comme `case r(name, remainingFields @ _*) =>`.
+
+Traduit par Antoine Pointeau.
diff --git a/_fr/tour/for-comprehensions.md b/_fr/tour/for-comprehensions.md
new file mode 100644
index 0000000000..ea4649ad39
--- /dev/null
+++ b/_fr/tour/for-comprehensions.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: For Comprehensions
+partof: scala-tour
+
+num: 15
+
+language: fr
+
+next-page: generic-classes
+previous-page: extractor-objects
+---
diff --git a/_fr/tour/generic-classes.md b/_fr/tour/generic-classes.md
new file mode 100644
index 0000000000..6eeb2e8fea
--- /dev/null
+++ b/_fr/tour/generic-classes.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Generic Classes
+partof: scala-tour
+
+num: 16
+
+language: fr
+
+next-page: variances
+previous-page: extractor-objects
+---
diff --git a/_fr/tour/higher-order-functions.md b/_fr/tour/higher-order-functions.md
new file mode 100644
index 0000000000..513f6b619f
--- /dev/null
+++ b/_fr/tour/higher-order-functions.md
@@ -0,0 +1,123 @@
+---
+layout: tour
+title: Higher-order Functions
+partof: scala-tour
+
+num: 10
+
+language: fr
+
+next-page: nested-functions
+previous-page: mixin-class-composition
+---
+
+Les fonctions d'ordre supérieur prennent d'autres fonctions en paramètres ou retournent une fonction en résultat.
+C'est possible car les fonctions sont des valeurs de première classe en Scala.
+La terminologie peut devenir une peu confuse à ce point, et nous utilisons l'expression "fonction d'ordre supérieur" à la fois pour les méthodes et les fonctions qui prennent d'autres fonctions en paramètres ou retournent une fonction en résultat.
+
+Dans le monde du pur orienté objet, une bonne pratique est d'éviter d'exposer des méthodes paramétrées avec des fonctions qui pourraient exposer l'état interne de l'objet. Le fait d’exposer l'état interne de l'objet pourrait casser les invariants de l'objet lui-même ce qui violerait l'encapsulation.
+
+Un des exemples les plus communs est la fonction d'ordre supérieur `map` qui est diponible pour les collections en Scala.
+
+```scala mdoc
+val salaries = Seq(20000, 70000, 40000)
+val doubleSalary = (x: Int) => x * 2
+val newSalaries = salaries.map(doubleSalary) // List(40000, 140000, 80000)
+```
+
+`doubleSalary` est une fonction qui prend un seul entier, `x` et retourne `x * 2`. La partie à gauche de la flèche `=>` est la liste de paramètres, et la valeur de l'expression à droite est ce qui est retourné. Sur la ligne 3, la fonction `doubleSalary` est appliquée à chaque élément dans la liste des salariés.
+
+Pour réduire le code, nous pouvons faire une fonction anonyme et la passer directement en argument de `map` :
+
+```scala:nest
+val salaries = Seq(20000, 70000, 40000)
+val newSalaries = salaries.map(x => x * 2) // List(40000, 140000, 80000)
+```
+
+Notez que `x` n'est pas déclaré comme un `Int` dans l'exemple ci-dessus. C'est parce que le compilateur peut inférrer le type en se basant sur le type que méthode `map` attend. (voir [Currying](/tour/multiple-parameter-lists.html)). Une autre façon d'écrire le même morceau de code encore plus idiomatique serait :
+
+```scala mdoc:nest
+val salaries = Seq(20000, 70000, 40000)
+val newSalaries = salaries.map(_ * 2)
+```
+
+Sachant que le compilateur Scala sait déjà quel est le type des paramètres (un seul `Int`), vous pouvez fournir uniquement la partie de droite de la fonction.
+La seule contrepartie c'est que vous devez utiliser `_` à la place du nom du paramètre (c'était `x` dans l'exemple précédent).
+
+## Convertir les méthodes en fonctions
+
+Il est aussi possible de passer des méthodes comme arguments aux fonctions d'ordre supérieur, parce que le compilateur Scala va convertir la méthode en fonction.
+
+```scala mdoc
+case class WeeklyWeatherForecast(temperatures: Seq[Double]) {
+
+ private def convertCtoF(temp: Double) = temp * 1.8 + 32
+
+ def forecastInFahrenheit: Seq[Double] = temperatures.map(convertCtoF) // <-- passing the method convertCtoF
+}
+```
+
+Ici la méthode `convertCtoF` est passée à la fonction d'ordre supérieur `map`. C'est possible car le compilateur convertit `convertCtoF` vers la fonction `x => convertCtoF(x)` (note : `x` sera un nom généré qui sera garanti d'être unique dans le scope).
+
+## Les fonction qui acceptent des fonctions
+
+Une raison d'utiliser les fonctions d'ordre supérieur est de réduire le code redondant. Suposons que vous souhaitez des méthodes qui augmentent le salaire de quelqu'un en fonction de différents facteurs. Sans créer de fonction d'ordre supérieur, cela ressemblerait à ça :
+
+```scala mdoc
+object SalaryRaiser {
+
+ def smallPromotion(salaries: List[Double]): List[Double] =
+ salaries.map(salary => salary * 1.1)
+
+ def greatPromotion(salaries: List[Double]): List[Double] =
+ salaries.map(salary => salary * math.log(salary))
+
+ def hugePromotion(salaries: List[Double]): List[Double] =
+ salaries.map(salary => salary * salary)
+}
+```
+
+Notez comment chacunes de ces trois méthodes ne changent que par le facteur de multiplication.
+Pour simplifier, vous pouvez extraire le code répété dans une fonction d'ordre supérieur comme ceci :
+
+```scala mdoc:nest
+object SalaryRaiser {
+
+ private def promotion(salaries: List[Double], promotionFunction: Double => Double): List[Double] =
+ salaries.map(promotionFunction)
+
+ def smallPromotion(salaries: List[Double]): List[Double] =
+ promotion(salaries, salary => salary * 1.1)
+
+ def greatPromotion(salaries: List[Double]): List[Double] =
+ promotion(salaries, salary => salary * math.log(salary))
+
+ def hugePromotion(salaries: List[Double]): List[Double] =
+ promotion(salaries, salary => salary * salary)
+}
+```
+
+La nouvelle méthode, `promotion`, prend les salaires plus une fonction du type `Double => Double` (càd. une fonction qui prend un Double et retourne un Double) et retourne le produit.
+
+Les méthodes et les fonctions expriment généralement des comportements ou des transformations de données, donc avoir des fonctions qui composent en se basant sur d'autres fonctions peut aider à construire des mécanismes génériques. Ces opérations génériques reportent le verrouillage de l'intégralité du comportement de l'opération, donnant aux clients un moyen de contrôler ou de personnaliser davantage certaines parties de l'opération elle-même.
+
+## Les fonctions qui retournent des fonctions
+
+Il y a certains cas ou vous voulez générer une fonction. Voici un exemple de méthode qui retourne une fonction.
+
+```scala mdoc
+def urlBuilder(ssl: Boolean, domainName: String): (String, String) => String = {
+ val schema = if (ssl) "https://" else "http://"
+ (endpoint: String, query: String) => s"$schema$domainName/$endpoint?$query"
+}
+
+val domainName = "www.example.com"
+def getURL = urlBuilder(ssl=true, domainName)
+val endpoint = "users"
+val query = "id=1"
+val url = getURL(endpoint, query) // "https://www.example.com/users?id=1": String
+```
+
+Notez le type de retour de urlBuilder `(String, String) => String`. Cela veut dire que la fonction anonyme retournée prend deux Strings et retourne une String. Dans ce cas, la fonction anonyme retournée est `(endpoint: String, query: String) => s"https://www.example.com/$endpoint?$query"`
+
+Traduit par Antoine Pointeau.
\ No newline at end of file
diff --git a/_fr/tour/implicit-conversions.md b/_fr/tour/implicit-conversions.md
new file mode 100644
index 0000000000..1030827e4b
--- /dev/null
+++ b/_fr/tour/implicit-conversions.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Implicit Conversions
+partof: scala-tour
+
+num: 25
+
+language: fr
+
+next-page: polymorphic-methods
+previous-page: implicit-parameters
+---
diff --git a/_fr/tour/implicit-parameters.md b/_fr/tour/implicit-parameters.md
new file mode 100644
index 0000000000..236dd136f5
--- /dev/null
+++ b/_fr/tour/implicit-parameters.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Implicit Parameters
+partof: scala-tour
+
+num: 24
+
+language: fr
+
+next-page: implicit-conversions
+previous-page: self-types
+---
diff --git a/_fr/tour/inner-classes.md b/_fr/tour/inner-classes.md
new file mode 100644
index 0000000000..a5df305ce5
--- /dev/null
+++ b/_fr/tour/inner-classes.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Inner Classes
+partof: scala-tour
+
+num: 20
+
+language: fr
+
+next-page: abstract-type-members
+previous-page: lower-type-bounds
+---
diff --git a/_fr/tour/lower-type-bounds.md b/_fr/tour/lower-type-bounds.md
new file mode 100644
index 0000000000..eb6ffb785c
--- /dev/null
+++ b/_fr/tour/lower-type-bounds.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Lower Type Bounds
+partof: scala-tour
+
+num: 19
+
+language: fr
+
+next-page: inner-classes
+previous-page: upper-type-bounds
+---
diff --git a/_fr/tour/mixin-class-composition.md b/_fr/tour/mixin-class-composition.md
new file mode 100644
index 0000000000..8d1b823c11
--- /dev/null
+++ b/_fr/tour/mixin-class-composition.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Class Composition with Mixins
+partof: scala-tour
+
+num: 6
+
+language: fr
+
+next-page: higher-order-functions
+previous-page: tuples
+---
diff --git a/_fr/tour/multiple-parameter-lists.md b/_fr/tour/multiple-parameter-lists.md
new file mode 100644
index 0000000000..476e918cc1
--- /dev/null
+++ b/_fr/tour/multiple-parameter-lists.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Multiple Parameter Lists (Currying)
+partof: scala-tour
+
+num: 9
+
+language: fr
+
+next-page: case-classes
+previous-page: nested-functions
+---
diff --git a/_fr/tour/named-arguments.md b/_fr/tour/named-arguments.md
new file mode 100644
index 0000000000..fec11428a3
--- /dev/null
+++ b/_fr/tour/named-arguments.md
@@ -0,0 +1,34 @@
+---
+layout: tour
+title: Named Arguments
+partof: scala-tour
+
+num: 6
+
+language: fr
+
+next-page: traits
+previous-page: default-parameter-values
+---
+
+En appelant des méthodes, vous pouvez nommer leurs arguments comme ceci :
+
+```scala mdoc
+def printName(first: String, last: String): Unit = {
+ println(first + " " + last)
+}
+
+printName("John", "Smith") // Prints "John Smith"
+printName(first = "John", last = "Smith") // Prints "John Smith"
+printName(last = "Smith", first = "John") // Prints "John Smith"
+```
+
+Notez comment l'ordre des arguments nommés peut être réarrangé. Cependant, si certains arguments sont nommés et d'autres non, les arguments non nommés doivent venir en premier et suivrent l'ordre de leurs paramètres dans la signature de la méthode.
+
+```scala mdoc:fail
+printName(last = "Smith", "john") // erreur: argument positionnel après un argument nommé
+```
+
+Les arguments nommés fonctionnent avec les appels de méthodes Java, mais seulement si la librairie Java en question a été compilée avec `-parameters`.
+
+Traduction par Antoine Pointeau.
\ No newline at end of file
diff --git a/_fr/tour/nested-functions.md b/_fr/tour/nested-functions.md
new file mode 100644
index 0000000000..f92045364f
--- /dev/null
+++ b/_fr/tour/nested-functions.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Nested Methods
+partof: scala-tour
+
+num: 8
+
+language: fr
+
+next-page: multiple-parameter-lists
+previous-page: higher-order-functions
+---
diff --git a/_fr/tour/operators.md b/_fr/tour/operators.md
new file mode 100644
index 0000000000..59c697727e
--- /dev/null
+++ b/_fr/tour/operators.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Operators
+partof: scala-tour
+
+num: 28
+
+language: fr
+
+next-page: by-name-parameters
+previous-page: type-inference
+---
diff --git a/_fr/tour/package-objects.md b/_fr/tour/package-objects.md
new file mode 100644
index 0000000000..80cfb5e055
--- /dev/null
+++ b/_fr/tour/package-objects.md
@@ -0,0 +1,9 @@
+---
+layout: tour
+title: Package Objects
+language: fr
+partof: scala-tour
+
+num: 36
+previous-page: packages-and-imports
+---
diff --git a/_fr/tour/packages-and-imports.md b/_fr/tour/packages-and-imports.md
new file mode 100644
index 0000000000..8edac3b01c
--- /dev/null
+++ b/_fr/tour/packages-and-imports.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Packages and Imports
+partof: scala-tour
+
+num: 33
+
+language: fr
+
+previous-page: named-arguments
+next-page: package-objects
+---
diff --git a/_fr/tour/pattern-matching.md b/_fr/tour/pattern-matching.md
new file mode 100644
index 0000000000..1cd3731b9a
--- /dev/null
+++ b/_fr/tour/pattern-matching.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Pattern Matching
+partof: scala-tour
+
+num: 11
+
+language: fr
+
+next-page: singleton-objects
+previous-page: case-classes
+---
diff --git a/_fr/tour/polymorphic-methods.md b/_fr/tour/polymorphic-methods.md
new file mode 100644
index 0000000000..6375d54957
--- /dev/null
+++ b/_fr/tour/polymorphic-methods.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Polymorphic Methods
+partof: scala-tour
+
+num: 26
+
+language: fr
+
+next-page: type-inference
+previous-page: implicit-conversions
+---
diff --git a/_fr/tour/regular-expression-patterns.md b/_fr/tour/regular-expression-patterns.md
new file mode 100644
index 0000000000..253da8efa6
--- /dev/null
+++ b/_fr/tour/regular-expression-patterns.md
@@ -0,0 +1,63 @@
+---
+layout: tour
+title: Regular Expression Patterns
+partof: scala-tour
+
+num: 17
+
+language: fr
+
+next-page: extractor-objects
+previous-page: singleton-objects
+---
+
+Les expressions régulières sont des chaînes de caractères qui peuvent être utilisées pour trouver des motifs (ou l'absence de motif) dans un texte. Toutes les chaînes de caractères peuvent être converties en expressions régulières en utilisant la méthode `.r`.
+
+```scala mdoc
+import scala.util.matching.Regex
+
+val numberPattern: Regex = "[0-9]".r
+
+numberPattern.findFirstMatchIn("awesomepassword") match {
+ case Some(_) => println("Password OK")
+ case None => println("Password must contain a number")
+}
+```
+
+Dans l'exemple ci-dessus, `numberPattern` est une `Regex` (EXpression REGulière) que nous utilisons pour vérifier que le mot de passe contient un nombre.
+
+Vous pouvez aussi faire des recherches de groupes d'expressions régulières en utilisant les parenthèses.
+
+```scala mdoc
+import scala.util.matching.Regex
+
+val keyValPattern: Regex = "([0-9a-zA-Z- ]+): ([0-9a-zA-Z-#()/. ]+)".r
+
+val input: String =
+ """background-color: #A03300;
+ |background-image: url(img/header100.png);
+ |background-position: top center;
+ |background-repeat: repeat-x;
+ |background-size: 2160px 108px;
+ |margin: 0;
+ |height: 108px;
+ |width: 100%;""".stripMargin
+
+for (patternMatch <- keyValPattern.findAllMatchIn(input))
+ println(s"key: ${patternMatch.group(1)} value: ${patternMatch.group(2)}")
+```
+
+Ici nous analysons les clefs et les valeurs d'une chaîne de caractère. Chaque correspondance a un groupe de sous-correspondances. Voici le résultat :
+
+```
+key: background-color value: #A03300
+key: background-image value: url(img/header100.png)
+key: background-position value: top center
+key: background-repeat value: repeat-x
+key: background-size value: 2160px 108px
+key: margin value: 0
+key: height value: 108px
+key: width value: 100
+```
+
+Traduit par Antoine Pointeau.
\ No newline at end of file
diff --git a/_fr/tour/self-types.md b/_fr/tour/self-types.md
new file mode 100644
index 0000000000..9d82783417
--- /dev/null
+++ b/_fr/tour/self-types.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Self-types
+partof: scala-tour
+
+num: 23
+
+language: fr
+
+next-page: implicit-parameters
+previous-page: compound-types
+---
diff --git a/_fr/tour/singleton-objects.md b/_fr/tour/singleton-objects.md
new file mode 100644
index 0000000000..073dfaf5ec
--- /dev/null
+++ b/_fr/tour/singleton-objects.md
@@ -0,0 +1,120 @@
+---
+layout: tour
+title: Singleton Objects
+partof: scala-tour
+
+num: 15
+
+language: fr
+
+next-page: regular-expression-patterns
+previous-page: pattern-matching
+---
+
+Un objet est une classe qui a exactement une instance. Il est créé de façon paresseuse au moment où il est référencé, comme une valeur paresseuse `lazy val`.
+
+En tant que valeur de premier niveau, un objet est un singleton.
+
+En tant que membre d'une classe englobante ou en tant que valeur locale, il se comporte exactement comme une `lazy val`.
+
+# Définir un objet singleton
+
+Un objet est une valeur. La définition d'un objet ressemble a une classe, mais utilise le mot clef `object` :
+
+```scala mdoc
+object Box
+```
+
+Voici un exemple d'un objet avec une méthode :
+
+```
+package logging
+
+object Logger {
+ def info(message: String): Unit = println(s"INFO: $message")
+}
+```
+
+La méthode `info` peut être importée depuis n'importe où dans le programme. Créer des méthodes utilitaires, comme celle-ci, est un cas d'usage commun pour les objets singleton.
+
+Regardons comment utiliser `info` dans un autre package :
+
+```
+import logging.Logger.info
+
+class Project(name: String, daysToComplete: Int)
+
+class Test {
+ val project1 = new Project("TPS Reports", 1)
+ val project2 = new Project("Website redesign", 5)
+ info("Created projects") // Prints "INFO: Created projects"
+}
+```
+
+La méthode `info` est visible grâce à l'import, `import logging.Logger.info`. Les imports ont besoin d'un chemin d'accès stable aux ressources, et un objet est un chemin stable.
+
+Note : Si un `objet` est encapsulé dans une autre classe ou un autre objet, alors l'objet est dépendant du chemin d'accès, comme les autres membres. Cela veut dire, par exemple, que si on prend 2 types de boissons, `class Milk` et `class OrangeJuice`, un membre de classe `object NutritionInfo` est dépendant de son instance d'encapsulation. `milk.NutritionInfo` est complètement différent de `oj.NutritionInfo`.
+
+## Les objets compagnons
+
+Un objet avec le même nom qu'une classe est appelé un _objet compagnon_. Inversement, la classe se nomme la _classe compagnon_ de l'objet. Une classe ou un objet compagnon peut accéder aux membres privés de son compagnon. L'objet compagnon est utile pour les méthodes et les valeurs qui ne sont pas spécifiques aux instances de la classe compagnon.
+
+```
+import scala.math._
+
+case class Circle(radius: Double) {
+ import Circle._
+ def area: Double = calculateArea(radius)
+}
+
+object Circle {
+ private def calculateArea(radius: Double): Double = Pi * pow(radius, 2.0)
+}
+
+val circle1 = Circle(5.0)
+
+circle1.area
+```
+
+La classe `class Circle` a un membre `area` qui est spécifique à chaque instance, et un singleton `object Circle` qui a une méthode `calculateArea` qui est disponible pour chaque instance.
+
+L'objet compagnon peut aussi contenir des méthodes de fabrique (_factory_) :
+
+```scala mdoc
+class Email(val username: String, val domainName: String)
+
+object Email {
+ def fromString(emailString: String): Option[Email] = {
+ emailString.split('@') match {
+ case Array(a, b) => Some(new Email(a, b))
+ case _ => None
+ }
+ }
+}
+
+val scalaCenterEmail = Email.fromString("scala.center@epfl.ch")
+scalaCenterEmail match {
+ case Some(email) => println(
+ s"""Registered an email
+ |Username: ${email.username}
+ |Domain name: ${email.domainName}
+ """.stripMargin)
+ case None => println("Error: could not parse email")
+}
+```
+
+L'objet `object Email` contient une méthode de fabrique `fromString` qui créé une instance de `Email` depuis une chaîne de caractères. L'instance est retournée en tant que `Option[Email]` pour gérer le cas des erreurs de syntaxe.
+
+Note : Si une classe ou un objet a un compagnon, tous deux doivent être définis dans le même fichier. Pour définir des compagnons dans le REPL, tous deux doivent être définis sur la même ligne ou définis en mode `:paste`.
+
+## Notes pour les programmeurs Java
+
+Les membres `static` en Java sont modélisés comme des membres ordinaires d'un objet compagnon en Scala.
+
+Lorsqu'on utilise un objet compagnon depuis du code Java, ses membres sont définis dans la classe compagnon avec le modificateur `static`. Cela s'appelle le _static forwarding_. Cela se produit même si vous n'avez pas défini de classe compagnon vous-même.
+
+## Plus d'informations
+
+* Apprenez-en plus sur les objets compagnons dans le [Scala Book](/overviews/scala-book/companion-objects.html)
+
+Traduit par Antoine Pointeau.
diff --git a/_fr/tour/tour-of-scala.md b/_fr/tour/tour-of-scala.md
new file mode 100644
index 0000000000..f5d0f5d20a
--- /dev/null
+++ b/_fr/tour/tour-of-scala.md
@@ -0,0 +1,90 @@
+---
+layout: tour
+title: Introduction
+partof: scala-tour
+
+num: 1
+language: fr
+next-page: basics
+
+---
+
+## Bienvenue au tour
+Ce tour contient une introduction morceaux par morceaux aux fonctionnalités les plus fréquemment
+utilisées en Scala. Il est adressé aux novices de Scala.
+
+Ceci est un bref tour du language, non pas un tutoriel complet.
+Si vous recherchez un guide plus détaillé, il est préférable d'opter pour [un livre](/books.html) ou de suivre
+[un cours en ligne](/online-courses.html).
+
+## Qu'est-ce que le Scala ?
+Scala est un langage de programmation à multiples paradigmes désigné pour exprimer des motifs de programmation communs de
+façon concise, élégante et robuste. Il intègre sans problème les fonctionnalités des langages orientés objet et des
+langages fonctionnels.
+
+## Scala est orienté objet ##
+Scala est un langage purement orienté objet dans le sens où [toute valeur est un objet](unified-types.html).
+Les types et les comportements de ces objets sont décrits par des [classes](classes.html) et des trait [traits](traits.html).
+Les classes peuvent être étendues à travers des sous-classes et grâce à un système flexible de [composition de classes](mixin-class-composition.html).
+
+## Scala est fonctionnel ##
+Scala est également un langage fonctionnel dans le sen où [toute fonction est une valeur](unified-types.html).
+Scala propose une [syntaxe légère](basics.html) pour définir des fonctions anonymes, supporte des
+[fonctions de haut niveau](higher-order-functions.html), autorise les fonctions [imbriquées](nested-functions.html) et
+supporte le [currying](multiple-parameter-lists.html).
+Les [case class](case-classes.html) de Scala et leur système intégré de [reconnaissance de motifs](pattern-matching.html)
+permettent de construire des types algébriques utilisés dans de nombreux langages de programmation.
+Les [objets singleton](singleton-objects.html) fournissent une façon pratique de regrouper des fonctions qui ne sont pas
+membres d'une classe.
+
+De plus, la notion de reconnaissance de motifs de Scala s'étend naturellement au
+[traitement des données XML](https://github.com/scala/scala-xml/wiki/XML-Processing) avec l'aide des
+[patrons d'expressions régulières](regular-expression-patterns.html), grâce à une extension générale via des
+[objets extracteurs](extractor-objects.html). Dans ce contexte, les [for comprehensions](for-comprehensions.html) sont
+utiles pour formuler des requêtes. Ces fonctionnalités font de Scala un langage idéal pour développer des applications
+comme des services Web.
+
+## Scala est fortement typé ##
+A la compilation, le système de type expressif de Scala renforce l'utilisation des abstractions d'une manière
+sécurisée et cohérente. En particulier, ce système de type supporte :
+
+* Les [classes génériques](generic-classes.html)
+* Les [annotations variables](variances.html)
+* Les limites de type [supérieures](upper-type-bounds.html) and [inférieures](lower-type-bounds.html)
+* Les [classes internes](inner-classes.html) et les membres d'objets de [types abstraits](abstract-type-members.html)
+* Les [types composés](compound-types.html)
+* Les [auto-références explicitement typées](self-types.html)
+* Les [paramètres](implicit-parameters.html) et les [conversions](implicit-conversions.html) implicites
+* Les [méthodes polymorphiques](polymorphic-methods.html)
+
+L'[inférence de type](type-inference.html) signifie que l'utilisateur n'est pas obligé d'annoter son code avec des
+informations redondantes. Rassemblées, toutes ces fonctionnalités fournissent une base solide pour la ré-utilisation
+sécurisée d'abstractions de programmation et pour une extension sûre au niveau des types de programme.
+
+## Scala est extensible ##
+
+En pratique, le développement d'applications dans un domaine spécifique demande souvent des extensions de langage propre
+à ce domaine. Scala fournit une combinaison de mécaniques de langage unique qui rend simple l'ajout de nouvelles
+constructions de langage avec l'importation de nouvelles librairies.
+
+Dans beaucoup de cas, cela peut être fait sans utiliser des outils de méta-programmation, comme les macros.
+En voici quelques exemples :
+
+* Les [classes implicites](/overviews/core/implicit-classes.html) permettent d'ajouter des méthodes supplémentaires à des types existants.
+* L'[interpolation de String](/overviews/core/string-interpolation.html) est extensible par l'utilisateur avec des interpolateurs personnalisés.
+
+## Scala interagit ##
+
+Scala est conçu pour interagir proprement avec le populaire Java Runtime Environment (JRE). En particulier, l'interaction
+avec le langage de programmation orienté objet le plus populaire du moment, Java, est la plus transparente possible.
+Les nouvelles fonctionnalités Java comme les SAMs, les [lambdas](higher-order-functions.html), les [annotations](annotations.html),
+et les [classes génériques](generic-classes.html) ont des équivalents directs en Scala.
+
+Il existe des fonctionnalités Scala sans équivalent Java, comme les [valeurs par défaut](default-parameter-values.html) et les
+[paramètres nommés](named-arguments.html), qui se compilent d'une façon la plus proche de Java possible. Scala possède le
+même modèle de compilation que Java (compilation séparée, chargement dynamique des classes) et permet d'avoir accès à des
+milliers de librairies de haute qualité.
+
+## Bon tour !
+
+Merci de continuer à la [page suivante](basics.html) pour en savoir plus.
diff --git a/_fr/tour/traits.md b/_fr/tour/traits.md
new file mode 100644
index 0000000000..069648bb53
--- /dev/null
+++ b/_fr/tour/traits.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Traits
+partof: scala-tour
+
+num: 5
+
+language: fr
+
+next-page: tuples
+previous-page: classes
+---
diff --git a/_fr/tour/tuples.md b/_fr/tour/tuples.md
new file mode 100644
index 0000000000..edef97a6ca
--- /dev/null
+++ b/_fr/tour/tuples.md
@@ -0,0 +1,82 @@
+---
+layout: tour
+title: Tuples
+partof: scala-tour
+
+num: 8
+
+language: fr
+
+next-page: mixin-class-composition
+previous-page: traits
+---
+
+En Scala, un tuple est une valeur qui contient un nombre fixe d'éléments, chacun avec son propre type. Les tuples sont immuables.
+
+Les tuples sont notamment utiles pour retourner plusieurs valeurs depuis une méthode.
+
+Un tuple avec deux éléments peut être créé de la façon suivante :
+
+```scala mdoc
+val ingredient = ("Sugar" , 25)
+```
+
+Cela crée un tuple contenant un élément de type `String` et un élément de type `Int`.
+
+Le type inféré de `ingredient` est `(String, Int)`, qui est un raccourci pour `Tuple2[String, Int]`.
+
+Pour représenter les tuples, Scala utilise une série de classes : `Tuple2`, `Tuple3`, etc., jusqu'a `Tuple22`.
+Chaque classe a autant de paramètres de types qu'elle a d'éléments.
+
+## Accéder aux éléments
+
+Une des méthodes pour accéder aux éléments d'un tuple est par position. Les éléments sont nommés individuellement `_1`, `_2`, et ainsi de suite.
+
+```scala mdoc
+println(ingredient._1) // Sugar
+println(ingredient._2) // 25
+```
+
+## Pattern matching sur les tuples
+
+Un tuple peut aussi être décomposé en utilisant le pattern matching :
+
+```scala mdoc
+val (name, quantity) = ingredient
+println(name) // Sugar
+println(quantity) // 25
+```
+
+Ici le type inféré de `name` est `String` et le type inféré de `quantity` est `Int`.
+
+Voici un autre exemple de pattern-matching sur un tuple :
+
+```scala mdoc
+val planets =
+ List(("Mercury", 57.9), ("Venus", 108.2), ("Earth", 149.6),
+ ("Mars", 227.9), ("Jupiter", 778.3))
+planets.foreach {
+ case ("Earth", distance) =>
+ println(s"Our planet is $distance million kilometers from the sun")
+ case _ =>
+}
+```
+
+Ou, en décomposition dans un `for` :
+
+```scala mdoc
+val numPairs = List((2, 5), (3, -7), (20, 56))
+for ((a, b) <- numPairs) {
+ println(a * b)
+}
+```
+
+## Les tuples et les classes de cas
+
+Les utilisateurs trouvent parfois qu'il est difficile de choisir entre les tuples et les classes de cas. Les classes de cas ont des éléments nommés. Les noms peuvent améliorer la lisibilité de certains codes. Dans l'exemple ci-dessus avec planet, nous pourrions définir `case class Planet(name: String, distance: Double)` plutôt que d'utiliser les tuples.
+
+## Plus d'informations
+
+* Apprennez-en d'avantage sur les tuples dans [Scala Book](/overviews/scala-book/tuples.html)
+
+Traduction par Antoine Pointeau.
\ No newline at end of file
diff --git a/_fr/tour/type-inference.md b/_fr/tour/type-inference.md
new file mode 100644
index 0000000000..019ed21ef5
--- /dev/null
+++ b/_fr/tour/type-inference.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Type Inference
+partof: scala-tour
+
+num: 27
+
+language: fr
+
+next-page: operators
+previous-page: polymorphic-methods
+---
diff --git a/_fr/tour/unified-types.md b/_fr/tour/unified-types.md
new file mode 100644
index 0000000000..6ecf013319
--- /dev/null
+++ b/_fr/tour/unified-types.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Unified Types
+partof: scala-tour
+
+num: 3
+
+language: fr
+
+next-page: classes
+previous-page: basics
+---
diff --git a/_fr/tour/upper-type-bounds.md b/_fr/tour/upper-type-bounds.md
new file mode 100644
index 0000000000..f47c6a4e30
--- /dev/null
+++ b/_fr/tour/upper-type-bounds.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Upper Type Bounds
+partof: scala-tour
+
+num: 18
+
+language: fr
+
+next-page: lower-type-bounds
+previous-page: variances
+---
diff --git a/_fr/tour/variances.md b/_fr/tour/variances.md
new file mode 100644
index 0000000000..5f535d303b
--- /dev/null
+++ b/_fr/tour/variances.md
@@ -0,0 +1,12 @@
+---
+layout: tour
+title: Variance
+partof: scala-tour
+
+num: 17
+
+language: fr
+
+next-page: upper-type-bounds
+previous-page: generic-classes
+---
diff --git a/_fr/tutorials/scala-for-java-programmers.md b/_fr/tutorials/scala-for-java-programmers.md
index b89649f1fa..0b9d3ffa63 100644
--- a/_fr/tutorials/scala-for-java-programmers.md
+++ b/_fr/tutorials/scala-for-java-programmers.md
@@ -20,9 +20,9 @@ des connaissances de base sur la programmation orientée objet, particulièremen
## Un premier exemple
-Commençons par écrire le célèbre programme *Hello world*.
+Commençons par écrire le célèbre programme *Hello world*.
Bien que simple, il permet de découvrir plusieurs fonctionnalités du language
-avec peu de de connaissance préalable de Scala. Voilà à quoi il ressemble :
+avec peu de connaissance préalable de Scala. Voilà à quoi il ressemble :
object HelloWorld {
def main(args: Array[String]): Unit = {
@@ -106,7 +106,7 @@ l'astérisque (`*`). C'est parce que l'astérisque est un identifiant valide en
un nom de méthode), comme nous le verrons plus tard.
Par conséquent, la déclaration d'importation dans la seconde ligne importe tous les membres de la classe
-`DateFormat`. Cela rend la méthode statique `getDateInstance` et le champ statiques `LONG`
+`DateFormat`. Cela rend la méthode statique `getDateInstance` et le champ statique `LONG`
directement visibles.
Dans la méthode `main`, nous avons tout d'abord créé une instance de la classe Java `Date`
@@ -141,7 +141,7 @@ De fait, une expression arithmétique comme la suivante :
1 + 2 * 3 / x
-consiste exclusivement en des appels de méthodes, parce qu il est équivalent à l'expression
+consiste exclusivement en des appels de méthodes, parce qu'il est équivalent à l'expression
suivante, comme nous l'avons vu dans la section précédente :
1.+(2.*(3)./(x)
@@ -250,7 +250,7 @@ malheureusement aucune règle simple pour savoir dans quel cas il est capable de
ce n'est pas généralement un problème car le compilateur se plaint quand il n'est pas capable d'inférer
un type qui n'a pas été donné explicitement. Une règle simple que les développeurs débutant en Scala
devraient suivre est d'essayer d'omettre les déclarations de type qui semblent être faciles à
-déduire et voir si le compilateur ne renvoie pas d'erreur. Après quelques temps, le développeur devrait
+déduire et voir si le compilateur ne renvoie pas d'erreur. Après quelque temps, le développeur devrait
avoir une bonne idée de quand il peut omettre les types et quand il faut les spécifier explicitement.
### Les méthodes sans arguments
@@ -267,7 +267,7 @@ leur nom pour les appeler, comme démontré dans l'exemple suivant :
Il serait plus agréable de pouvoir accéder à la partie réelle et imaginaire comme si elles étaient des
champs, sans ajouter une paire de parenthèses vides. C'est parfaitement faisable en Scala, simplement en
-les définissant comme des méthodes *sans argument*. De telles méthodes différents des méthodes avec
+les définissant comme des méthodes *sans argument*. De telles méthodes diffèrent des méthodes avec
aucun argument : elles n'ont pas de parenthèses après leur nom, que ce soit dans leur déclaration
ou lors de leur utilisation. Notre classe `Complexe` peut être réécrite de cette façon :
@@ -317,11 +317,11 @@ simples composées de sommes, de constantes numériques et de variables. Deux ex
sont `1+2` et `(x+x)+(7+y)`.
Nous devons d'abord décider d'une représentation pour de telles expressions.
-La manière la plus naturelle est un arbre où chaque noeud représente une opération (ici, une addition) et
+La manière la plus naturelle est un arbre où chaque nœud représente une opération (ici, une addition) et
chaque feuille est une valeur (ici des constantes ou variables).
En Java, un tel arbre serait représenté par une super classe abstraite pour les arbres et une
-sous classe concrète pour chaque noeud et feuille. Dans un langage de programmation fonctionnelle,
+sous classe concrète pour chaque nœud et feuille. Dans un langage de programmation fonctionnelle,
on utiliserait plutôt un type de donnée algébrique pour faire la même chose. Scala fournit le concept de
*case class* qui est quelque part entre ces deux concepts. Voici comment elles peuvent être utilisées pour
définir le type des arbres pour notre exemple :
@@ -347,7 +347,7 @@ différent des classes traditionnelles en différents points :
comme nous le verrons plus bas.
Maintenant que nous avons défini le type de données pour représenter nos expressions arithmétiques,
-il est temps de définir des opérations pour les manipuler. Nous allons commencer avec une fonction
+il est temps de définir des opérations pour les manipuler. Nous allons commencer par une fonction
pour évaluer une expression dans un certain *environnement*. Le but de cet environnement est de
donner des valeurs aux variables. Par exemple, l'expression `x+1` évaluée dans un environnement qui
associe la valeur `5` à la variable `x`, écrit `{ x -> 5 }`, donne comme résultat `6`.
@@ -398,11 +398,11 @@ devrait être claire :
motif décrit à gauche de la flèche ;
2. Si la première vérification échoue, c'est-à-dire que l'arbre n'est pas une `Somme`,
on continue et on vérifie si `a` est une `Var`. Si c'est le cas,
- il relie le nom contenu dans le noeud `Var` à une variable `n` et
+ il relie le nom contenu dans le nœud `Var` à une variable `n` et
il traite l'expression à droite de la flèche ;
3. Si la deuxième vérification échoue, c'est-à-dire que l'arbre n'est ni
une `Somme` ni une `Var`, on vérifie si l'arbre est un `Const`. Si
- c'est le cas, il relie la valeur contenue dans le noeud `Const` à une
+ c'est le cas, il relie la valeur contenue dans le nœud `Const` à une
variable `v` et il traite l'expression à droite de la flèche ;
4. Enfin, si toutes les vérifications échouent, une exception est levée pour signaler
l'échec de l'expression. Dans notre cas, cela pourrait arriver si
@@ -420,13 +420,13 @@ la définition de méthodes dans les case class tout comme dans les classes norm
Décider d'utiliser un pattern matching ou des méthodes est donc une question de
goût mais a aussi des implications importantes sur l'extensibilité :
-- quand on utilise des méthodes, il est facile d'ajouter un nouveau type de noeud en même temps
+- quand on utilise des méthodes, il est facile d'ajouter un nouveau type de nœud en même temps
qu'une nouvelle sous classe de `Arbre` est définie. Par contre,
ajouter une nouvelle opération pour manipuler un arbre est
fastidieux car il demande de modifier toutes les sous classes de `Arbre` ;
- quand on utilise un pattern matching, la situation est inversée : ajouter un
- nouveau type de noeud demande la modification de toutes les fonctions qui effectuent
- un pattern matching sur un arbre pour prendre en compte le nouveau noeud.
+ nouveau type de nœud demande la modification de toutes les fonctions qui effectuent
+ un pattern matching sur un arbre pour prendre en compte le nouveau nœud.
Par contre, ajouter une nouvelle opération est facile en la définissant
en tant que fonction indépendante.
@@ -439,7 +439,7 @@ garder à l'esprit les règles suivantes par rapport à cette opération :
variable utilisée pour la dérivation et zéro sinon ;
3. la dérivée d'une constante est zéro.
-Ces règles peut être traduites presque littéralement en du code Scala
+Ces règles peuvent presque être traduites littéralement en du code Scala
pour obtenir la définition suivante :
def derivee(a: Arbres, v: String): Arbres = a match {
@@ -503,7 +503,7 @@ Notez que depuis Java 8, les interfaces Java peut aussi contenir du code, soit
en utilisant le mot clé `default` soit avec des méthodes statiques.
Pour s'apercevoir de l'utilité des traits, regardons un exemple classique :
-les objets ordonnés. Il est souvent utile de pouvoir comparer entre eux des objets
+les objets ordonnés. Il est souvent utile de pouvoir comparer des objets
d'une même classe, par exemple pour les trier. En Java,
les objets qui sont comparables implémentent l'interface `Comparable`.
En Scala, on peut faire un peu mieux qu'en Java en définissant
@@ -616,7 +616,7 @@ Les développeurs Java se retrouvent à utiliser `Object`, le super type de
tous les objets. Cependant, cette solution est loin d'être
idéale, puisqu'elle ne marche pas pour les types basiques (`int`,
`long`, `float`, etc.) et cela implique que le développeur
-devra faire un certain nombre de conversion de types.
+devra faire un certain nombre de conversions de types.
Scala rend possible la définition de classes (et de méthodes) génériques pour
résoudre ce problème. Examinons ceci au travers d'un exemple d'une
diff --git a/_getting-started/index.md b/_getting-started/index.md
deleted file mode 100644
index 77147fc08c..0000000000
--- a/_getting-started/index.md
+++ /dev/null
@@ -1,61 +0,0 @@
----
-layout: singlepage-overview
-title: Getting Started
-partof: getting-started
-languages: [ja]
-includeTOC: true
-
-redirect_from: "/getting-started.html"
----
-
-There are __two__ main ways people prefer to work in Scala:
-
-* Using an IDE.
-* Using the command line.
-
-The following tutorials will walk you through the setup process for whichever way
-you prefer.
-
-However, if you just want to jump directly into Scala without installing anything, skip the guides on this page and check out:
-
-* [Our interactive introduction to Scala on scala-exercises.com](https://www.scala-exercises.org/scala_tutorial/terms_and_types), or
-* [Scastie](https://scastie.scala-lang.org/), Scala in the browser, with access to all Scala compilers and all published libraries!
-
-## Setting up and getting started with Scala
-
-### If you prefer working in an IDE...
-
-IntelliJ is the most commonly-used IDE by Scala developers. In this tutorial,
-we'll walk you through downloading and setting up IntelliJ with the Scala
-plugin, and we'll get you started with your first Scala project, complete with
-unit tests!
-
-* [Getting Started with Scala in IntelliJ](/getting-started/intellij-track/getting-started-with-scala-in-intellij.html)
-* [Building a Scala Project with IntelliJ and sbt](/getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.html)
-* [Testing Scala in IntelliJ with ScalaTest](/getting-started/intellij-track/testing-scala-in-intellij-with-scalatest.html)
-
-
-### If you prefer working on the command line...
-
-If you prefer using a text editor like emacs, Vim, Atom, or Sublime Text, then
-the best way to compile, test, and run Scala code is by using _sbt_, Scala's build
-tool.
-
-* [Getting Started with Scala and sbt on the Command Line](/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.html)
-* [Testing Scala with sbt and ScalaTest on the Command Line](/getting-started/sbt-track/testing-scala-with-sbt-on-the-command-line.html)
-
-
-
-## Next Steps
-Once you've finished these tutorials, check out:
-
-* [The Tour of Scala](/tour/tour-of-scala.html) for bite-sized introductions to Scala's features.
-* [The Scala Book](/overviews/scala-book/introduction.html), which provides a set of short lessons introducing Scala’s main features.
-* [Learning Resources](/learn.html), which includes online interactive tutorials and courses.
-* [Our list of some popular Scala books](/books.html).
-
-## Getting Help
-There are a multitude of mailing lists and real-time chat channels in case you want to quickly connect with other Scala users. Check out our [community](https://scala-lang.org/community/) page for a list of these resources, and for where to reach out for help.
diff --git a/_glossary/index.md b/_glossary/index.md
index 0778d19cd6..9d4d490c65 100644
--- a/_glossary/index.md
+++ b/_glossary/index.md
@@ -16,380 +16,380 @@ languages: [zh-cn]
-* #### algebraic data type
+* ### algebraic data type
A type defined by providing several alternatives, each of which comes with its own constructor. It usually comes with a way to decompose the type through pattern matching. The concept is found in specification languages and functional programming languages. Algebraic data types can be emulated in Scala with case classes.
-* #### alternative
+* ### alternative
A branch of a match expression. It has the form “`case` _pattern_ => _expression_.” Another name for alternative is _case_.
-* #### annotation
+* ### annotation
An annotation appears in source code and is attached to some part of the syntax. Annotations are computer processable, so you can use them to effectively add an extension to Scala.
-* #### anonymous class
+* ### anonymous class
An anonymous class is a synthetic subclass generated by the Scala compiler from a new expression in which the class or trait name is followed by curly braces. The curly braces contains the body of the anonymous subclass, which may be empty. However, if the name following new refers to a trait or class that contains abstract members, these must be made concrete inside the curly braces that define the body of the anonymous subclass.
-* #### anonymous function
+* ### anonymous function
Another name for [function literal](#function-literal).
-* #### apply
+* ### apply
You can apply a method, function, or closure to arguments, which means you invoke it on those arguments.
-* #### argument
+* ### argument
When a function is invoked, an argument is passed for each parameter of that function. The parameter is the variable that refers to the argument. The argument is the object passed at invocation time. In addition, applications can take (command line) arguments that show up in the `Array[String]` passed to main methods of singleton objects.
-* #### assign
+* ### assign
You can assign an object to a variable. Afterwards, the variable will refer to the object.
-* #### auxiliary constructor
+* ### auxiliary constructor
Extra constructors defined inside the curly braces of the class definition, which look like method definitions named `this`, but with no result type.
-* #### block
-One or more expressions and declarations surrounded by curly braces. When the block evaluates, all of its expressions and declarations are processed in order, and then the block returns the value of the last expression as its own value. Blocks are commonly used as the bodies of functions, [for expressions](#for-expression), `while` loops, and any other place where you want to group a number of statements together. More formally, a block is an encapsulation construct for which you can only see side effects and a result value. The curly braces in which you define a class or object do not, therefore, form a block, because fields and methods (which are defined inside those curly braces) are visible from the out- side. Such curly braces form a template.
+* ### block
+One or more expressions and declarations surrounded by curly braces. When the block evaluates, all of its expressions and declarations are processed in order, and then the block returns the value of the last expression as its own value. Blocks are commonly used as the bodies of functions, [for expressions](#for-expression), `while` loops, and any other place where you want to group a number of statements together. More formally, a block is an encapsulation construct for which you can only see side effects and a result value. The curly braces in which you define a class or object do not, therefore, form a block, because fields and methods (which are defined inside those curly braces) are visible from the outside. Such curly braces form a template.
-* #### bound variable
+* ### bound variable
A bound variable of an expression is a variable that’s both used and defined inside the expression. For instance, in the function literal expression `(x: Int) => (x, y)`, both variables `x` and `y` are used, but only `x` is bound, because it is defined in the expression as an `Int` and the sole argument to the function described by the expression.
-* #### by-name parameter
+* ### by-name parameter
A parameter that is marked with a `=>` in front of the parameter type, e.g., `(x: => Int)`. The argument corresponding to a by-name parameter is evaluated not before the method is invoked, but each time the parameter is referenced by name inside the method. If a parameter is not by-name, it is by-value.
-* #### by-value parameter
+* ### by-value parameter
A parameter that is not marked with a `=>` in front of the parameter type, e.g., `(x: Int)`. The argument corresponding to a by-value parameter is evaluated before the method is invoked. By-value parameters contrast with by-name parameters.
-* #### class
+* ### class
Defined with the `class` keyword, a _class_ may either be abstract or concrete, and may be parameterized with types and values when instantiated. In `new Array[String](2)`, the class being instantiated is `Array` and the type of the value that results is `Array[String]`. A class that takes type parameters is called a _type constructor_. A type can be said to have a class as well, as in: the class of type `Array[String]` is `Array`.
-* #### closure
+* ### closure
A function object that captures free variables, and is said to be “closed” over the variables visible at the time it is created.
-* #### companion class
+* ### companion class
A class that shares the same name with a singleton object defined in the same source file. The class is the singleton object’s companion class.
-* #### companion object
+* ### companion object
A singleton object that shares the same name with a class defined in the same source file. Companion objects and classes have access to each other’s private members. In addition, any implicit conversions defined in the companion object will be in scope anywhere the class is used.
-* #### contravariant
+* ### contravariant
A _contravariant_ annotation can be applied to a type parameter of a class or trait by putting a minus sign (-) before the type parameter. The class or trait then subtypes contravariantly with—in the opposite direction as—the type annotated parameter. For example, `Function1` is contravariant in its first type parameter, and so `Function1[Any, Any]` is a subtype of `Function1[String, Any]`.
-* #### covariant
+* ### covariant
A _covariant_ annotation can be applied to a type parameter of a class or trait by putting a plus sign (+) before the type parameter. The class or trait then subtypes covariantly with—in the same direction as—the type annotated parameter. For example, `List` is covariant in its type parameter, so `List[String]` is a subtype of `List[Any]`.
-* #### currying
+* ### currying
A way to write functions with multiple parameter lists. For instance `def f(x: Int)(y: Int)` is a curried function with two parameter lists. A curried function is applied by passing several arguments lists, as in: `f(3)(4)`. However, it is also possible to write a _partial application_ of a curried function, such as `f(3)`.
-* #### declare
+* ### declare
You can _declare_ an abstract field, method, or type, which gives an entity a name but not an implementation. The key difference between declarations and definitions is that definitions establish an implementation for the named entity, declarations do not.
-* #### define
+* ### define
To _define_ something in a Scala program is to give it a name and an implementation. You can define classes, traits, singleton objects, fields, methods, local functions, local variables, _etc_. Because definitions always involve some kind of implementation, abstract members are declared not defined.
-* #### direct subclass
+* ### direct subclass
A class is a _direct subclass_ of its direct superclass.
-* #### direct superclass
+* ### direct superclass
The class from which a class or trait is immediately derived, the nearest class above it in its inheritance hierarchy. If a class `Parent` is mentioned in a class `Child`’s optional extends clause, then `Parent` is the direct superclass of `Child`. If a trait is mentioned in `Child`’s extends clause, the trait’s direct superclass is the `Child`’s direct superclass. If `Child` has no extends clause, then `AnyRef` is the direct superclass of `Child`. If a class’s direct superclass takes type parameters, for example class `Child` extends `Parent[String]`, the direct superclass of `Child` is still `Parent`, not `Parent[String]`. On the other hand, `Parent[String]` would be the direct supertype of `Child`. See [supertype](#supertype) for more discussion of the distinction between class and type.
-* #### equality
+* ### equality
When used without qualification, _equality_ is the relation between values expressed by `==`. See also [reference equality](#reference-equality).
-* #### existential type
+* ### existential type
An existential type includes references to type variables that are unknown. For example, `Array[T] forSome { type T }` is an existential type. It is an array of `T`, where `T` is some completely unknown type. All that is assumed about `T` is that it exists at all. This assumption is weak, but it means at least that an `Array[T] forSome { type T }` is indeed an array and not a banana.
-* #### expression
+* ### expression
Any bit of Scala code that yields a result. You can also say that an expression _evaluates_ to a result or _results_ in a value.
-* #### filter
+* ### filter
An `if` followed by a boolean expression in a [for expression](#for-expression). In `for(i <- 1 to 10; if i % 2 == 0)`, the filter is “`if i % 2 == 0`”. The value to the right of the `if` is the [filter expression](#filter-expression). Also known as a guard.
-* #### filter expression
+* ### filter expression
A _filter expression_ is the boolean expression following an `if` in a [for expression](#for-expression). In `for( i <- 1 to 10 ; if i % 2 == 0)`,the filter expression is “`i % 2 == 0`”.
-* #### first-class function
+* ### first-class function
Scala supports _first-class functions_, which means you can express functions in function literal syntax, i.e., `(x: Int) => x + 1`, and that functions can be represented by objects, which are called [function values](#function-value).
-* #### for comprehension
+* ### for comprehension
A _for comprehension_ is a type of [for expression](#for-expression) that creates a new collection. For each iteration of the `for` comprehension, the [yield](#yield) clause defines an element of the new collection. For example, `for (i <- (0 until 2); j <- (2 until 4)) yield (i, j)` returns the collection `Vector((0,2), (0,3), (1,2), (1,3))`.
-* #### for expression
+* ### for expression
A _for expression_ is either a [for loop](#for-loop), which iterates over one or more collections, or a [for comprehension](#for-comprehension), which builds a new collection from the elements of one or more collections. A `for` expression is built up of [generators](#generator), [filters](#filter), variable definitions, and (in the case of [for comprehensions](#for-comprehension)) a [yield](#yield) clause.
-* #### for loop
+* ### for loop
A _for loop_ is a type of [for expression](#for-expression) that loops over one or more collections. Since `for` loops return unit, they usually produce side-effects. For example, `for (i <- 0 until 100) println(i)` prints the numbers 0 through 99.
-* #### free variable
+* ### free variable
A _free variable_ of an expression is a variable that’s used inside the expression but not defined inside the expression. For instance, in the function literal expression `(x: Int) => (x, y)`, both variables `x` and `y` are used, but only `y` is a free variable, because it is not defined inside the expression.
-* #### function
+* ### function
A _function_ can be [invoked](#invoke) with a list of arguments to produce a result. A function has a parameter list, a body, and a result type. Functions that are members of a class, trait, or singleton object are called [methods](#method). Functions defined inside other functions are called [local functions](#local-function). Functions with the result type of `Unit` are called [procedures](#procedure). Anonymous functions in source code are called [function literals](#function-literal). At run time, function literals are instantiated into objects called [function values](#function-value).
-* #### function literal
-A function with no name in Scala source code, specified with function literal syntax. For example, `(x: Int, y: Int) => x + y`.
+* ### function literal
+A function with no name in Scala source code, specified with _function literal_ syntax. For example, `(x: Int, y: Int) => x + y`.
-* #### function value
-A function object that can be invoked just like any other function. A function value’s class extends one of the `FunctionN` traits (e.g., `Function0`, `Function1`) from package `scala`, and is usually expressed in source code via [function literal](#function-literal) syntax. A function value is “invoked” when its apply method is called. A function value that captures free variables is a [closure](#closure).
+* ### function value
+A function object that can be invoked just like any other function. A _function value_’s class extends one of the `FunctionN` traits (e.g., `Function0`, `Function1`) from package `scala`, and is usually expressed in source code via [function literal](#function-literal) syntax. A function value is “invoked” when its apply method is called. A function value that captures free variables is a [closure](#closure).
-* #### functional style
+* ### functional style
The _functional style_ of programming emphasizes functions and evaluation results and deemphasizes the order in which operations occur. The style is characterized by passing function values into looping methods, immutable data, methods with no side effects. It is the dominant paradigm of languages such as Haskell and Erlang, and contrasts with the [imperative style](#imperative-style).
-* #### generator
-A generator defines a named val and assigns to it a series of values in a [for expression](#for-expression). For example, in `for(i <- 1 to 10)`, the generator is “`i <- 1 to 10`”. The value to the right of the `<-` is the [generator expression](#generator-expression).
+* ### generator
+A _generator_ defines a named val and assigns to it a series of values in a [for expression](#for-expression). For example, in `for(i <- 1 to 10)`, the generator is “`i <- 1 to 10`”. The value to the right of the `<-` is the [generator expression](#generator-expression).
-* #### generator expression
-A generator expression generates a series of values in a [for expression](#for-expression). For example, in `for(i <- 1 to 10)`, the generator expression is “`1 to 10`”.
+* ### generator expression
+A _generator expression_ generates a series of values in a [for expression](#for-expression). For example, in `for(i <- 1 to 10)`, the generator expression is “`1 to 10`”.
-* #### generic class
-A class that takes type parameters. For example, because `scala.List` takes a type parameter, `scala.List` is a generic class.
+* ### generic class
+A class that takes type parameters. For example, because `scala.List` takes a type parameter, `scala.List` is a _generic class_.
-* #### generic trait
-A trait that takes type parameters. For example, because trait `scala.collection.Set` takes a type parameter, it is a generic trait.
+* ### generic trait
+A trait that takes type parameters. For example, because trait `scala.collection.Set` takes a type parameter, it is a _generic trait_.
-* #### guard
+* ### guard
See [filter](#filter).
-* #### helper function
+* ### helper function
A function whose purpose is to provide a service to one or more other functions nearby. Helper functions are often implemented as local functions.
-* #### helper method
+* ### helper method
A [helper function](#helper-function) that’s a member of a class. Helper methods are often private.
-* #### immutable
+* ### immutable
An object is _immutable_ if its value cannot be changed after it is created in any way visible to clients. Objects may or may not be immutable.
-* #### imperative style
+* ### imperative style
The _imperative style_ of programming emphasizes careful sequencing of operations so that their effects happen in the right order. The style is characterized by iteration with loops, mutating data in place, and methods with side effects. It is the dominant paradigm of languages such as C, C++, C# and Java, and contrasts with the [functional style](#functional-style).
-* #### initialize
-When a variable is defined in Scala source code, you must initialize it with an object.
+* ### initialize
+When a variable is defined in Scala source code, you must _initialize_ it with an object.
-* #### instance
+* ### instance
An _instance_, or class instance, is an object, a concept that exists only at run time.
-* #### instantiate
+* ### instantiate
To _instantiate_ a class is to make a new object from the class, an action that happens only at run time.
-* #### invariant
+* ### invariant
_Invariant_ is used in two ways. It can mean a property that always holds true when a data structure is well-formed. For example, it is an invariant of a sorted binary tree that each node is ordered before its right subnode, if it has a right subnode. Invariant is also sometimes used as a synonym for nonvariant: “class `Array` is invariant in its type parameter.”
-* #### invoke
+* ### invoke
You can _invoke_ a method, function, or closure _on_ arguments, meaning its body will be executed with the specified arguments.
-* #### JVM
+* ### JVM
The _JVM_ is the Java Virtual Machine, or [runtime](#runtime), that hosts a running Scala program.
-* #### literal
+* ### literal
`1`, `"One"`, and `(x: Int) => x + 1` are examples of _literals_. A literal is a shorthand way to describe an object, where the shorthand exactly mirrors the structure of the created object.
-* #### local function
+* ### local function
A _local function_ is a `def` defined inside a block. To contrast, a `def` defined as a member of a class, trait, or singleton object is called a [method](#method).
-* #### local variable
+* ### local variable
A _local variable_ is a `val` or `var` defined inside a block. Although similar to [local variables](#local-variable), parameters to functions are not referred to as local variables, but simply as parameters or “variables” without the “local.”
-* #### member
+* ### member
A _member_ is any named element of the template of a class, trait, or singleton object. A member may be accessed with the name of its owner, a dot, and its simple name. For example, top-level fields and methods defined in a class are members of that class. A trait defined inside a class is a member of its enclosing class. A type defined with the type keyword in a class is a member of that class. A class is a member of the package in which is it defined. By contrast, a local variable or local function is not a member of its surrounding block.
-* #### message
+* ### message
Actors communicate with each other by sending each other _messages_. Sending a message does not interrupt what the receiver is doing. The receiver can wait until it has finished its current activity and its invariants have been reestablished.
-* #### meta-programming
+* ### meta-programming
Meta-programming software is software whose input is itself software. Compilers are meta-programs, as are tools like `scaladoc`. Meta-programming software is required in order to do anything with an annotation.
-* #### method
+* ### method
A _method_ is a function that is a member of some class, trait, or singleton object.
-* #### mixin
+* ### mixin
_Mixin_ is what a trait is called when it is being used in a mixin composition. In other words, in “`trait Hat`,” `Hat` is just a trait, but in “`new Cat extends AnyRef with Hat`,” `Hat` can be called a mixin. When used as a verb, “mix in” is two words. For example, you can _mix_ traits _in_ to classes or other traits.
-* #### mixin composition
+* ### mixin composition
The process of mixing traits into classes or other traits. _Mixin composition_ differs from traditional multiple inheritance in that the type of the super reference is not known at the point the trait is defined, but rather is determined anew each time the trait is mixed into a class or other trait.
-* #### modifier
+* ### modifier
A keyword that qualifies a class, trait, field, or method definition in some way. For example, the `private` modifier indicates that a class, trait, field, or method being defined is private.
-* #### multiple definitions
+* ### multiple definitions
The same expression can be assigned in _multiple definitions_ if you use the syntax `val v1, v2, v3 = exp`.
-* #### nonvariant
+* ### nonvariant
A type parameter of a class or trait is by default _nonvariant_. The class or trait then does not subtype when that parameter changes. For example, because class `Array` is nonvariant in its type parameter, `Array[String]` is neither a subtype nor a supertype of `Array[Any]`.
-* #### operation
+* ### operation
In Scala, every _operation_ is a method call. Methods may be invoked in _operator notation_, such as `b + 2`, and when in that notation, `+` is an _operator_.
-* #### parameter
+* ### parameter
Functions may take zero to many _parameters_. Each parameter has a name and a type. The distinction between parameters and arguments is that arguments refer to the actual objects passed when a function is invoked. Parameters are the variables that refer to those passed arguments.
-* #### parameterless function
+* ### parameterless function
A function that takes no parameters, which is defined without any empty parentheses. Invocations of parameterless functions may not supply parentheses. This supports the [uniform access principle](#uniform-access-principle), which enables the `def` to be changed into a `val` without requiring a change to client code.
-* #### parameterless method
+* ### parameterless method
A _parameterless method_ is a parameterless function that is a member of a class, trait, or singleton object.
-* #### parametric field
+* ### parametric field
A field defined as a class parameter.
-* #### partially applied function
+* ### partially applied function
A function that’s used in an expression and that misses some of its arguments. For instance, if function `f` has type `Int => Int => Int`, then `f` and `f(1)` are _partially applied functions_.
-* #### path-dependent type
+* ### path-dependent type
A type like `swiss.cow.Food`. The `swiss.cow` part is a path that forms a reference to an object. The meaning of the type is sensitive to the path you use to access it. The types `swiss.cow.Food` and `fish.Food`, for example, are different types.
-* #### pattern
+* ### pattern
In a `match` expression alternative, a _pattern_ follows each `case` keyword and precedes either a _pattern guard_ or the `=>` symbol.
-* #### pattern guard
+* ### pattern guard
In a `match` expression alternative, a _pattern guard_ can follow a [pattern](#pattern). For example, in “`case x if x % 2 == 0 => x + 1`”, the pattern guard is “`if x % 2 == 0`”. A case with a pattern guard will only be selected if the pattern matches and the pattern guard yields true.
-* #### predicate
+* ### predicate
A _predicate_ is a function with a `Boolean` result type.
-* #### primary constructor
+* ### primary constructor
The main constructor of a class, which invokes a superclass constructor, if necessary, initializes fields to passed values, and executes any top-level code defined between the curly braces of the class. Fields are initialized only for value parameters not passed to the superclass constructor, except for any that are not used in the body of the class and can therefore be optimized away.
-* #### procedure
+* ### procedure
A _procedure_ is a function with result type of `Unit`, which is therefore executed solely for its side effects.
-* #### reassignable
+* ### reassignable
A variable may or may not be _reassignable_. A `var` is reassignable while a `val` is not.
-* #### recursive
+* ### recursive
A function is _recursive_ if it calls itself. If the only place the function calls itself is the last expression of the function, then the function is [tail recursive](#tail-recursive).
-* #### reference
+* ### reference
A _reference_ is the Java abstraction of a pointer, which uniquely identifies an object that resides on the JVM’s heap. Reference type variables hold references to objects, because reference types (instances of `AnyRef`) are implemented as Java objects that reside on the JVM’s heap. Value type variables, by contrast, may sometimes hold a reference (to a boxed wrapper type) and sometimes not (when the object is being represented as a primitive value). Speaking generally, a Scala variable [refers](#refers) to an object. The term “refers” is more abstract than “holds a reference.” If a variable of type `scala.Int` is currently represented as a primitive Java `int` value, then that variable still refers to the `Int` object, but no reference is involved.
-* #### reference equality
+* ### reference equality
_Reference equality_ means that two references identify the very same Java object. Reference equality can be determined, for reference types only, by calling `eq` in `AnyRef`. (In Java programs, reference equality can be determined using `==` on Java [reference types](#reference-type).)
-* #### reference type
+* ### reference type
A _reference type_ is a subclass of `AnyRef`. Instances of reference types always reside on the JVM’s heap at run time.
-* #### referential transparency
+* ### referential transparency
A property of functions that are independent of temporal context and have no side effects. For a particular input, an invocation of a referentially transparent function can be replaced by its result without changing the program semantics.
-* #### refers
+* ### refers
A variable in a running Scala program always _refers_ to some object. Even if that variable is assigned to `null`, it conceptually refers to the `Null` object. At runtime, an object may be implemented by a Java object or a value of a primitive type, but Scala allows programmers to think at a higher level of abstraction about their code as they imagine it running. See also [reference](#reference).
-* #### refinement type
+* ### refinement type
A type formed by supplying a base type with a number of members inside curly braces. The members in the curly braces refine the types that are present in the base type. For example, the type of “animal that eats grass” is `Animal { type SuitableFood = Grass }`.
-* #### result
+* ### result
An expression in a Scala program yields a _result_. The result of every expression in Scala is an object.
-* #### result type
+* ### result type
A method’s _result type_ is the type of the value that results from calling the method. (In Java, this concept is called the return type.)
-* #### return
+* ### return
A function in a Scala program _returns_ a value. You can call this value the [result](#result) of the function. You can also say the function _results in_ the value. The result of every function in Scala is an object.
-* #### runtime
+* ### runtime
The Java Virtual Machine, or [JVM](#jvm), that hosts a running Scala program. Runtime encompasses both the virtual machine, as defined by the Java Virtual Machine Specification, and the runtime libraries of the Java API and the standard Scala API. The phrase at run time (with a space between run and time) means when the program is running, and contrasts with compile time.
-* #### runtime type
+* ### runtime type
The type of an object at run time. To contrast, a [static type](#static-type) is the type of an expression at compile time. Most runtime types are simply bare classes with no type parameters. For example, the runtime type of `"Hi"` is `String`, and the runtime type of `(x: Int) => x + 1` is `Function1`. Runtime types can be tested with `isInstanceOf`.
-* #### script
+* ### script
A file containing top level definitions and statements, which can be run directly with `scala` without explicitly compiling. A script must end in an expression, not a definition.
-* #### selector
+* ### selector
The value being matched on in a `match` expression. For example, in “`s match { case _ => }`”, the selector is `s`.
-* #### self type
+* ### self type
A _self type_ of a trait is the assumed type of `this`, the receiver, to be used within the trait. Any concrete class that mixes in the trait must ensure that its type conforms to the trait’s self type. The most common use of self types is for dividing a large class into several traits (as described in Chapter 29 of [Programming in Scala](https://www.artima.com/shop/programming_in_scala)).
-* #### semi-structured data
+* ### semi-structured data
XML data is semi-structured. It is more structured than a flat binary file or text file, but it does not have the full structure of a programming language’s data structures.
-* #### serialization
-You can _serialize_ an object into a byte stream which can then be saved to files or transmitted over the network. You can later _deserialize_ the byte stream, even on different computer, and obtain an object that is the same as the original serialized object.
+* ### serialization
+You can _serialize_ an object into a byte stream which can then be saved to a file or transmitted over the network. You can later _deserialize_ the byte stream, even on different computer, and obtain an object that is the same as the original serialized object.
-* #### shadow
+* ### shadow
A new declaration of a local variable _shadows_ one of the same name in an enclosing scope.
-* #### signature
+* ### signature
_Signature_ is short for [type signature](#type-signature).
-* #### singleton object
+* ### singleton object
An object defined with the object keyword. Each singleton object has one and only one instance. A singleton object that shares its name with a class, and is defined in the same source file as that class, is that class’s [companion object](#companion-object). The class is its [companion class](#companion-class). A singleton object that doesn’t have a companion class is a [standalone object](#standalone-object).
-* #### standalone object
+* ### standalone object
A [singleton object](#singleton-object) that has no [companion class](#companion-class).
-* #### statement
+* ### statement
An expression, definition, or import, _i.e._, things that can go into a template or a block in Scala source code.
-* #### static type
+* ### static type
See [type](#type).
-* #### structural type
+* ### structural type
A [refinement type](#refinement-type) where the refinements are for members not in the base type. For example, `{ def close(): Unit }` is a structural type, because the base type is `AnyRef`, and `AnyRef` does not have a member named `close`.
-* #### subclass
+* ### subclass
A class is a _subclass_ of all of its [superclasses](#superclass) and [supertraits](#supertrait).
-* #### subtrait
+* ### subtrait
A trait is a _subtrait_ of all of its [supertraits](#supertrait).
-* #### subtype
+* ### subtype
The Scala compiler will allow any of a type’s _subtypes_ to be used as a substitute wherever that type is required. For classes and traits that take no type parameters, the subtype relationship mirrors the subclass relationship. For example, if class `Cat` is a subclass of abstract class `Animal`, and neither takes type parameters, type `Cat` is a subtype of type `Animal`. Likewise, if trait `Apple` is a subtrait of trait `Fruit`, and neither takes type parameters, type `Apple` is a subtype of type `Fruit`. For classes and traits that take type parameters, however, variance comes into play. For example, because abstract class `List` is declared to be covariant in its lone type parameter (i.e., `List` is declared `List[+A]`), `List[Cat]` is a subtype of `List[Animal]`, and `List[Apple]` a subtype of `List[Fruit]`. These subtype relationships exist even though the class of each of these types is `List`. By contrast, because `Set` is not declared to be covariant in its type parameter (i.e., `Set` is declared `Set[A]` with no plus sign), `Set[Cat]` is not a subtype of `Set[Animal]`. A subtype should correctly implement the contracts of its supertypes, so that the Liskov Substitution Principle applies, but the compiler only verifies this property at the level of type checking.
-* #### superclass
+* ### superclass
A class’s _superclasses_ include its direct superclass, its direct superclass’s direct superclass, and so on, all the way up to `Any`.
-* #### supertrait
+* ### supertrait
A class’s or trait’s _supertraits_, if any, include all traits directly mixed into the class or trait or any of its superclasses, plus any supertraits of those traits.
-* #### supertype
+* ### supertype
A type is a _supertype_ of all of its subtypes.
-* #### synthetic class
+* ### synthetic class
A synthetic class is generated automatically by the compiler rather than being written by hand by the programmer.
-* #### tail recursive
+* ### tail recursive
A function is _tail recursive_ if the only place the function calls itself is the last operation of the function.
-* #### target typing
+* ### target typing
_Target typing_ is a form of type inference that takes into account the type that’s expected. In `nums.filter((x) => x > 0)`, for example, the Scala compiler infers type of `x` to be the element type of `nums`, because the `filter` method invokes the function on each element of `nums`.
-* #### template
+* ### template
A _template_ is the body of a class, trait, or singleton object definition. It defines the type signature, behavior and initial state of the class, trait, or object.
-* #### trait
+* ### trait
A _trait_, which is defined with the `trait` keyword, is like an abstract class that cannot take any value parameters and can be “mixed into” classes or other traits via the process known as [mixin composition](#mixin-composition). When a trait is being mixed into a class or trait, it is called a [mixin](#mixin). A trait may be parameterized with one or more types. When parameterized with types, the trait constructs a type. For example, `Set` is a trait that takes a single type parameter, whereas `Set[Int]` is a type. Also, `Set` is said to be “the trait of” type `Set[Int]`.
-* #### type
+* ### type
Every variable and expression in a Scala program has a _type_ that is known at compile time. A type restricts the possible values to which a variable can refer, or an expression can produce, at run time. A variable or expression’s type can also be referred to as a _static type_ if necessary to differentiate it from an object’s [runtime type](#runtime-type). In other words, “type” by itself means static type. Type is distinct from class because a class that takes type parameters can construct many types. For example, `List` is a class, but not a type. `List[T]` is a type with a free type parameter. `List[Int]` and `List[String]` are also types (called ground types because they have no free type parameters). A type can have a “[class](#class)” or “[trait](#trait).” For example, the class of type `List[Int]` is `List`. The trait of type `Set[String]` is `Set`.
-* #### type constraint
+* ### type constraint
Some [annotations](#annotation) are _type constraints_, meaning that they add additional limits, or constraints, on what values the type includes. For example, `@positive` could be a type constraint on the type `Int`, limiting the type of 32-bit integers down to those that are positive. Type constraints are not checked by the standard Scala compiler, but must instead be checked by an extra tool or by a compiler plugin.
-* #### type constructor
+* ### type constructor
A class or trait that takes type parameters.
-* #### type parameter
+* ### type parameter
A parameter to a generic class or generic method that must be filled in by a type. For example, class `List` is defined as “`class List[T] { . . . `”, and method `identity`, a member of object `Predef`, is defined as “`def identity[T](x:T) = x`”. The `T` in both cases is a type parameter.
-* #### type signature
+* ### type signature
A method’s _type signature_ comprises its name, the number, order, and types of its parameters, if any, and its result type. The type signature of a class, trait, or singleton object comprises its name, the type signatures of all of its members and constructors, and its declared inheritance and mixin relations.
-* #### uniform access principle
+* ### uniform access principle
The _uniform access principle_ states that variables and parameterless functions should be accessed using the same syntax. Scala supports this principle by not allowing parentheses to be placed at call sites of parameterless functions. As a result, a parameterless function definition can be changed to a `val`, or _vice versa_, without affecting client code.
-* #### unreachable
+* ### unreachable
At the Scala level, objects can become _unreachable_, at which point the memory they occupy may be reclaimed by the runtime. Unreachable does not necessarily mean unreferenced. Reference types (instances of `AnyRef`) are implemented as objects that reside on the JVM’s heap. When an instance of a reference type becomes unreachable, it indeed becomes unreferenced, and is available for garbage collection. Value types (instances of `AnyVal`) are implemented as both primitive type values and as instances of Java wrapper types (such as `java.lang.Integer`), which reside on the heap. Value type instances can be boxed (converted from a primitive value to a wrapper object) and unboxed (converted from a wrapper object to a primitive value) throughout the lifetime of the variables that refer to them. If a value type instance currently represented as a wrapper object on the JVM’s heap becomes unreachable, it indeed becomes unreferenced, and is available for garbage collection. But if a value type currently represented as a primitive value becomes unreachable, then it does not become unreferenced, because it does not exist as an object on the JVM’s heap at that point of time. The runtime may reclaim memory occupied by unreachable objects, but if an Int, for example, is implemented at run time by a primitive Java int that occupies some memory in the stack frame of an executing method, then the memory for that object is “reclaimed” when the stack frame is popped as the method completes. Memory for reference types, such as `Strings`, may be reclaimed by the JVM’s garbage collector after they become unreachable.
-* #### unreferenced
+* ### unreferenced
See [unreachable](#unreachable).
-* #### value
+* ### value
The result of any computation or expression in Scala is a _value_, and in Scala, every value is an object. The term value essentially means the image of an object in memory (on the JVM’s heap or stack).
-* #### value type
+* ### value type
A _value type_ is any subclass of `AnyVal`, such as `Int`, `Double`, or `Unit`. This term has meaning at the level of Scala source code. At runtime, instances of value types that correspond to Java primitive types may be implemented in terms of primitive type values or instances of wrapper types, such as `java.lang.Integer`. Over the lifetime of a value type instance, the runtime may transform it back and forth between primitive and wrapper types (_i.e._, to box and unbox it).
-* #### variable
+* ### variable
A named entity that refers to an object. A variable is either a `val` or a `var`. Both `val`s and `var`s must be initialized when defined, but only `var`s can be later reassigned to refer to a different object.
-* #### variance
+* ### variance
A type parameter of a class or trait can be marked with a _variance_ annotation, either [covariant](#covariant) (+) or [contravariant](#contravariant) (-). Such variance annotations indicate how subtyping works for a generic class or trait. For example, the generic class `List` is covariant in its type parameter, and thus `List[String]` is a subtype of `List[Any]`. By default, _i.e._, absent a `+` or `-` annotation, type parameters are [nonvariant](#nonvariant).
-* #### yield
+* ### yield
An expression can _yield_ a result. The `yield` keyword designates the result of a [for comprehension](#for-comprehension).
diff --git a/_includes/_markdown/_ru/install-cask.md b/_includes/_markdown/_ru/install-cask.md
new file mode 100644
index 0000000000..1cac104c20
--- /dev/null
+++ b/_includes/_markdown/_ru/install-cask.md
@@ -0,0 +1,45 @@
+{% altDetails require-info-box 'Установка Cask' %}
+
+{% tabs cask-install class=tabs-build-tool %}
+
+{% tab 'Scala CLI' %}
+
+Вы можете объявить зависимость от Cask с помощью следующей директивы `using`:
+
+```scala
+//> using dep com.lihaoyi::cask::0.10.2
+```
+
+{% endtab %}
+
+{% tab 'sbt' %}
+
+В файле `build.sbt` вы можете добавить зависимость от Cask:
+
+```scala
+lazy val example = project.in(file("example"))
+ .settings(
+ scalaVersion := "3.4.2",
+ libraryDependencies += "com.lihaoyi" %% "cask" % "0.10.2",
+ fork := true
+ )
+```
+
+{% endtab %}
+
+{% tab 'Mill' %}
+
+В файле `build.sc` вы можете добавить зависимость от Cask:
+
+```scala
+object example extends RootModule with ScalaModule {
+ def scalaVersion = "3.4.2"
+ def ivyDeps = Agg(
+ ivy"com.lihaoyi::cask::0.10.2"
+ )
+}
+```
+{% endtab %}
+
+{% endtabs %}
+{% endaltDetails %}
diff --git a/_includes/_markdown/_ru/install-munit.md b/_includes/_markdown/_ru/install-munit.md
new file mode 100644
index 0000000000..aa15142558
--- /dev/null
+++ b/_includes/_markdown/_ru/install-munit.md
@@ -0,0 +1,68 @@
+{% altDetails install-info-box 'Установка MUnit' %}
+
+{% tabs munit-unit-test-1 class=tabs-build-tool %}
+{% tab 'Scala CLI' %}
+
+Вы можете запросить весь набор инструментов одной командой:
+
+```scala
+//> using toolkit latest
+```
+
+MUnit, будучи тестовым фреймворком, доступен только в тестовых файлах:
+файлах в каталоге `test` или тех, которые имеют расширение `.test.scala`.
+Подробнее о тестовой области (test scope) см. [в документации Scala CLI](https://scala-cli.virtuslab.org/docs/commands/test/).
+
+В качестве альтернативы вы можете запросить только определенную версию MUnit:
+
+```scala
+//> using dep org.scalameta::munit:1.1.0
+```
+
+{% endtab %}
+
+{% tab 'sbt' %}
+
+В файле `build.sbt` вы можете добавить зависимость от toolkit-test:
+
+```scala
+lazy val example = project.in(file("."))
+ .settings(
+ scalaVersion := "3.4.2",
+ libraryDependencies += "org.scala-lang" %% "toolkit-test" % "0.7.0" % Test
+ )
+```
+
+Здесь конфигурация `Test` означает, что зависимость используется только исходными файлами в `src/test`.
+
+В качестве альтернативы вы можете запросить только определенную версию MUnit:
+
+```scala
+libraryDependencies += "org.scalameta" %% "munit" % "1.1.0" % Test
+```
+{% endtab %}
+
+{% tab 'Mill' %}
+
+В файле `build.sc` вы можете добавить объект `test`, расширяющий `Tests` и `TestModule.Munit`:
+
+```scala
+object example extends ScalaModule {
+ def scalaVersion = "3.4.2"
+ object test extends Tests with TestModule.Munit {
+ def ivyDeps =
+ Agg(
+ ivy"org.scala-lang::toolkit-test:0.7.0"
+ )
+ }
+}
+```
+
+В качестве альтернативы вы можете запросить только определенную версию MUnit:
+
+```scala
+ivy"org.scalameta::munit:1.1.0"
+```
+{% endtab %}
+{% endtabs %}
+{% endaltDetails %}
\ No newline at end of file
diff --git a/_includes/_markdown/_ru/install-os-lib.md b/_includes/_markdown/_ru/install-os-lib.md
new file mode 100644
index 0000000000..f010d1f7fd
--- /dev/null
+++ b/_includes/_markdown/_ru/install-os-lib.md
@@ -0,0 +1,64 @@
+{% altDetails require-info-box 'Установка OS-Lib' %}
+
+{% tabs oslib-install class=tabs-build-tool %}
+
+{% tab 'Scala CLI' %}
+
+Вы можете запросить весь набор инструментов одной командой:
+
+```scala
+//> using toolkit latest
+```
+
+В качестве альтернативы вы можете запросить только определенную версию OS-Lib:
+
+```scala
+//> using dep com.lihaoyi::os-lib:0.11.3
+```
+
+{% endtab %}
+
+{% tab 'sbt' %}
+
+В файле `build.sbt` вы можете добавить зависимость от `toolkit`:
+
+```scala
+lazy val example = project.in(file("."))
+ .settings(
+ scalaVersion := "3.4.2",
+ libraryDependencies += "org.scala-lang" %% "toolkit" % "0.7.0"
+ )
+```
+
+В качестве альтернативы вы можете запросить только определенную версию OS-Lib:
+
+```scala
+libraryDependencies += "com.lihaoyi" %% "os-lib" % "0.11.3"
+```
+
+{% endtab %}
+
+{% tab 'Mill' %}
+
+В файле `build.sc` вы можете добавить зависимость от `toolkit`:
+
+```scala
+object example extends ScalaModule {
+ def scalaVersion = "3.4.2"
+ def ivyDeps =
+ Agg(
+ ivy"org.scala-lang::toolkit:0.7.0"
+ )
+}
+```
+
+В качестве альтернативы вы можете запросить только определенную версию OS-Lib:
+
+```scala
+ivy"com.lihaoyi::os-lib:0.11.3"
+```
+
+{% endtab %}
+
+{% endtabs %}
+{% endaltDetails %}
\ No newline at end of file
diff --git a/_includes/_markdown/_ru/install-sttp.md b/_includes/_markdown/_ru/install-sttp.md
new file mode 100644
index 0000000000..fec7938cea
--- /dev/null
+++ b/_includes/_markdown/_ru/install-sttp.md
@@ -0,0 +1,64 @@
+
+{% altDetails install-info-box 'Установка sttp' %}
+
+{% tabs sttp-install-methods class=tabs-build-tool%}
+
+{% tab 'Scala CLI' %}
+
+Вы можете запросить весь набор инструментов одной командой:
+
+```scala
+//> using toolkit latest
+```
+
+В качестве альтернативы вы можете запросить только определенную версию sttp:
+
+```scala
+//> using dep com.softwaremill.sttp.client4::core:4.0.0-RC1
+```
+
+{% endtab %}
+
+{% tab 'sbt' %}
+
+В файле `build.sbt` вы можете добавить зависимость от `toolkit`:
+
+```scala
+lazy val example = project.in(file("."))
+ .settings(
+ scalaVersion := "3.4.2",
+ libraryDependencies += "org.scala-lang" %% "toolkit" % "0.7.0"
+ )
+```
+
+В качестве альтернативы вы можете запросить только определенную версию sttp:
+
+```scala
+libraryDependencies += "com.softwaremill.sttp.client4" %% "core" % "4.0.0-RC1"
+```
+
+{% endtab %}
+
+{% tab 'Mill' %}
+
+В файле `build.sc` вы можете добавить зависимость от `toolkit`:
+
+```scala
+object example extends ScalaModule {
+ def scalaVersion = "3.4.2"
+ def ivyDeps =
+ Agg(
+ ivy"org.scala-lang::toolkit:0.7.0"
+ )
+}
+```
+
+В качестве альтернативы вы можете запросить только определенную версию sttp:
+
+```scala
+ivy"com.softwaremill.sttp.client4::core:4.0.0-RC1"
+```
+
+{% endtab %}
+{% endtabs %}
+{% endaltDetails %}
diff --git a/_includes/_markdown/_ru/install-upickle.md b/_includes/_markdown/_ru/install-upickle.md
new file mode 100644
index 0000000000..83880a91a8
--- /dev/null
+++ b/_includes/_markdown/_ru/install-upickle.md
@@ -0,0 +1,64 @@
+
+{% altDetails install-info-box 'Установка upickle' %}
+
+{% tabs upickle-install-methods class=tabs-build-tool %}
+
+{% tab 'Scala CLI' %}
+
+Вы можете запросить весь набор инструментов одной командой:
+
+```scala
+//> using toolkit latest
+```
+
+В качестве альтернативы вы можете запросить только определенную версию UPickle:
+
+```scala
+//> using dep com.lihaoyi::upickle:4.1.0
+```
+
+{% endtab %}
+
+{% tab 'sbt' %}
+
+В файле `build.sbt` вы можете добавить зависимость от `toolkit`:
+
+```scala
+lazy val example = project.in(file("."))
+ .settings(
+ scalaVersion := "3.4.2",
+ libraryDependencies += "org.scala-lang" %% "toolkit" % "0.7.0"
+ )
+```
+
+В качестве альтернативы вы можете запросить только определенную версию UPickle:
+
+```scala
+libraryDependencies += "com.lihaoyi" %% "upickle" % "4.1.0"
+```
+
+{% endtab %}
+
+{% tab 'Mill' %}
+
+В файле `build.sc` вы можете добавить зависимость от `toolkit`:
+
+```scala
+object example extends ScalaModule {
+ def scalaVersion = "3.4.2"
+ def ivyDeps =
+ Agg(
+ ivy"org.scala-lang::toolkit:0.7.0"
+ )
+}
+```
+
+В качестве альтернативы вы можете запросить только определенную версию UPickle:
+
+```scala
+ivy"com.lihaoyi::upickle:4.1.0"
+```
+
+{% endtab %}
+{% endtabs %}
+{% endaltDetails %}
diff --git a/_includes/_markdown/courses-coursera.md b/_includes/_markdown/courses-coursera.md
new file mode 100644
index 0000000000..403c5e3100
--- /dev/null
+++ b/_includes/_markdown/courses-coursera.md
@@ -0,0 +1,18 @@
+## Scala Courses on Coursera by EPFL
+
+The [Scala Center](https://scala.epfl.ch) at EPFL offers free online courses of various levels, from beginner to advanced.
+
+For beginners:
+
+- [Effective Programming in Scala](https://www.coursera.org/learn/effective-scala): a practical introduction to Scala for professional developers
+- [Functional Programming Principles in Scala](https://www.coursera.org/learn/scala-functional-programming): the foundational course by Martin Odersky, Scala's creator
+
+More advanced topics:
+
+- [Functional Program Design in Scala](https://www.coursera.org/learn/scala-functional-program-design): builds on functional principles with more advanced concepts
+- [Parallel Programming](https://www.coursera.org/learn/scala-parallel-programming)
+- [Big Data Analysis with Scala and Spark](https://www.coursera.org/learn/scala-spark-big-data)
+- [Programming Reactive Systems](https://www.coursera.org/learn/scala-akka-reactive): introduces Akka, actors and reactive streams
+
+All courses are free to audit, with an option to pay for a certificate, to showcase your skills on your resume or LinkedIn.
+For more on Scala Center's online courses, visit [this page](https://docs.scala-lang.org/online-courses.html#learning-platforms).
diff --git a/_includes/_markdown/courses-extension-school.md b/_includes/_markdown/courses-extension-school.md
new file mode 100644
index 0000000000..003c42a4f2
--- /dev/null
+++ b/_includes/_markdown/courses-extension-school.md
@@ -0,0 +1,9 @@
+## EPFL Extension School: Effective Programming in Scala
+
+Subscribing to [Effective programming in Scala](https://www.epfl.ch/education/continuing-education/effective-programming-in-scala/) on the EPFL Extension School offers:
+
+- Regular Q&A sessions and code reviews with experts from the Scala team
+- An [Extension School certificate](https://www.epfl.ch/education/continuing-education/certifications/) upon completion
+
+This course combines video lessons, written content and hands-on exercise focused on practical aspects, including business domain modeling, error handling, data manipulation, and task parallelization.
+For more on Scala Center's online courses, visit [this page](https://docs.scala-lang.org/online-courses.html#learning-platforms).
diff --git a/_includes/_markdown/courses-rock-the-jvm.md b/_includes/_markdown/courses-rock-the-jvm.md
new file mode 100644
index 0000000000..0b0db4f9f1
--- /dev/null
+++ b/_includes/_markdown/courses-rock-the-jvm.md
@@ -0,0 +1,17 @@
+## Rock the JVM Courses
+
+_As part of a partnership with the Scala Center, Rock the JVM donates 30% of the revenue from any courses purchased through the links in this section to support the Scala Center._
+
+[Rock the JVM](https://rockthejvm.com?affcode=256201_r93i1xuv) is a learning platform with free and premium courses on the Scala language, and all major libraries and tools in the Scala ecosystem: Typelevel, Zio, Akka/Pekko, Spark, and others.
+Its main Scala courses are:
+
+- [Scala at Light Speed](https://rockthejvm.com/courses/scala-at-light-speed?affcode=256201_r93i1xuv) (free)
+- [Scala & Functional Programming Essentials](https://rockthejvm.com/courses/scala-essentials?affcode=256201_r93i1xuv) (premium)
+- [Advanced Scala and Functional Programming](https://rockthejvm.com/courses/advanced-scala?affcode=256201_r93i1xuv) (premium)
+- [Scala Macros & Metaprogramming](https://rockthejvm.com/courses/scala-macros-and-metaprogramming?affcode=256201_r93i1xuv) (premium)
+
+Other courses teach how to build full-stack Scala applications, using [Typelevel](https://rockthejvm.com/courses/typelevel-rite-of-passage?affcode=256201_r93i1xuv) or [ZIO](https://rockthejvm.com/courses/zio-rite-of-passage?affcode=256201_r93i1xuv) ecosystems.
+
+
+
+Explore more premium [courses](https://rockthejvm.com/courses?affcode=256201_r93i1xuv) or check out [free video tutorials](https://youtube.com/rockthejvm?affcode=256201_r93i1xuv) and [free articles](https://rockthejvm.com/articles?affcode=256201_r93i1xuv).
diff --git a/_includes/_markdown/install-cask.md b/_includes/_markdown/install-cask.md
new file mode 100644
index 0000000000..3637ddfac9
--- /dev/null
+++ b/_includes/_markdown/install-cask.md
@@ -0,0 +1,37 @@
+{% altDetails require-info-box 'Getting Cask' %}
+
+{% tabs cask-install class=tabs-build-tool %}
+
+{% tab 'Scala CLI' %}
+You can declare a dependency on Cask with the following `using` directive:
+```scala
+//> using dep com.lihaoyi::cask::0.10.2
+```
+{% endtab %}
+
+{% tab 'sbt' %}
+In your `build.sbt`, you can add a dependency on Cask:
+```scala
+lazy val example = project.in(file("example"))
+ .settings(
+ scalaVersion := "3.4.2",
+ libraryDependencies += "com.lihaoyi" %% "cask" % "0.10.2",
+ fork := true
+ )
+```
+{% endtab %}
+
+{% tab 'Mill' %}
+In your `build.sc`, you can add a dependency on Cask:
+```scala
+object example extends RootModule with ScalaModule {
+ def scalaVersion = "3.4.2"
+ def ivyDeps = Agg(
+ ivy"com.lihaoyi::cask::0.10.2"
+ )
+}
+```
+{% endtab %}
+
+{% endtabs %}
+{% endaltDetails %}
diff --git a/_includes/_markdown/install-munit.md b/_includes/_markdown/install-munit.md
new file mode 100644
index 0000000000..47eeb1509f
--- /dev/null
+++ b/_includes/_markdown/install-munit.md
@@ -0,0 +1,53 @@
+{% altDetails install-info-box 'Getting MUnit' %}
+
+{% tabs munit-unit-test-1 class=tabs-build-tool %}
+{% tab 'Scala CLI' %}
+You can require the entire toolkit in a single line:
+```scala
+//> using toolkit latest
+```
+MUnit, being a testing framework, is only available in test files: files in a `test` directory or ones that have the `.test.scala` extension. Refer to the [Scala CLI documentation](https://scala-cli.virtuslab.org/docs/commands/test/) to learn more about the test scope.
+
+Alternatively, you can require just a specific version of MUnit:
+```scala
+//> using dep org.scalameta::munit:1.1.0
+```
+{% endtab %}
+{% tab 'sbt' %}
+In your build.sbt file, you can add the dependency on toolkit-test:
+```scala
+lazy val example = project.in(file("."))
+ .settings(
+ scalaVersion := "3.4.2",
+ libraryDependencies += "org.scala-lang" %% "toolkit-test" % "0.7.0" % Test
+ )
+```
+
+Here the `Test` configuration means that the dependency is only used by the source files in `src/test`.
+
+Alternatively, you can require just a specific version of MUnit:
+```scala
+libraryDependencies += "org.scalameta" %% "munit" % "1.1.0" % Test
+```
+{% endtab %}
+{% tab 'Mill' %}
+In your build.sc file, you can add a `test` object extending `Tests` and `TestModule.Munit`:
+```scala
+object example extends ScalaModule {
+ def scalaVersion = "3.4.2"
+ object test extends Tests with TestModule.Munit {
+ def ivyDeps =
+ Agg(
+ ivy"org.scala-lang::toolkit-test:0.7.0"
+ )
+ }
+}
+```
+
+Alternatively, you can require just a specific version of MUnit:
+```scala
+ivy"org.scalameta::munit:1.1.0"
+```
+{% endtab %}
+{% endtabs %}
+{% endaltDetails %}
diff --git a/_includes/_markdown/install-os-lib.md b/_includes/_markdown/install-os-lib.md
new file mode 100644
index 0000000000..ae254d9d71
--- /dev/null
+++ b/_includes/_markdown/install-os-lib.md
@@ -0,0 +1,46 @@
+{% altDetails require-info-box 'Getting OS-Lib' %}
+
+{% tabs oslib-install class=tabs-build-tool %}
+{% tab 'Scala CLI' %}
+You can require the entire toolkit in a single line:
+```scala
+//> using toolkit latest
+```
+
+Alternatively, you can require just a specific version of OS-Lib:
+```scala
+//> using dep com.lihaoyi::os-lib:0.11.3
+```
+{% endtab %}
+{% tab 'sbt' %}
+In your `build.sbt`, you can add a dependency on the toolkit:
+```scala
+lazy val example = project.in(file("."))
+ .settings(
+ scalaVersion := "3.4.2",
+ libraryDependencies += "org.scala-lang" %% "toolkit" % "0.7.0"
+ )
+```
+Alternatively, you can require just a specific version of OS-Lib:
+```scala
+libraryDependencies += "com.lihaoyi" %% "os-lib" % "0.11.3"
+```
+{% endtab %}
+{% tab 'Mill' %}
+In your `build.sc` file, you can add a dependency on the Toolkit:
+```scala
+object example extends ScalaModule {
+ def scalaVersion = "3.4.2"
+ def ivyDeps =
+ Agg(
+ ivy"org.scala-lang::toolkit:0.7.0"
+ )
+}
+```
+Alternatively, you can require just a specific version of OS-Lib:
+```scala
+ivy"com.lihaoyi::os-lib:0.11.3"
+```
+{% endtab %}
+{% endtabs %}
+{% endaltDetails %}
diff --git a/_includes/_markdown/install-sttp.md b/_includes/_markdown/install-sttp.md
new file mode 100644
index 0000000000..0173ec47e1
--- /dev/null
+++ b/_includes/_markdown/install-sttp.md
@@ -0,0 +1,47 @@
+{% altDetails install-info-box 'Getting sttp' %}
+
+{% tabs sttp-install-methods class=tabs-build-tool%}
+{% tab 'Scala CLI' %}
+You can require the entire toolkit in a single line:
+```scala
+//> using toolkit latest
+```
+
+Alternatively, you can require just a specific version of sttp:
+```scala
+//> using dep com.softwaremill.sttp.client4::core:4.0.0-RC1
+```
+{% endtab %}
+{% tab 'sbt' %}
+In your build.sbt file, you can add a dependency on the Toolkit:
+```scala
+lazy val example = project.in(file("."))
+ .settings(
+ scalaVersion := "3.4.2",
+ libraryDependencies += "org.scala-lang" %% "toolkit" % "0.7.0"
+ )
+```
+
+Alternatively, you can require just a specific version of sttp:
+```scala
+libraryDependencies += "com.softwaremill.sttp.client4" %% "core" % "4.0.0-RC1"
+```
+{% endtab %}
+{% tab 'Mill' %}
+In your build.sc file, you can add a dependency on the Toolkit:
+```scala
+object example extends ScalaModule {
+ def scalaVersion = "3.4.2"
+ def ivyDeps =
+ Agg(
+ ivy"org.scala-lang::toolkit:0.7.0"
+ )
+}
+```
+Alternatively, you can require just a specific version of sttp:
+```scala
+ivy"com.softwaremill.sttp.client4::core:4.0.0-RC1"
+```
+{% endtab %}
+{% endtabs %}
+{% endaltDetails %}
diff --git a/_includes/_markdown/install-upickle.md b/_includes/_markdown/install-upickle.md
new file mode 100644
index 0000000000..9f9cff8a62
--- /dev/null
+++ b/_includes/_markdown/install-upickle.md
@@ -0,0 +1,46 @@
+{% altDetails install-info-box 'Getting upickle' %}
+
+{% tabs upickle-install-methods class=tabs-build-tool %}
+{% tab 'Scala CLI' %}
+Using Scala CLI, you can require the entire toolkit in a single line:
+```scala
+//> using toolkit latest
+```
+
+Alternatively, you can require just a specific version of UPickle:
+```scala
+//> using dep com.lihaoyi::upickle:4.1.0
+```
+{% endtab %}
+{% tab 'sbt' %}
+In your build.sbt file, you can add the dependency on the Toolkit:
+```scala
+lazy val example = project.in(file("."))
+ .settings(
+ scalaVersion := "3.4.2",
+ libraryDependencies += "org.scala-lang" %% "toolkit" % "0.7.0"
+ )
+```
+Alternatively, you can require just a specific version of UPickle:
+```scala
+libraryDependencies += "com.lihaoyi" %% "upickle" % "4.1.0"
+```
+{% endtab %}
+{% tab 'Mill' %}
+In your build.sc file, you can add the dependency to the upickle library:
+```scala
+object example extends ScalaModule {
+ def scalaVersion = "3.4.2"
+ def ivyDeps =
+ Agg(
+ ivy"org.scala-lang::toolkit:0.7.0"
+ )
+}
+```
+Alternatively, you can require just a specific version of UPickle:
+```scala
+ivy"com.lihaoyi::upickle:4.1.0"
+```
+{% endtab %}
+{% endtabs %}
+{% endaltDetails %}
diff --git a/_includes/alert-banner.html b/_includes/alert-banner.html
new file mode 100644
index 0000000000..94c5ac1273
--- /dev/null
+++ b/_includes/alert-banner.html
@@ -0,0 +1,10 @@
+{% comment %}use the variable 'message' to include markdown text to display in the alert.{% endcomment %}
+
+{% unless include.message_id == 'disabled' %}
+
+
diff --git a/_includes/column-list-of-items.html b/_includes/column-list-of-items.html
deleted file mode 100644
index eb9e1600be..0000000000
--- a/_includes/column-list-of-items.html
+++ /dev/null
@@ -1,18 +0,0 @@
-{% comment %}
- Layouts using this include should pass an include variable called 'collection' referencing a collection carrying the data (i.e.: contribute_community_tickets, contribute_resources...)
-{% endcomment %}
-
\ No newline at end of file
diff --git a/_includes/documentation-sections.html b/_includes/documentation-sections.html
new file mode 100644
index 0000000000..cac3c2d21b
--- /dev/null
+++ b/_includes/documentation-sections.html
@@ -0,0 +1,18 @@
+
-
\ No newline at end of file
+
diff --git a/_includes/version-specific-notice.html b/_includes/version-specific-notice.html
new file mode 100644
index 0000000000..4a92f84a6d
--- /dev/null
+++ b/_includes/version-specific-notice.html
@@ -0,0 +1,31 @@
+{% if include.language %}
+
+
+ {% if include.language == 'scala3' %}
+ {% if include.page-language == 'ru' %}
+ Эта страница документа относится к Scala 3 и
+ может охватывать новые концепции, недоступные в Scala 2.
+ Если не указано явно, все примеры кода на этой странице
+ предполагают, что вы используете Scala 3.
+ {% else %}
+ This doc page is specific to Scala 3,
+ and may cover new concepts not available in Scala 2. Unless
+ otherwise stated, all the code examples in this page assume
+ you are using Scala 3.
+ {% endif %}
+ {% else if include.language == 'scala2' %}
+ {% if include.page-language == 'ru' %}
+ Эта страница документа относится к функциям, представленным в Scala 2,
+ которые либо были удалены в Scala 3, либо заменены альтернативными.
+ Если не указано явно, все примеры кода на этой странице предполагают,
+ что вы используете Scala 2.
+ {% else %}
+ This doc page is specific to features shipped in Scala 2,
+ which have either been removed in Scala 3 or replaced by an
+ alternative. Unless otherwise stated, all the code examples
+ in this page assume you are using Scala 2.
+ {% endif %}
+ {% endif %}
+
+
+{% endif %}
diff --git a/_it/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.md b/_it/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.md
new file mode 100644
index 0000000000..0de0347ca5
--- /dev/null
+++ b/_it/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.md
@@ -0,0 +1,79 @@
+---
+title: Primi passi su scala e sbt con la linea di comando
+layout: singlepage-overview
+partof: getting-started-with-scala-and-sbt-on-the-command-line
+language: it
+disqus: true
+next-page: /it/testing-scala-with-sbt-on-the-command-line
+---
+
+In questo tutorial si vedrà come creare un progetto Scala a partire da un template, che può essere usato come punto di partenza anche per progettti personali.
+Lo strumento utilizzato per tale scopo è [sbt](https://www.scala-sbt.org/1.x/docs/index.html), che è lo standard di build per Scala.
+sbt permette di compilare, eseguire e testare i tuoi progetti, ma permette di svolgere anche altri compiti.
+Si presuppone una conoscenza dell'uso della linea di comando.
+
+## Installazione
+1. Assicurarsi di avere la Java 8 JDK (conosciuta anche come 1.8) installata
+ * Per verificarlo, eseguire `javac -version` da linea di comando e controllare che nell'output sia riportato
+ `javac 1.8.___`
+ * Se non si possiede la versione 1.8 o superiore, installarla seguendo [queste indicazioni](https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
+1. Installare sbt
+ * [Mac](https://www.scala-sbt.org/1.x/docs/Installing-sbt-on-Mac.html)
+ * [Windows](https://www.scala-sbt.org/1.x/docs/Installing-sbt-on-Windows.html)
+ * [Linux](https://www.scala-sbt.org/1.x/docs/Installing-sbt-on-Linux.html)
+
+## Creare il progetto
+1. Eseguire il comando `cd` specificando una cartella vuota per spostarsi in essa.
+1. Eseguire il comando `sbt new scala/hello-world.g8`. Questo effettuerà una pull del template 'hello-world' da GitHub.
+ Si occuperà inoltre di creare la cartella `target`, che per ora può essere ignorata.
+1. Quando richiesto verrà richiesto il nome dell'applicazione, indicare `hello-world`. In questo modo verrà creato un progetto chiamato "hello-world".
+1. Osserviamo cosa è stato generato una volta eseguiti i passaggi sopra riportati:
+
+```
+- hello-world
+ - project (sbt usa questa cartella per installare e gestire plugins e dipendenze)
+ - build.properties
+ - src
+ - main
+ - scala (Tutto il codice scala che viene scritto dovrà andare qui)
+ - Main.scala (Entry point dell'applicazione) <-- per ora è tutto ciò che ci servirà
+ - build.sbt (il file di definizione della build interpretato da sbt)
+```
+
+Una volta che verrà buildato il progetto, sbt creerà diverse cartelle `target` per i file generati. Possono essere ignorate per lo scopo di questo tutorial.
+
+## Eseguire il progetto
+1. `cd` nella cartella `hello-world`.
+1. Lanciare il comando `sbt`. Questo aprirà la console di sbt.
+1. Eseguire `~run`. Il carattere `~` è opzionale. Indica ad sbt di eseguirsi ad ogni salvataggio di un file, permettendo un ciclo di modifica, esecuzione e debug più veloce. sbt genererà anche una cartella chiamata `target` che può essere ignorata.
+
+## Modificare il codice
+1. Aprire il file `src/main/scala/Main.scala` in un qualsiasi editor di testo.
+1. Modificare "Hello, World!" in "Hello, New York!"
+1. Se non è stato interrotto il comando sbt, dovrebbe ora apparire "Hello, New York!" sulla console.
+1. Si può continuare a modificare il file, e le modifiche dovrebbero apparire a schermo se non vengono riportati errori.
+
+## Aggiungere una dipendenza
+Vediamo ora come utilizzare librerie pubblicate da terzi per aggiungere ulteriori funzionalità alle nostre applicazioni.
+
+1. Aprire il file `build.sbt` con un qualsiasi editor di testo e aggiungere la seguente riga:
+
+```
+libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2"
+```
+`libraryDependencies` è un set (un tipo di collection in scala), e utilizzando il simbolo `+=`,
+si sta aggiungendo la dipendenza [scala-parser-combinators](https://github.com/scala/scala-parser-combinators) al set di dipendenze che sbt fetcherà quando verà inizializzato.
+Una volta eseguito questo passaggio, sarà possibile importare classi, object ed altro da scala-parser-combinators tramite una semplice istruzione di import.
+
+Ulteriori librerie pubblicate possono essere trovate sul sito
+[Scaladex](https://index.scala-lang.org/), dove è possibile copiare le informazioni delle dipendenze cercate nel file `build.sbt`.
+
+## Next steps
+
+Si consiglia di continuare al tutorial successivo della serie _getting started with sbt_ , ed imparare a [testare il codice Scala con sbt tramite linea di comando](testing-scala-with-sbt-on-the-command-line.html).
+
+**oppure**
+
+- Continuare ad imparare Scala online e in maniera interattiva su
+ [Scala Exercises](https://www.scala-exercises.org/scala_tutorial).
+- Imparare le feature di Scala tramite articoli più concisi su [Tour of Scala]({{ site.baseurl }}/tour/tour-of-scala.html).
\ No newline at end of file
diff --git a/_it/getting-started/sbt-track/testing-scala-with-sbt-on-the-command-line.md b/_it/getting-started/sbt-track/testing-scala-with-sbt-on-the-command-line.md
new file mode 100644
index 0000000000..cac6f0953a
--- /dev/null
+++ b/_it/getting-started/sbt-track/testing-scala-with-sbt-on-the-command-line.md
@@ -0,0 +1,101 @@
+---
+title: Testare scala con sbt da linea di comando
+layout: singlepage-overview
+partof: testing-scala-with-sbt-on-the-command-line
+language: it
+disqus: true
+previous-page: /it/getting-started-with-scala-and-sbt-on-the-command-line
+---
+
+Ci sono diverse librerie e modalità per testare il codice Scala, ma in questo tutorial verrà mostrato come eseguire il testing usando [AnyFunSuite](https://www.scalatest.org/scaladoc/3.2.2/org/scalatest/funsuite/AnyFunSuite.html) del framework ScalaTest.
+Si assume che si sappia [creare un progetto Scala con sbt](getting-started-with-scala-and-sbt-on-the-command-line.html).
+
+## Setup
+1. Da linea di comando, creare una nuova directory in una posizione a propria scelta.
+1. `cd` nella cartella appena creata ed eseguire `sbt new scala/scalatest-example.g8`
+1. Quando richiesto, rinominare il progetto come `ScalaTestTutorial`.
+1. Il progetto avrà già in se la libreria ScalaTest come dipendenza indicata nel file `build.sbt`.
+1. `cd` nel progetto ed eseguire `sbt test`. Questo eseguirà la test suite
+`CubeCalculatorTest` con un unico test chiamato `CubeCalculator.cube`.
+
+```
+sbt test
+[info] Loading global plugins from /Users/username/.sbt/0.13/plugins
+[info] Loading project definition from /Users/username/workspace/sandbox/my-something-project/project
+[info] Set current project to scalatest-example (in build file:/Users/username/workspace/sandbox/my-something-project/)
+[info] CubeCalculatorTest:
+[info] - CubeCalculator.cube
+[info] Run completed in 267 milliseconds.
+[info] Total number of tests run: 1
+[info] Suites: completed 1, aborted 0
+[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
+[info] All tests passed.
+[success] Total time: 1 s, completed Feb 2, 2017 7:37:31 PM
+```
+
+## Comprendere i test
+1. In qualsiasi editor di testo aprire i seguenti due file:
+ * `src/main/scala/CubeCalculator.scala`
+ * `src/test/scala/CubeCalculatorTest.scala`
+1. Nel file `CubeCalculator.scala`, è riportata la definizione della funzione `cube`.
+1. Nel file `CubeCalculatorTest.scala`, è presente una classe chiamata allo stesso modo dell'oggetto che stiamo testando.
+
+```
+ import org.scalatest.funsuite.AnyFunSuite
+
+ class CubeCalculatorTest extends AnyFunSuite {
+ test("CubeCalculator.cube") {
+ assert(CubeCalculator.cube(3) === 27)
+ }
+ }
+```
+
+Analizziamo ogni riga di codice.
+
+* `class CubeCalculatorTest` significa che stiamo testando l'oggetto `CubeCalculator`
+* `extends AnyFunSuite` ci permette di utilizzare la funzionalità della classe AnyFunSuite, come ad esempio la funzione `test`
+* `test` è una funzione proveniente da AnyFunSuite che raccoglie i risultati delle asserzioni all'interno del corpo della funzione.
+* `"CubeCalculator.cube"` è il nome del test. Può essere chiamato in qualsiasi modo, ma la convenzione è "NomeClasse.nomeMetodo".
+* `assert` prende una condizione booleana e stabilisce se il test è superato o no.
+* `CubeCalculator.cube(3) === 27` controlla se l'output della funzione `cube` sia realmente 27.
+Il simbolo `===` è parte di ScalaTest e restituisce messaggi di errore comprensibili.
+
+## Aggiungere un altro test case
+1. Aggiungere un altro blocco di testo contenente il proprio enunciato `assert` che verificherà il cubo di `0`.
+
+ ```
+ import org.scalatest.funsuite.AnyFunSuite
+
+ class CubeCalculatorTest extends AnyFunSuite {
+ test("CubeCalculator.cube 3 should be 27") {
+ assert(CubeCalculator.cube(3) === 27)
+ }
+
+ test("CubeCalculator.cube 0 should be 0") {
+ assert(CubeCalculator.cube(0) === 0)
+ }
+ }
+ ```
+
+1. Lanciare `sbt test` nuovamente e controllare i risultati.
+
+ ```
+ sbt test
+ [info] Loading project definition from C:\projects\scalaPlayground\scalatestpractice\project
+ [info] Loading settings for project root from build.sbt ...
+ [info] Set current project to scalatest-example (in build file:/C:/projects/scalaPlayground/scalatestpractice/)
+ [info] Compiling 1 Scala source to C:\projects\scalaPlayground\scalatestpractice\target\scala-2.13\test-classes ...
+ [info] CubeCalculatorTest:
+ [info] - CubeCalculator.cube 3 should be 27
+ [info] - CubeCalculator.cube 0 should be 0
+ [info] Run completed in 257 milliseconds.
+ [info] Total number of tests run: 2
+ [info] Suites: completed 1, aborted 0
+ [info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0
+ [info] All tests passed.
+ [success] Total time: 3 s, completed Dec 4, 2019 10:34:04 PM
+ ```
+
+## Conclusioni
+In questo tutorial è stato mostrato una delle modalità per testare il codice Scala. Per saperne di più su FunSuite si può consultare [il sito ufficiale](https://www.scalatest.org/getting_started_with_fun_suite).
+Si possono anche consultare altri framework di testing come [ScalaCheck](https://www.scalacheck.org/) e [Specs2](https://etorreborre.github.io/specs2/).
diff --git a/_it/tutorials/scala-for-java-programmers.md b/_it/tutorials/scala-for-java-programmers.md
index fa4327bbeb..180e5795bb 100644
--- a/_it/tutorials/scala-for-java-programmers.md
+++ b/_it/tutorials/scala-for-java-programmers.md
@@ -26,7 +26,7 @@ Scala senza richiedere troppe conoscenze del linguaggio stesso.
Ecco come appeare il codice:
object HelloWorld {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
println("Hello, world!")
}
}
@@ -73,7 +73,7 @@ avrà il nome `HelloWorld.class` e conterrà una classe che può essere
direttamente eseguita con il comando `scala`, come mostra la seguente
sezione.
-### Eseguimo l'esempio
+### Eseguiamo l'esempio
Una volta compilato il programma può esser facilmente eseguito con il
comando scala. L'uso è molto simile al comando java ed accetta le stesse
@@ -91,13 +91,13 @@ codice Java. Tutte le classi del package `java.lang` sono importate di
default mentre le altre richiedono l’esplicito import.
Osserviamo un esempio che lo dimostra. Vogliamo ottenere la data
-corrente e formattarla in accordo con la convezione usata in uno
+corrente e formattarla in accordo con la convenzione usata in uno
specifico paese del mondo, diciamo la Francia. (Altre regioni, come la parte
di lingua francese della Svizzera, utilizzano le stesse convenzioni.)
Le librerie delle classi Java definiscono potenti classi di utilità come
`Date` e `DateFormat`. Poiché Scala interagisce direttamente con Java, non
-esistono le classi equivalenti nella libreria delle classi di Scala--possiamo
+esistono le classi equivalenti nella libreria delle classi di Scala; possiamo
semplicemente importare le classi dei corrispondenti package Java:
import java.util.{Date, Locale}
@@ -105,14 +105,14 @@ semplicemente importare le classi dei corrispondenti package Java:
import java.text.DateFormat._
object FrenchDate {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val now = new Date
val df = getDateInstance(LONG, Locale.FRANCE)
println(df format now)
}
}
-L’istruzione import di Scala è molto simile all’equivalente in Java
+L’istruzione `import` di Scala è molto simile all’equivalente in Java
tuttavia, risulta essere più potente. Più classi possono essere importate
dallo stesso package includendole in parentesi graffe come nella prima riga
di codice precedentemente riportato. Un’altra differenza è evidente
@@ -130,7 +130,7 @@ Java che di default contiene la data corrente. Successivamente, definiamo il
formato della data usando il metodo statico `getDateInstance` importato
precedentemente. Infine, stampiamo la data corrente, formattata secondo la
localizzazione scelta, con l’istanza `DateFormat`; quest’ultima linea mostra
-un’importante proprietà di Scala.I metodi che prendono un argomento possono
+un’importante proprietà di Scala. I metodi che prendono un argomento (ed uno soltanto) possono
essere usati con una sintassi non fissa. Questa forma dell’espressione
df format now
@@ -204,7 +204,7 @@ frase “time flies like an arrow” ogni secondo.
def timeFlies() {
println("time flies like an arrow...")
}
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
oncePerSecond(timeFlies)
}
}
@@ -228,7 +228,7 @@ invece di *timeFlies* e appare come di seguito:
def oncePerSecond(callback: () => Unit) {
while (true) { callback(); Thread sleep 1000 }
}
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
oncePerSecond(() =>
println("time flies like an arrow..."))
}
@@ -262,7 +262,7 @@ modo: `new Complex(1.5, 2.3)`. La classe ha due metodi, `re` e `im` che
danno l’accesso rispettivamente alla parte reale e a quella immaginaria
del numero complesso.
-Da notare che il tipo di ritorno dei due metodi non è specificato esplicitamante.
+Da notare che il tipo di ritorno dei due metodi non è specificato esplicitamente.
Sarà il compilatore che lo dedurrà automaticamente osservando la parte a destra
del segno uguale dei metodi e deducendo che per entrambi si tratta di
valori di tipo `Double`.
@@ -283,7 +283,7 @@ necessario far seguire il nome del metodo da una coppia di parentesi tonde
vuote, come mostrato nel codice seguente:
object ComplexNumbers {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val c = new Complex(1.2, 3.4)
println("imaginary part: " + c.im())
}
@@ -419,7 +419,7 @@ detto in Scala non è difficile:
}
Questa funzione di valutazione lavora effettuando un *pattern matching*
-sull’albero `t`. Intuitivamente il significato della definizione precendente
+sull’albero `t`. Intuitivamente il significato della definizione precedente
dovrebbe esser chiaro:
1. prima controlla se l’albero `t` è un `Sum`; se lo è, esegue il bind del
@@ -499,7 +499,7 @@ sull’espressione `(x+x)+(7+y)`: prima calcola il suo valore
nell’environment `{ x -> 5, y -> 7 }`, dopo calcola la
derivata relativa ad `x` e poi ad `y`.
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val exp: Tree = Sum(Sum(Var("x"),Var("x")),Sum(Const(7),Var("y")))
val env: Environment = { case "x" => 5 case "y" => 7 }
println("Expression: " + exp)
@@ -557,7 +557,7 @@ dichiarazione di un trait:
}
Questa definizione crea un nuovo tipo chiamato `Ord` che ha lo stesso
-ruolo dell’interfaccia `Comparable` in Java e, fornisce l’implementazione
+ruolo dell’interfaccia `Comparable` in Java e fornisce l’implementazione
di default di tre predicati in termini del quarto astraendone uno.
I predicati di uguaglianza e disuguaglianza non sono presenti in questa
dichiarazione poichè sono presenti di default in tutti gli oggetti.
@@ -578,11 +578,11 @@ definendo la classe `Date` come segue:
def year = y
def month = m
def day = d
- override def toString(): String = year + "-" + month + "-" + day
+ override def toString(): String = s"$year-$month-$day"
La parte importante qui è la dichiarazione `extends Ord` che segue il nome
della classe e dei parametri. Dichiara che la classe `Date` eredita il
-codice dal trait `extends Ord`.
+codice dal trait `Ord`.
Successivamente ridefiniamo il metodo `equals`, ereditato da `Object`,
in modo tale che possa confrontare in modo corretto le date confrontando
@@ -646,7 +646,7 @@ restrittivo.
I programmatori Java hanno fatto ricorso all’uso di `Object`, che è il
super-tipo di tutti gli oggetti. Questa soluzione è in ogni caso ben lontana
dall’esser ideale perché non funziona per i tipi base (`int`, `long`, `float`,
-ecc.) ed implica che molto type casts dinamico deve esser fatto dal
+ecc.) ed implica che molto type cast dinamico deve esser fatto dal
programmatore.
Scala rende possibile la definizione delle classi generiche (e metodi) per
@@ -678,7 +678,7 @@ per creare ed usare una cella che contiene un intero si potrebbe scrivere il
seguente codice:
object IntegerReference {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val cell = new Reference[Int]
cell.set(13)
println("Reference contains the half of " + (cell.get * 2))
@@ -694,6 +694,6 @@ poiché è stata dichiarata per memorizzare un intero.
Questo documento ha fornito una veloce introduzione del linguaggio Scala e
presentato alcuni esempi di base. Il lettore interessato può continuare, per
-esempio, leggendo il documento *Scala By Example* che contiene esempi molti più
+esempio, leggendo il documento [*Tour of Scala*](https://docs.scala-lang.org/tour/tour-of-scala.html) che contiene esempi molti più
avanzati e consultare al bisogno la documentazione
*Scala Language Specification*.
diff --git a/_ja/cheatsheets/index.md b/_ja/cheatsheets/index.md
index f34596a8cf..ac3551736c 100644
--- a/_ja/cheatsheets/index.md
+++ b/_ja/cheatsheets/index.md
@@ -5,7 +5,7 @@ title: Scala Cheatsheet
partof: cheatsheet
by: Kenji Ohtsuka
-about: Thanks to Brendan O'Connor. このチートシートは Scala 構文 のクイックリファレンスとして作成されました。 Licensed by Brendan O'Connor under a CC-BY-SA 3.0 license.
+about: Thanks to Brendan O'Connor. このチートシートは Scala 構文 のクイックリファレンスとして作成された。 Licensed by Brendan O'Connor under a CC-BY-SA 3.0 license.
language: ja
---
@@ -260,7 +260,7 @@ breakable {
val div = x / y.toFloat
println("%d/%d = %.1f".format(x, y, div))
}
-
+
+## インターフェース、トレイト、継承
+
+Java 8以降に慣れていれば、ScalaのtraitはJavaのインターフェースに良く似ていることに気づくと思います。
+Pythonのインターフェース(プロトコル)や抽象クラスがあまり使われないのに対して、Scalaではトレイトが常に使われています。
+したがって、この例では両者を比較するのではなく、Scalaのトレイトを使って数学のちょっとした問題を解く方法を紹介します:
+
+```scala
+trait Adder:
+ def add(a: Int, b: Int) = a + b
+
+trait Multiplier:
+ def multiply(a: Int, b: Int) = a * b
+
+// create a class from the traits
+class SimpleMath extends Adder, Multiplier
+val sm = new SimpleMath
+sm.add(1,1) // 2
+sm.multiply(2,2) // 4
+```
+
+クラスやオブジェクトでtraitを使う方法は他にも[たくさんあります][modeling-intro]。
+しかし、これは概念を論理的な動作のグループに整理して、完全な解答を作成するために必要に応じてそれらを統合するために、どのように使うことができるかのちょっとしたアイデアを与えてくれます。
+
+## 制御構文
+
+ここではPythonとScalaの[制御構文][control-structures]を比較します。
+どちらの言語にも `if`/`else`, `while`, `for` ループ、 `try` といった構文があります。
+加えて、Scala には `match` 式があります。
+
+### `if` 文, 1行
+
+
+
+
+
+ if x == 1: print(x)
+
+
+
+
+ if x == 1 then println(x)
+
+
+
+
+
+### `if` 文, 複数行
+
+
+
+
+
+ if x == 1:
+ print("x is 1, as you can see:")
+ print(x)
+
+
+
+
+ if x == 1 then
+ println("x is 1, as you can see:")
+ println(x)
+
+
+
+
+
+### if, else if, else:
+
+
+
+
+
+ if x < 0:
+ print("negative")
+ elif x == 0:
+ print("zero")
+ else:
+ print("positive")
+
+
+
+
+ if x < 0 then
+ println("negative")
+ else if x == 0 then
+ println("zero")
+ else
+ println("positive")
+
+
+
+
+
+### `if` 文からの戻り値
+
+
+
+
+
+ min_val = a if a < b else b
+
+
+
+
+ val minValue = if a < b then a else b
+
+
+
+
+
+### メソッドの本体としての`if`
+
+
+
+
+
+ def min(a, b):
+ return a if a < b else b
+
+
+
+
+ def min(a: Int, b: Int): Int =
+ if a < b then a else b
+
+
+
+
+
+### `while` ループ
+
+
+
+
+
+ i = 1
+ while i < 3:
+ print(i)
+ i += 1
+
+
+
+
+ var i = 1
+ while i < 3 do
+ println(i)
+ i += 1
+
+
+
+
+
+### rangeを指定した`for` ループ
+
+
+
+
+
+ for i in range(0,3):
+ print(i)
+
+
+
+
+ // preferred
+ for i <- 0 until 3 do println(i)
+
+ // also available
+ for (i <- 0 until 3) println(i)
+
+ // multiline syntax
+ for
+ i <- 0 until 3
+ do
+ println(i)
+
+
+
+
+
+### リスト範囲内の`for` ループ
+
+
+
+
+
+ for i in ints: print(i)
+
+ for i in ints:
+ print(i)
+
+
+
+
+ for i <- ints do println(i)
+
+
+
+
+
+### 複数行での`for` ループ
+
+
+
+
+
+ for i in ints:
+ x = i * 2
+ print(f"i = {i}, x = {x}")
+
+
+
+
+ for
+ i <- ints
+ do
+ val x = i * 2
+ println(s"i = $i, x = $x")
+
+
+
+
+
+### 複数の “range” ジェネレータ
+
+
+
+
+
+ for i in range(1,3):
+ for j in range(4,6):
+ for k in range(1,10,3):
+ print(f"i = {i}, j = {j}, k = {k}")
+
+
+
+
+ for
+ i <- 1 to 2
+ j <- 4 to 5
+ k <- 1 until 10 by 3
+ do
+ println(s"i = $i, j = $j, k = $k")
+
+
+
+
+
+### ガード付きジェネレータ (`if` 式)
+
+
+
+
+
+ for i in range(1,11):
+ if i % 2 == 0:
+ if i < 5:
+ print(i)
+
+
+
+
+ for
+ i <- 1 to 10
+ if i % 2 == 0
+ if i < 5
+ do
+ println(i)
+
+
+
+
+
+### 行ごとに複数の`if`条件
+
+
+
+
+
+ for i in range(1,11):
+ if i % 2 == 0 and i < 5:
+ print(i)
+
+
+
+
+ for
+ i <- 1 to 10
+ if i % 2 == 0 && i < 5
+ do
+ println(i)
+
+
+
+
+
+### 内包表記
+
+
+
+
+
+ xs = [i * 10 for i in range(1, 4)]
+ # xs: [10,20,30]
+
+
+
+
+ val xs = for i <- 1 to 3 yield i * 10
+ // xs: Vector(10, 20, 30)
+
+
+
+
+
+### `match` 条件式
+
+
+
+
+
+ # From 3.10, Python supports structural pattern matching
+ # You can also use dictionaries for basic “switch” functionality
+ match month:
+ case 1:
+ monthAsString = "January"
+ case 2:
+ monthAsString = "February"
+ case _:
+ monthAsString = "Other"
+
+
+
+
+ val monthAsString = month match
+ case 1 => "January"
+ case 2 => "February"
+ _ => "Other"
+
+
+
+
+
+### switch/match
+
+
+
+
+
+ # Only from Python 3.10
+ match i:
+ case 1 | 3 | 5 | 7 | 9:
+ numAsString = "odd"
+ case 2 | 4 | 6 | 8 | 10:
+ numAsString = "even"
+ case _:
+ numAsString = "too big"
+
+
+
+
+ val numAsString = i match
+ case 1 | 3 | 5 | 7 | 9 => "odd"
+ case 2 | 4 | 6 | 8 | 10 => "even"
+ case _ => "too big"
+
Scala is unusual because it is usually installed for each of your Scala projects rather than being installed system-wide. Both of the above options manage a specific Scala version per Scala project you create.
-
-
Release Notes
-
For important changes, please consult the release notes.
{% endfor %}
diff --git a/_layouts/inner-page-parent-dropdown.html b/_layouts/root-content-layout.html
similarity index 67%
rename from _layouts/inner-page-parent-dropdown.html
rename to _layouts/root-content-layout.html
index 5b89d3ef47..b45513d346 100644
--- a/_layouts/inner-page-parent-dropdown.html
+++ b/_layouts/root-content-layout.html
@@ -1,13 +1,13 @@
{% include headertop.html %}
{% include headerbottom.html %}
-{% if page.new-version %}This page has a new version.{% endif %}
+{% include alert-banner.html message_id='disabled' message=site.data.messages.scam-banner %}
+
{% include navbar-inner.html %}
-
@@ -22,11 +22,19 @@
{% endif %}
{{ page.title }}
+
+
+
+
+
+
+
Language
-
+
+
diff --git a/_layouts/root-index-layout.html b/_layouts/root-index-layout.html
new file mode 100644
index 0000000000..c236bb7b2f
--- /dev/null
+++ b/_layouts/root-index-layout.html
@@ -0,0 +1,33 @@
+{% include headertop.html %} {% include headerbottom.html %}
+
+
+
+{% include alert-banner.html message_id='disabled' message=site.data.messages.scam-banner %}
+
+{% include navbar-inner.html %}
+
+
+
+
+
+
- {% if page.vote-text %}{{ page.vote-text }}{% endif %}
-
- {% endif %}
+
Status
+ {% if page.stage == "implementation" %}
+
+ This proposal has been accepted by the committee.
+ {% if page.status == "waiting-for-implementation" %}
+ An implementation is welcome in the compiler.
+ {% else %}
+ It might be available as an experimental feature in the latest version of the compiler.
+ {% endif %}
+
+ {% else if page.stage == "completed" %}
+
+ This proposal has been implemented,
+ {% if page.status == "accepted" %}
+ it will be available in the next minor release of the compiler.
+ {% else if page.status == "shipped" %}
+ it is available in the latest version of the compiler.
+ {% endif %}
+
-
- {% include paginator.html urlPath="training" %}
-
\ No newline at end of file
diff --git a/_overviews/FAQ/breakout.md b/_overviews/FAQ/breakout.md
deleted file mode 100644
index dfb41380ab..0000000000
--- a/_overviews/FAQ/breakout.md
+++ /dev/null
@@ -1,233 +0,0 @@
----
-layout: multipage-overview
-title: What is breakOut, and how does it work?
-overview-name: FAQ
-partof: FAQ
-
-num: 5
-permalink: /tutorials/FAQ/:title.html
----
-You might have encountered some code like the one below, and wonder what is
-`breakOut`, and why is it being passed as parameter?
-
- import scala.collection.breakOut
- val map : Map[Int,String] = List("London", "France").map(x => (x.length, x))(breakOut)
-
-
-The answer is found on the definition of `map`:
-
- def map[B, That](f : (A) => B)(implicit bf : CanBuildFrom[Repr, B, That]) : That
-
-Note that it has two parameters. The first is your function and the second is
-an implicit. If you do not provide that implicit, Scala will choose the most
-_specific_ one available.
-
-### About breakOut
-
-So, what's the purpose of `breakOut`? Consider the example given at the
-beginning , You take a list of strings, transform each string into a tuple
-`(Int, String)`, and then produce a `Map` out of it. The most obvious way to do
-that would produce an intermediary `List[(Int, String)]` collection, and then
-convert it.
-
-Given that `map` uses a `Builder` to produce the resulting collection, wouldn't
-it be possible to skip the intermediary `List` and collect the results directly
-into a `Map`? Evidently, yes, it is. To do so, however, we need to pass a
-proper `CanBuildFrom` to `map`, and that is exactly what `breakOut` does.
-
-Let's look, then, at the definition of `breakOut`:
-
- def breakOut[From, T, To](implicit b : CanBuildFrom[Nothing, T, To]) =
- new CanBuildFrom[From, T, To] {
- def apply(from: From) = b.apply() ; def apply() = b.apply()
- }
-
-Note that `breakOut` is parameterized, and that it returns an instance of
-`CanBuildFrom`. As it happens, the types `From`, `T` and `To` have already been
-inferred, because we know that `map` is expecting `CanBuildFrom[List[String],
-(Int, String), Map[Int, String]]`. Therefore:
-
- From = List[String]
- T = (Int, String)
- To = Map[Int, String]
-
-To conclude let's examine the implicit received by `breakOut` itself. It is of
-type `CanBuildFrom[Nothing,T,To]`. We already know all these types, so we can
-determine that we need an implicit of type
-`CanBuildFrom[Nothing,(Int,String),Map[Int,String]]`. But is there such a
-definition?
-
-Let's look at `CanBuildFrom`'s definition:
-
- trait CanBuildFrom[-From, -Elem, +To]
- extends AnyRef
-
-So `CanBuildFrom` is contra-variant on its first type parameter. Because
-`Nothing` is a bottom class (ie, it is a subclass of everything), that means
-*any* class can be used in place of `Nothing`.
-
-Since such a builder exists, Scala can use it to produce the desired output.
-
-### About Builders
-
-A lot of methods from Scala's collections library consists of taking the
-original collection, processing it somehow (in the case of `map`, transforming
-each element), and storing the results in a new collection.
-
-To maximize code reuse, this storing of results is done through a _builder_
-(`scala.collection.mutable.Builder`), which basically supports two operations:
-appending elements, and returning the resulting collection. The type of this
-resulting collection will depend on the type of the builder. Thus, a `List`
-builder will return a `List`, a `Map` builder will return a `Map`, and so on.
-The implementation of the `map` method need not concern itself with the type of
-the result: the builder takes care of it.
-
-On the other hand, that means that `map` needs to receive this builder somehow.
-The problem faced when designing Scala 2.8 Collections was how to choose the
-best builder possible. For example, if I were to write `Map('a' ->
-1).map(_.swap)`, I'd like to get a `Map(1 -> 'a')` back. On the other hand, a
-`Map('a' -> 1).map(_._1)` can't return a `Map` (it returns an `Iterable`).
-
-The magic of producing the best possible `Builder` from the known types of the
-expression is performed through this `CanBuildFrom` implicit.
-
-### About CanBuildFrom
-
-To better explain what's going on, I'll give an example where the collection
-being mapped is a `Map` instead of a `List`. I'll go back to `List` later. For
-now, consider these two expressions:
-
- Map(1 -> "one", 2 -> "two") map Function.tupled(_ -> _.length)
- Map(1 -> "one", 2 -> "two") map (_._2)
-
-The first returns a `Map` and the second returns an `Iterable`. The magic of
-returning a fitting collection is the work of `CanBuildFrom`. Let's consider
-the definition of `map` again to understand it.
-
-The method `map` is inherited from `TraversableLike`. It is parameterized on
-`B` and `That`, and makes use of the type parameters `A` and `Repr`, which
-parameterize the class. Let's see both definitions together:
-
-The class `TraversableLike` is defined as:
-
- trait TraversableLike[+A, +Repr]
- extends HasNewBuilder[A, Repr] with AnyRef
-
- def map[B, That](f : (A) => B)(implicit bf : CanBuildFrom[Repr, B, That]) : That
-
-
-To understand where `A` and `Repr` come from, let's consider the definition of
-`Map` itself:
-
- trait Map[A, +B]
- extends Iterable[(A, B)] with Map[A, B] with MapLike[A, B, Map[A, B]]
-
-Because `TraversableLike` is inherited by all traits which extend `Map`, `A`
-and `Repr` could be inherited from any of them. The last one gets the
-preference, though. So, following the definition of the immutable `Map` and all
-the traits that connect it to `TraversableLike`, we have:
-
- trait Map[A, +B]
- extends Iterable[(A, B)] with Map[A, B] with MapLike[A, B, Map[A, B]]
-
- trait MapLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]]
- extends MapLike[A, B, This]
-
- trait MapLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]]
- extends PartialFunction[A, B] with IterableLike[(A, B), This] with Subtractable[A, This]
-
- trait IterableLike[+A, +Repr]
- extends Equals with TraversableLike[A, Repr]
-
- trait TraversableLike[+A, +Repr]
- extends HasNewBuilder[A, Repr] with AnyRef
-
-If you pass the type parameters of `Map[Int, String]` all the way down the
-chain, we find that the types passed to `TraversableLike`, and, thus, used by
-`map`, are:
-
- A = (Int,String)
- Repr = Map[Int, String]
-
-Going back to the example, the first map is receiving a function of type
-`((Int, String)) => (Int, Int)` and the second map is receiving a function of
-type `((Int, String)) => String`. I use the double parenthesis to emphasize it is
-a tuple being received, as that's the type of `A` as we saw.
-
-With that information, let's consider the other types.
-
- map Function.tupled(_ -> _.length):
- B = (Int, Int)
-
- map (_._2):
- B = String
-
-We can see that the type returned by the first `map` is `Map[Int,Int]`, and the
-second is `Iterable[String]`. Looking at `map`'s definition, it is easy to see
-that these are the values of `That`. But where do they come from?
-
-If we look inside the companion objects of the classes involved, we see some
-implicit declarations providing them. On object `Map`:
-
- implicit def canBuildFrom [A, B] : CanBuildFrom[Map, (A, B), Map[A, B]]
-
-And on object `Iterable`, whose class is extended by `Map`:
-
- implicit def canBuildFrom [A] : CanBuildFrom[Iterable, A, Iterable[A]]
-
-These definitions provide factories for parameterized `CanBuildFrom`.
-
-Scala will choose the most specific implicit available. In the first case, it
-was the first `CanBuildFrom`. In the second case, as the first did not match,
-it chose the second `CanBuildFrom`.
-
-### Back to the first example
-
-Let's see the first example, `List`'s and `map`'s definition (again) to
-see how the types are inferred:
-
- val map : Map[Int,String] = List("London", "France").map(x => (x.length, x))(breakOut)
-
- sealed abstract class List[+A]
- extends LinearSeq[A] with Product with GenericTraversableTemplate[A, List] with LinearSeqLike[A, List[A]]
-
- trait LinearSeqLike[+A, +Repr <: LinearSeqLike[A, Repr]]
- extends SeqLike[A, Repr]
-
- trait SeqLike[+A, +Repr]
- extends IterableLike[A, Repr]
-
- trait IterableLike[+A, +Repr]
- extends Equals with TraversableLike[A, Repr]
-
- trait TraversableLike[+A, +Repr]
- extends HasNewBuilder[A, Repr] with AnyRef
-
- def map[B, That](f : (A) => B)(implicit bf : CanBuildFrom[Repr, B, That]) : That
-
-The type of `List("London", "France")` is `List[String]`, so the types `A` and
-`Repr` defined on `TraversableLike` are:
-
- A = String
- Repr = List[String]
-
-The type for `(x => (x.length, x))` is `(String) => (Int, String)`, so the type
-of `B` is:
-
- B = (Int, String)
-
-The last unknown type, `That` is the type of the result of `map`, and we
-already have that as well:
-
- val map : Map[Int,String] =
-
-So,
-
- That = Map[Int, String]
-
-That means `breakOut` must, necessarily, return a type or subtype of
-`CanBuildFrom[List[String], (Int, String), Map[Int, String]]`.
-
-This answer was originally submitted in response to [this question on Stack Overflow][1].
-
- [1]: https://stackoverflow.com/q/1715681/53013
diff --git a/_overviews/FAQ/chaining-implicits.md b/_overviews/FAQ/chaining-implicits.md
deleted file mode 100644
index cf8f513174..0000000000
--- a/_overviews/FAQ/chaining-implicits.md
+++ /dev/null
@@ -1,109 +0,0 @@
----
-layout: multipage-overview
-title: How can I chain/nest implicit conversions?
-overview-name: FAQ
-partof: FAQ
-
-num: 6
-permalink: /tutorials/FAQ/:title.html
----
-
-The enrich-my-library pattern allows one to seemingly add a method to a class by
-making available an implicit conversion from that class to one that implements
-the method.
-
-Scala does not allow two such implicit conversions taking place, however, so
-one cannot got from `A` to `C` using an implicit `A` to `B` and another
-implicit `B` to `C`. Is there a way around this restriction?
-
-Scala has a restriction on automatic conversions to add a method, which is that
-it won't apply more than one conversion in trying to find methods. For example:
-
- class A(val n: Int)
- class B(val m: Int, val n: Int)
- class C(val m: Int, val n: Int, val o: Int) {
- def total = m + n + o
- }
-
- import scala.language.implicitConversions
-
- // This demonstrates implicit conversion chaining restrictions
- object T1 { // to make it easy to test on REPL
- implicit def toA(n: Int): A = new A(n)
- implicit def aToB(a: A): B = new B(a.n, a.n)
- implicit def bToC(b: B): C = new C(b.m, b.n, b.m + b.n)
-
- // won't work
- println(5.total)
- println(new A(5).total)
-
- // works
- println(new B(5, 5).total)
- println(new C(5, 5, 10).total)
- }
-
-However, if an implicit definition requires an implicit parameter itself, Scala
-_will_ look for additional implicit values for as long as needed. Continuing from
-the last example:
-
- object T2 {
- implicit def toA(n: Int): A = new A(n)
- implicit def aToB[A1](a: A1)(implicit f: A1 => A): B =
- new B(a.n, a.n)
- implicit def bToC[B1](b: B1)(implicit f: B1 => B): C =
- new C(b.m, b.n, b.m + b.n)
-
- // works
- println(5.total)
- println(new A(5).total)
- println(new B(5, 5).total)
- println(new C(5, 5, 10).total)
- }
-
-_"Magic!"_, you might say. Not so. Here is how the compiler would translate each
-one:
-
- object T1Translated {
- implicit def toA(n: Int): A = new A(n)
- implicit def aToB(a: A): B = new B(a.n, a.n)
- implicit def bToC(b: B): C = new C(b.m, b.n, b.m + b.n)
-
- // Scala won't do this
- println(bToC(aToB(toA(5))).total)
- println(bToC(aToB(new A(5))).total)
-
- // Just this
- println(bToC(new B(5, 5)).total)
-
- // No implicits required
- println(new C(5, 5, 10).total)
- }
-
- object T2Translated {
- implicit def toA(n: Int): A = new A(n)
- implicit def aToB[A1](a: A1)(implicit f: A1 => A): B =
- new B(a.n, a.n)
- implicit def bToC[B1](b: B1)(implicit f: B1 => B): C =
- new C(b.m, b.n, b.m + b.n)
-
- // Scala does this
- println(bToC(5)(x => aToB(x)(y => toA(y))).total)
- println(bToC(new A(5))(x => aToB(x)(identity)).total)
- println(bToC(new B(5, 5))(identity).total)
-
- // no implicits required
- println(new C(5, 5, 10).total)
- }
-
-So, while `bToC` is being used as an implicit conversion, `aToB` and `toA` are
-being passed as _implicit parameters_, instead of being chained as implicit
-conversions.
-
-See also:
-
-* [Context bounds](context-bounds.html)
-* [A discussion on types, origin and precedence of implicits](finding-implicits.html)
-
-This question and answer were originally submitted on [Stack Overflow][1].
-
- [1]: https://stackoverflow.com/questions/5332801/how-can-i-chain-implicits-in-scala/5332804
diff --git a/_overviews/FAQ/collections.md b/_overviews/FAQ/collections.md
deleted file mode 100644
index 6c0ad3355d..0000000000
--- a/_overviews/FAQ/collections.md
+++ /dev/null
@@ -1,382 +0,0 @@
----
-layout: multipage-overview
-title: How are the collections structured? Which one should I choose?
-overview-name: FAQ
-partof: FAQ
-
-num: 8
-permalink: /tutorials/FAQ/:title.html
----
-## Foreword
-
-There's a [2.8 collection walk-through][1] by Martin Odersky which should
-probably be your first reference. It has been supplemented as well with
-[architectural notes][2], which will be of particular interest to those who
-want to design their own collections.
-
-The rest of this answer was written way before any such thing existed (in fact,
-before 2.8.0 itself was released).
-
-You can find a paper about it as [Scala SID #3][3]. Other papers in that area
-should be interesting as well to people interested in the differences between
-Scala 2.7 and 2.8.
-
-I'll quote from the paper, selectively, and complement with some thoughts of
-mine. There are also some images, generated by Matthias at decodified.com, and
-the original SVG files can be found [here][4].
-
-## The collection classes/traits themselves
-
-There are actually three hierarchies of traits for the collections: one for
-mutable collections, one for immutable collections, and one which doesn't make
-any assumptions about the collections.
-
-There's also a distinction between parallel, serial and maybe-parallel
-collections, which was introduced with Scala 2.9. I'll talk about them in the
-next section. The hierarchy described in this section refers _exclusively to
-non-parallel collections_.
-
-The following image shows the non-specific hierarchy as of Scala 2.10:
-
-[![General collection hierarchy][5]][5]
-
-All elements shown are traits. In the other two hierarchies there are also
-classes directly inheriting the traits as well as classes which can be _viewed
-as_ belonging in that hierarchy through implicit conversion to wrapper classes.
-The legend for these graphs can be found after them.
-
-Graph for immutable hierarchy:
-
-[![Immutable collection hierarchy][10]][10]
-
-Graph for mutable hierarchy:
-
-[![Mutable collection hierarchy][11]][11]
-
-Legend:
-
-[![Graph legend][8]][8]
-
-Here's an abbreviated ASCII depiction of the collection hierarchy, for those who can't see the images.
-
- Traversable
- |
- |
- Iterable
- |
- +------------------+--------------------+
- Map Set Seq
- | | |
- | | +------+-------+
- SortedMap SortedSet Buffer Vector LinearSeq
- |
- |
- BitSet
-
-## Parallel Collections
-
-When Scala 2.9 introduced parallel collections, one of the design goals was to
-make their use as seamless as possible. In the simplest terms, one can replace
-a non-parallel (serial) collection with a parallel one, and instantly reap the
-benefits.
-
-However, since all collections until then were serial, many algorithms using
-them assumed and depended on the fact that they _were_ serial. Parallel
-collections fed to the methods with such assumptions would fail. For this
-reason, all the hierarchy described in the previous section _mandates serial
-processing_.
-
-Two new hierarchies were created to support the parallel collections.
-
-The parallel collections hierarchy has the same names for traits, but preceded
-with `Par`: `ParIterable`, `ParSeq`, `ParMap` and `ParSet`. Note that there is
-no `ParTraversable`, since any collection supporting parallel access is capable
-of supporting the stronger `ParIterable` trait. It doesn't have some of the
-more specialized traits present in the serial hierarchy either. This whole
-hierarchy is found under the directory `scala.collection.parallel`.
-
-The classes implementing parallel collections also differ, with `ParHashMap`
-and `ParHashSet` for both mutable and immutable parallel collections, plus
-`ParRange` and `ParVector` implementing `immutable.ParSeq` and `ParArray`
-implementing `mutable.ParSeq`.
-
-Another hierarchy also exists that mirrors the traits of serial and parallel
-collections, but with a prefix `Gen`: `GenTraversable`, `GenIterable`,
-`GenSeq`, `GenMap` and `GenSet`. These traits are _parents_ to both parallel
-and serial collections. This means that a method taking a `Seq` cannot receive
-a parallel collection, but a method taking a `GenSeq` is expected to work with
-both serial and parallel collections.
-
-Given the way these hierarchies were structured, code written for Scala 2.8 was
-fully compatible with Scala 2.9, and demanded serial behavior. Without being
-rewritten, it cannot take advantage of parallel collections, but the changes
-required are very small.
-
-### Using Parallel Collections
-
-Any collection can be converted into a parallel one by calling the method `par`
-on it. Likewise, any collection can be converted into a serial one by calling
-the method `seq` on it.
-
-If the collection was already of the type requested (parallel or serial), no
-conversion will take place. If one calls `seq` on a parallel collection or
-`par` on a serial collection, however, a new collection with the requested
-characteristic will be generated.
-
-Do not confuse `seq`, which turns a collection into a non-parallel collection,
-with `toSeq`, which returns a `Seq` created from the elements of the
-collection. Calling `toSeq` on a parallel collection will return a `ParSeq`,
-not a serial collection.
-
-## The Main Traits
-
-While there are many implementing classes and subtraits, there are some basic
-traits in the hierarchy, each of which providing more methods or more specific
-guarantees, but reducing the number of classes that could implement them.
-
-In the following subsections, I'll give a brief description of the main traits
-and the idea behind them.
-
-### Trait TraversableOnce
-
-This trait is pretty much like trait `Traversable` described below, but with
-the limitation that you can only use it _once_. That is, any methods called on
-a `TraversableOnce` _may_ render it unusable.
-
-This limitation makes it possible for the same methods to be shared between the
-collections and `Iterator`. This makes it possible for a method that works with
-an `Iterator` but not using `Iterator`-specific methods to actually be able to
-work with any collection at all, plus iterators, if rewritten to accept
-`TraversableOnce`.
-
-Because `TraversableOnce` unifies collections and iterators, and iterators are
-not considered collections, it does not appear in the previous graphs, which
-concern themselves only with collections.
-
-### Trait Traversable
-
-At the top of the _collection_ hierarchy is trait `Traversable`. Its only
-abstract operation is
-
- def foreach[U](f: Elem => U)
-
-The operation is meant to traverse all elements of the collection, and apply
-the given operation f to each element. The application is done for its side
-effect only; in fact any function result of f is discarded by foreach.
-
-Traversable objects can be finite or infinite. An example of an infinite
-traversable object is the stream of natural numbers `Stream.from(0)`. The
-method `hasDefiniteSize` indicates whether a collection is possibly infinite.
-If `hasDefiniteSize` returns true, the collection is certainly finite. If it
-returns false, the collection has not been fully elaborated yet, so it might
-be infinite or finite.
-
-This class defines methods which can be efficiently implemented in terms of
-`foreach` (over 40 of them).
-
-### Trait Iterable
-
-This trait declares an abstract method `iterator` that returns an iterator that
-yields all the collection’s elements one by one. The `foreach` method in
-`Iterable` is implemented in terms of `iterator`. Subclasses of `Iterable`
-often override foreach with a direct implementation for efficiency.
-
-Class `Iterable` also adds some less-often used methods to `Traversable`, which
-can be implemented efficiently only if an `iterator` is available. They are
-summarized below.
-
- xs.iterator An iterator that yields every element in xs, in the same order as foreach traverses elements.
- xs takeRight n A collection consisting of the last n elements of xs (or, some arbitrary n elements, if no order is defined).
- xs dropRight n The rest of the collection except xs takeRight n.
- xs sameElements ys A test whether xs and ys contain the same elements in the same order
-
-### Seq, Set and Map
-
-After `Iterable` there come three base traits which inherit from it: `Seq`,
-`Set`, and `Map`. All three have an `apply` method and all three implement the
-`PartialFunction` trait, but the meaning of `apply` is different in each case.
-
-I trust the meaning of `Seq`, `Set` and `Map` is intuitive. After them, the
-classes break up in specific implementations that offer particular guarantees
-with regards to performance, and the methods it makes available as a result of
-it. Also available are some traits with further refinements, such as
-`LinearSeq`, `IndexedSeq` and `SortedSet`.
-
-## Complete Overview
-
-### Base Classes and Traits
-
-* `TraversableOnce` -- All methods and behavior common to collections and iterators.
-
- * `Traversable` -- Basic collection class. Can be implemented just with `foreach`.
-
- * `TraversableProxy` -- Proxy for a `Traversable`. Just point `self` to the real collection.
- * `TraversableView` -- A Traversable with some non-strict methods.
- * `TraversableForwarder` -- Forwards most methods to `underlying`, except `toString`, `hashCode`, `equals`, `stringPrefix`, `newBuilder`, `view` and all calls creating a new iterable object of the same kind.
- * `mutable.Traversable` and `immutable.Traversable` -- same thing as `Traversable`, but restricting the collection type.
- * Other special-cases `Iterable` classes, such as `MetaData`, exists.
- * `Iterable` -- A collection for which an `Iterator` can be created (through `iterator`).
- * `IterableProxy`, `IterableView`, `mutable` and `immutable.Iterable`.
-
- * `Iterator` -- A trait which is not descendant of `Traversable`. Define `next` and `hasNext`.
- * `CountedIterator` -- An `Iterator` defining `count`, which returns the elements seen so far.
- * `BufferedIterator` -- Defines `head`, which returns the next element without consuming it.
- * Other special-cases `Iterator` classes, such as `Source`, exists.
-
-### The Sequences
-
-* `Seq` -- A sequence of elements. One assumes a well-defined size and element repetition. Extends `PartialFunction` as well.
-
- * `IndexedSeq` -- Sequences that support O(1) element access and O(1) length computation.
- * `IndexedSeqView`
- * `immutable.PagedSeq` -- An implementation of `IndexedSeq` where the elements are produced on-demand by a function passed through the constructor.
- * `immutable.IndexedSeq`
-
- * `immutable.Range` -- A delimited sequence of integers, closed on the lower end, open on the high end, and with a step.
- * `immutable.Range.Inclusive` -- A `Range` closed on the high end as well.
- * `immutable.NumericRange` -- A more generic version of `Range` which works with any `Integral`.
- * `immutable.NumericRange.Inclusive`, `immutable.NumericRange.Exclusive`.
- * `immutable.WrappedString`, `immutable.RichString` -- Wrappers which enables seeing a `String` as a `Seq[Char]`, while still preserving the `String` methods. I'm not sure what the difference between them is.
-
- * `mutable.IndexedSeq`
- * `mutable.GenericArray` -- An `Seq`-based array-like structure. Note that the "class" `Array` is Java's `Array`, which is more of a memory storage method than a class.
- * `mutable.ResizableArray` -- Internal class used by classes based on resizable arrays.
- * `mutable.PriorityQueue`, `mutable.SynchronizedPriorityQueue` -- Classes implementing prioritized queues -- queues where the elements are dequeued according to an `Ordering` first, and order of queueing last.
- * `mutable.PriorityQueueProxy` -- an abstract `Proxy` for a `PriorityQueue`.
-
- * `LinearSeq` -- A trait for linear sequences, with efficient time for `isEmpty`, `head` and `tail`.
-
- * `immutable.LinearSeq`
- * `immutable.List` -- An immutable, singly-linked, list implementation.
- * `immutable.Stream` -- A lazy-list. Its elements are only computed on-demand, but memoized (kept in memory) afterwards. It can be theoretically infinite.
- * `mutable.LinearSeq`
- * `mutable.DoublyLinkedList` -- A list with mutable `prev`, `head` (`elem`) and `tail` (`next`).
- * `mutable.LinkedList` -- A list with mutable `head` (`elem`) and `tail` (`next`).
- * `mutable.MutableList` -- A class used internally to implement classes based on mutable lists.
- * `mutable.Queue`, `mutable.QueueProxy` -- A data structure optimized for FIFO (First-In, First-Out) operations.
- * `mutable.QueueProxy` -- A `Proxy` for a `mutable.Queue`.
-
- * `SeqProxy`, `SeqView`, `SeqForwarder`
-
- * `immutable.Seq`
-
- * `immutable.Queue` -- A class implementing a FIFO-optimized (First-In, First-Out) data structure. There is no common superclass of both `mutable` and `immutable` queues.
- * `immutable.Stack` -- A class implementing a LIFO-optimized (Last-In, First-Out) data structure. There is no common superclass of both `mutable` `immutable` stacks.
- * `immutable.Vector` -- ?
- * `scala.xml.NodeSeq` -- A specialized XML class which extends `immutable.Seq`.
- * `immutable.IndexedSeq` -- As seen above.
- * `immutable.LinearSeq` -- As seen above.
-
- * `mutable.ArrayStack` -- A class implementing a LIFO-optimized data structure using arrays. Supposedly significantly faster than a normal stack.
- * `mutable.Stack`, `mutable.SynchronizedStack` -- Classes implementing a LIFO-optimized data structure.
- * `mutable.StackProxy` -- A `Proxy` for a `mutable.Stack`..
- * `mutable.Seq`
-
- * `mutable.Buffer` -- Sequence of elements which can be changed by appending, prepending or inserting new members.
- * `mutable.ArrayBuffer` -- An implementation of the `mutable.Buffer` class, with constant amortized time for the append, update and random access operations. It has some specialized subclasses, such as `NodeBuffer`.
- * `mutable.BufferProxy`, `mutable.SynchronizedBuffer`.
- * `mutable.ListBuffer` -- A buffer backed by a list. It provides constant time append and prepend, with most other operations being linear.
- * `mutable.ObservableBuffer` -- A *mixin* trait which, when mixed to a `Buffer`, provides notification events through a `Publisher` interfaces.
- * `mutable.IndexedSeq` -- As seen above.
- * `mutable.LinearSeq` -- As seen above.
-
-### The Sets
-
-* `Set` -- A set is a collection that includes at most one of any object.
-
- * `SortedSet` -- A set whose elements are ordered.
- * `immutable.SortedSet`
- * `immutable.BitSet` -- A set of integers stored as a bitset.
- * `immutable.TreeSet` -- An implementation of a `SortedSet` based on a tree.
- * `mutable.SortedSet`
- * `mutable.BitSet` -- A set of integers stored as a bitset.
-
- * `SetProxy` -- A `Proxy` for a `Set`.
-
- * `immutable.Set`
- * `immutable.HashSet` -- An implementation of `Set` based on element hashing.
- * `immutable.ListSet` -- An implementation of `Set` based on lists.
- * Additional set classes exists to provide optimized implementations for sets from 0 to 4 elements.
- * `immutable.SetProxy` -- A `Proxy` for an immutable `Set`.
-
- * `mutable.Set`
- * `mutable.HashSet` -- An implementation of `Set` based on element hashing.
- * `mutable.ImmutableSetAdaptor` -- A class implementing a mutable `Set` from an immutable `Set`.
- * `LinkedHashSet` -- An implementation of `Set` based on lists.
- * `ObservableSet` -- A *mixin* trait which, when mixed with a `Set`, provides notification events through a `Publisher` interface.
- * `SetProxy` -- A `Proxy` for a `Set`.
- * `SynchronizedSet` -- A *mixin* trait which, when mixed with a `Set`, provides notification events through a `Publisher` interface.
-
-### The Maps
-
-* `Map` -- An `Iterable` of `Tuple2`, which also provides methods for retrieving a value (the second element of the tuple) given a key (the first element of the tuple). Extends `PartialFunction` as well.
- * `MapProxy` -- A `Proxy` for a `Map`.
- * `DefaultMap` -- A trait implementing some of `Map`'s abstract methods.
- * `SortedMap` -- A `Map` whose keys are sorted.
- * `immutable.SortMap`
- * `immutable.TreeMap` -- A class implementing `immutable.SortedMap`.
- * `immutable.Map`
- * `immutable.MapProxy`
- * `immutable.HashMap` -- A class implementing `immutable.Map` through key hashing.
- * `immutable.IntMap` -- A class implementing `immutable.Map` specialized for `Int` keys. Uses a tree based on the binary digits of the keys.
- * `immutable.ListMap` -- A class implementing `immutable.Map` through lists.
- * `immutable.LongMap` -- A class implementing `immutable.Map` specialized for `Long` keys. See `IntMap`.
- * There are additional classes optimized for an specific number of elements.
- * `mutable.Map`
- * `mutable.HashMap` -- A class implementing `mutable.Map` through key hashing.
- * `mutable.ImmutableMapAdaptor` -- A class implementing a `mutable.Map` from an existing `immutable.Map`.
- * `mutable.LinkedHashMap` -- ?
- * `mutable.ListMap` -- A class implementing `mutable.Map` through lists.
- * `mutable.MultiMap` -- A class accepting more than one distinct value for each key.
- * `mutable.ObservableMap` -- A *mixin* which, when mixed with a `Map`, publishes events to observers through a `Publisher` interface.
- * `mutable.OpenHashMap` -- A class based on an open hashing algorithm.
- * `mutable.SynchronizedMap` -- A *mixin* which should be mixed with a `Map` to provide a version of it with synchronized methods.
- * `mutable.MapProxy`.
-
-## Bonus Questions
-
-* Why the Like classes exist (e.g. TraversableLike)?
-
-This was done to achieve maximum code reuse. The concrete *generic*
-implementation for classes with a certain structure (a traversable, a map, etc)
-is done in the Like classes. The classes intended for general consumption,
-then, override selected methods that can be optimized.
-
-* What the companion methods are for (e.g. List.companion)?
-
-The builder for the classes, ie, the object which knows how to create instances
-of that class in a way that can be used by methods like `map`, is created by a
-method in the companion object. So, in order to build an object of type X, I
-need to get that builder from the companion object of X. Unfortunately, there
-is no way, in Scala, to get from class X to object X. Because of that, there is
-a method defined in each instance of X, `companion`, which returns the
-companion object of class X.
-
-While there might be some use for such method in normal programs, its target is
-enabling code reuse in the collection library.
-
-* How I know what implicit objects are in scope at a given point?
-
-You aren't supposed to care about that. They are implicit precisely so that you
-don't need to figure out how to make it work.
-
-These implicits exists to enable the methods on the collections to be defined
-on parent classes but still return a collection of the same type. For example,
-the `map` method is defined on `TraversableLike`, but if you used on a `List`
-you'll get a `List` back.
-
-This answer was originally submitted in response to [this question][9] on Stack
-Overflow.
-
-
- [1]: https://docs.scala-lang.org/overviews/collections/introduction.html
- [2]: https://docs.scala-lang.org/overviews/core/architecture-of-scala-collections.html
- [3]: https://www.scala-lang.org/sid/3
- [4]: https://github.com/sirthias/scala-collections-charts/downloads
- [5]: /resources/images/tour/collections-diagram.svg
- [6]: https://i.stack.imgur.com/2fjoA.png
- [7]: https://i.stack.imgur.com/Dsptl.png
- [8]: /resources/images/tour/collections-legend-diagram.svg
- [9]: https://stackoverflow.com/q/1722137/53013
- [10]: /resources/images/tour/collections-immutable-diagram.svg
- [11]: /resources/images/tour/collections-mutable-diagram.svg
diff --git a/_overviews/FAQ/context-bounds.md b/_overviews/FAQ/context-bounds.md
deleted file mode 100644
index 8efd4174da..0000000000
--- a/_overviews/FAQ/context-bounds.md
+++ /dev/null
@@ -1,104 +0,0 @@
----
-layout: multipage-overview
-title: What are Scala context bounds?
-overview-name: FAQ
-partof: FAQ
-
-num: 3
-permalink: /tutorials/FAQ/:title.html
----
-
-What is a Context Bound?
-------------------------
-
-Context bounds were introduced in Scala 2.8.0, and are typically used with the
-so-called _type class pattern_, a pattern of code that emulates the
-functionality provided by Haskell type classes, though in a more verbose
-manner.
-
-A context bound requires a _parameterized type_, such as `Ordered[A]`,
-but unlike `String`.
-
-A context bound describes an implicit _value_. It is used to declare that for
-some type `A`, there is an
-implicit value of type `B[A]` available. The syntax goes like this:
-
- def f[A : B](a: A) = g(a) // where g requires an implicit value of type B[A]
-
-The common example of usage in Scala is this:
-
- def f[A : ClassTag](n: Int) = new Array[A](n)
-
-An `Array` initialization on a parameterized type requires a `ClassTag` to
-be available, for arcane reasons related to type erasure and the non-erasure
-nature of arrays.
-
-Another very common example in the library is a bit more complex:
-
- def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b)
-
-Here, `implicitly` is used to retrieve the implicit value we want, one of type
-`Ordering[A]`, which class defines the method `compare(a: A, b: A): Int`.
-
-We'll see another way of doing this below.
-
-How are Context Bounds implemented?
----------------------------------------------------
-
-It shouldn't be surprising that context bounds are
-implemented with implicit parameters, given their definition. Actually, the
-syntax I showed are syntactic sugars for what really happens. See below how
-they de-sugar:
-
- def g[A : B](a: A) = h(a)
- def g[A](a: A)(implicit ev: B[A]) = h(a)
-
-So, naturally, one can write them in their full syntax, which is specially
-useful for context bounds:
-
- def f[A](a: A, b: A)(implicit ord: Ordering[A]) = ord.compare(a, b)
-
-What are Context Bounds used for?
----------------------------------
-
-Context bounds are mainly used in what has become known as _typeclass pattern_,
-as a reference to Haskell's type classes. Basically, this pattern implements an
-alternative to inheritance by making functionality available through a sort of
-implicit adapter pattern.
-
-The classic example is Scala 2.8's `Ordering`. The usage is:
-
- def f[A : Ordering](a: A, b: A) = if (implicitly[Ordering[A]].lt(a, b)) a else b
-
-Though you'll usually see that written like this:
-
- def f[A](a: A, b: A)(implicit ord: Ordering[A]) = {
- import ord._
- if (a < b) a else b
- }
-
-Which take advantage of some implicit conversions inside `Ordering` that enable
-the traditional operator style. Another example in Scala 2.8 is the `Numeric`:
-
- def f[A : Numeric](a: A, b: A) = implicitly[Numeric[A]].plus(a, b)
-
-A more complex example is the new collection usage of `CanBuildFrom`, but
-there's already a very long answer about that, so I'll avoid it here. And, as
-mentioned before, there's the `ClassTag` usage, which is required to
-initialize new arrays without concrete types.
-
-Though it has been possible for a long time, the use of context bounds has
-really taken off in 2010, and is now found to some degree in most of Scala's
-most important libraries and frameworks. The most extreme example of its usage,
-though, is the Scalaz library, which brings a lot of the power of Haskell to
-Scala. I recommend reading up on typeclass patterns to get more acquainted it
-all the ways in which it can be used.
-
-Related questions of interest:
-
-* [A discussion on types, origin and precedence of implicits](finding-implicits.html)
-* [Chaining implicits](chaining-implicits.html)
-
-This answer was originally submitted in response to [this question on Stack Overflow][1].
-
- [1]: https://stackoverflow.com/q/4465948/53013
diff --git a/_overviews/FAQ/finding-implicits.md b/_overviews/FAQ/finding-implicits.md
deleted file mode 100644
index 5be593d931..0000000000
--- a/_overviews/FAQ/finding-implicits.md
+++ /dev/null
@@ -1,415 +0,0 @@
----
-layout: multipage-overview
-title: Where does Scala look for implicits?
-overview-name: FAQ
-partof: FAQ
-
-num: 7
-permalink: /tutorials/FAQ/:title.html
----
-
-Newcomers to Scala often ask: Where does the compiler look for implicits?
-
-For example, where do the values for `integral` below come from?
-
- scala> import scala.math._
- import scala.math._
-
- scala> def foo[T](t: T)(implicit integral: Integral[T]): Unit = {
- println(integral)
- }
- foo: [T](t: T)(implicit integral: scala.math.Integral[T])Unit
-
- scala> foo(0)
- scala.math.Numeric$IntIsIntegral$@3dbea611
-
- scala> foo(0L)
- scala.math.Numeric$LongIsIntegral$@48c610af
-
-The natural continuation of this line of inquiry leads to a second question: How
-does the compiler choose which implicit to use, in certain situations of apparent
-ambiguity (but that compile anyway)?
-
-For instance, `scala.Predef` defines two conversions from `String`: one to
-`WrappedString` and another to `StringOps`. Both classes, however, share a lot
-of methods, so why doesn't Scala complain about ambiguity when, say, calling
-`map`?
-
-**Note:** this question was inspired by [this other question on Stack
-Overflow][4], but states the problem in more general terms. The example was
-copied from there, because it is referred to in the answer.
-
-## Types of Implicits
-
-Implicits in Scala refers to either a value that can be passed "automatically",
-so to speak, or a conversion from one type to another that is made
-automatically.
-
-### Implicit Conversion
-
-Speaking very briefly about the latter type, if one calls a method `m` on an
-object `o` of a class `C`, and that class does not support method `m`, then
-Scala will look for an implicit conversion from `C` to something that _does_
-support `m`. A simple example would be the method `map` on `String`:
-
- "abc".map(_.toInt)
-
-`String` does not support the method `map`, but `StringOps` does, and there's
-an implicit conversion from `String` to `StringOps` available (see `implicit
-def augmentString` on `Predef`).
-
-### Implicit Parameters
-
-The other kind of implicit is the implicit _parameter_. These are passed to
-method calls like any other parameter, but the compiler tries to fill them in
-automatically. If it can't, it will complain. One _can_ pass these parameters
-explicitly, which is how one uses `breakOut`, for example (see question about
-`breakOut`, on a day you are feeling up for a challenge).
-
-In this case, one has to declare the need for an implicit, such as the `foo`
-method declaration:
-
- def foo[T](t: T)(implicit integral: Integral[T]): Unit = {
- println(integral)
- }
-
-### Implicit conversions as implicit parameters
-
-There's one situation where an implicit is both an implicit conversion and an
-implicit parameter. For example:
-
- def getIndex[T, CC](seq: CC, value: T)(implicit conv: CC => Seq[T]) = seq.indexOf(value)
-
- getIndex("abc", 'a')
-
-The method `getIndex` can receive any object, as long as there is an implicit
-conversion available from its class to `Seq[T]`. Because of that, a `String` can be
-passed to `getIndex`, and it will work.
-
-Behind the scenes, the compiler changes `seq.IndexOf(value)` to
-`conv(seq).indexOf(value)`.
-
-### Context Bounds
-
-Another common pattern in implicit parameters is the _type class pattern_. This
-pattern enables the provision of common interfaces to classes which did not
-declare them. It can both serve as a bridge pattern -- gaining separation of
-concerns -- and as an adapter pattern.
-
-The `Integral` class mentioned above is a classic example of type class pattern.
-Another example on Scala's standard library is `Ordering`. Scalaz is a library
-that makes heavy use of this pattern.
-
-This is an example of its use:
-
- def sum[T](list: List[T])(implicit integral: Integral[T]): T = {
- import integral._ // get the implicits in question into scope
- list.foldLeft(integral.zero)(_ + _)
- }
-
-There is also a syntactic sugar for it, called a _context bound_, which is made
-less useful by the need to refer to the implicit. A straight conversion of that
-method looks like this:
-
- def sum[T : Integral](list: List[T]): T = {
- val integral = implicitly[Integral[T]]
- import integral._ // get the implicits in question into scope
- list.foldLeft(integral.zero)(_ + _)
- }
-
-Context bounds are more useful when you just need to _pass_ them to other
-methods that use them. For example, the method `sorted` on `Seq` needs an
-implicit `Ordering`. To create a method `reverseSort`, one could write:
-
- def reverseSort[T : Ordering](seq: Seq[T]) = seq.sorted.reverse
-
-Because `Ordering[T]` was implicitly passed to `reverseSort`, it can then pass
-it implicitly to `sorted`.
-
-## Where do Implicits Come From?
-
-As described above, there are several contexts in which an implicit value may be required
-for an expression to typecheck. The required implicit type is what determines
-which value is selected. That value is found either in lexical scope or,
-failing that, in what is called implicit scope.
-
-### Implicits Defined in Lexical Scope
-
-When a value of a certain name is required, lexical scope is searched for
-a value with that name. Similarly, when an implicit value of a certain type is required,
-lexical scope is searched for a value with that type.
-
-Any such value which can be referenced with its "simple" name, without
-selecting from another value using dotted syntax, is an eligible implicit value.
-
-For example, here is a function that takes an implicit scaling factor.
-The function requires a parameter of type `Int`, and there is a value
-of that type in scope. The variable name `n` does not matter in this
-case.
-
- implicit val n: Int = 5
- def scale(x: Int)(implicit y: Int) = x * y
- scale(5) // takes n from the current scope, with the result 25
-
-The invocation can be rewritten `scale(5)(n)`. If `n` can be referenced
-using its simple name, as shown here, it is eligible as an implicit value.
-
-An implicit value can be introduced into scope by an import statement:
-
- import scala.collection.JavaConverters._
- def env = System.getenv().asScala // extension method enabled by imported implicit
- val term = env("TERM") // it's a Scala Map
-
-There may be more than one such value because they have different names.
-
-In that case, overload resolution is used to pick one of them. The algorithm
-for overload resolution is the same used to choose the reference for a
-given name, when more than one term in scope has that name. For example,
-`println` is overloaded, and each overload takes a different parameter type.
-An invocation of `println` requires selecting the correct overloaded method.
-
-In implicit search, overload resolution chooses a value among more than one
-that have the same required type. Usually this entails selecting a narrower
-type or a value defined in a subclass relative to other eligible values.
-
-The rule that the value must be accessible using its simple name means
-that the normal rules for name binding apply.
-
-In summary, a definition for `x` shadows a definition in
-an enclosing scope. But a binding for `x` can also be introduced by
-local imports. Imported symbols can't override definitions of the same
-name in an enclosing scope. Similarly, wildcard imports can't override
-an import of a specific name, and names in the current package that are
-visible from other source files can't override imports or local definitions.
-
-These are the normal rules for deciding what `x` means in a given context,
-and also determine which value `x` is accessible by its simple name and
-is eligible as an implicit.
-
-This means that an implicit in scope can be disabled by shadowing it with
-a term of the same name.
-
-For example, here, `X.f` is supplied the imported `X.s`: `X.f(s)`.
-The body of `f` uses an implicit `Int`, from the immediate scope,
-which shadows the `n` from `Y`, which is therefore not an eligible
-implicit value. The parameter `s` shadows the member `s`.
-
-The method `g` does not compile because the implicit `t` is shadowed
-by a `t` that is not implicit, so no implicit `T` is in scope.
-
- object Y {
- implicit val n: Int = 17
- trait T {
- implicit val i: Int = 17
- implicit def t: T = ???
- }
- object X extends T {
- implicit val n: Int = 42
- implicit val s: String = "hello, world\n"
- def f(implicit s: String) = implicitly[String] * implicitly[Int]
- override def t: T = ???
- def g = implicitly[T]
- }
- }
- import Y.X._
- f
-
-The invocation of `f` was enabled by importing from `Y.X.`. But it is
-not convenient to require an import to access implicit values
-provided by a package.
-
-If an implicit value is not found in lexical scope, implicit search
-continues in implicit scope.
-
-### Implicits Defined in Implicit Scope
-
-Implicit syntax can avoid the [import tax][1], which of course is a "sin tax,"
-by leveraging "implicit scope", which depends on the type of the implicit
-instead of imports in lexical scope.
-
-When an implicit of type `T` is required, implicit scope includes
-the companion object `T`:
-
- trait T
- object T { implicit val t: T = new T { } }
-
-When an `F[T]` is required, implicit scope includes both the companion
-of `F` and the companion of the type argument, e.g., `object C` for `F[C]`.
-
-In addition, implicit scope includes the companions of the base classes
-of `F` and `C`, including package objects, such as `p` for `p.F`.
-
-### Companion Objects of a Type
-
-There are two object companions of note here. First, the object companion of
-the "source" type is looked into. For instance, inside the object `Option`
-there is an implicit conversion to `Iterable`, so one can call `Iterable`
-methods on `Option`, or pass `Option` to something expecting an `Iterable`. For
-example:
-
- for {
- x <- List(1, 2, 3)
- y <- Some('x')
- } yield (x, y)
-
-That expression is translated by the compiler into
-
- List(1, 2, 3).flatMap(x => Some('x').map(y => (x, y)))
-
-However, `List.flatMap` expects a `TraversableOnce`, which `Option` is not. The
-compiler then looks inside `Option`'s object companion and finds the conversion
-to `Iterable`, which is a `TraversableOnce`, making this expression correct.
-
-Second, the companion object of the expected type:
-
- List(1, 2, 3).sorted
-
-The method `sorted` takes an implicit `Ordering`. In this case, it looks inside
-the object `Ordering`, companion to the class `Ordering`, and finds an implicit
-`Ordering[Int]` there.
-
-Note that companion objects of super classes are also looked into. For example:
-
- class A(val n: Int)
- object A {
- implicit def str(a: A) = "A: %d" format a.n
- }
- class B(val x: Int, y: Int) extends A(y)
- val b = new B(5, 2)
- val s: String = b // s == "A: 2"
-
-This is how Scala found the implicit `Numeric[Int]` and `Numeric[Long]` in the
-opening example, by the way, as they are found inside `Numeric`, not `Integral`.
-
-### Implicit scope of an argument's type
-
-If you have a method with an argument type `A`, then the implicit scope of type
-`A` will also be considered. Here "implicit scope" means all these rules
-will be applied recursively -- for example, the companion object of `A` will be
-searched for implicits, as per the rule above.
-
-Note that this does not mean the implicit scope of `A` will be searched for
-conversions of that parameter alone, but of the whole expression. For example:
-
- class A(val n: Int) {
- def +(other: A) = new A(n + other.n)
- }
- object A {
- implicit def fromInt(n: Int) = new A(n)
- }
-
- // This becomes possible:
- 1 + new A(1)
- // because it is converted into this:
- A.fromInt(1) + new A(1)
-
-### Implicit scope of type arguments
-
-This is required to make the type class pattern really work. Consider
-`Ordering`, for instance... it comes with some implicits in its companion
-object, but you can't add stuff to it. So how can you make an `Ordering` for
-your own class that is automatically found?
-
-Let's start with the implementation:
-
- class A(val n: Int)
- object A {
- implicit val ord = new Ordering[A] {
- def compare(x: A, y: A) = implicitly[Ordering[Int]].compare(x.n, y.n)
- }
- }
-
-So, consider what happens when you call
-
- List(new A(5), new A(2)).sorted
-
-As we saw, the method `sorted` expects an `Ordering[A]` (actually, it expects
-an `Ordering[B]`, where `B >: A`). There isn't any such thing inside
-`Ordering`, and there is no "source" type on which to look. Obviously, it is
-finding it inside `A`, which is a _type argument_ of `Ordering`.
-
-This is also how various collection methods expecting `CanBuildFrom` work: the
-implicits are found inside companion objects to the type parameters of
-`CanBuildFrom`.
-
-**Note**: `Ordering` is defined as `trait Ordering[T]`, where `T` is a type
-parameter. The implicit looked for above is `Ordering[A]`, where
-`A` is an actual type, not type parameter: it is a _type argument_ to
-`Ordering`. See section 7.2 of the [Scala Specification][6].
-
-### Outer Objects for Nested Types
-
-The principle is simple:
-
- class A(val n: Int) {
- class B(val m: Int) { require(m < n) }
- }
- object A {
- implicit def bToString(b: A#B) = "B: %d" format b.m
- }
- val a = new A(5)
- val b = new a.B(3)
- val s: String = b // s == "B: 3"
-
-A real world example of this would be welcome. Please share your example!
-
-### Package Objects Can Contribute Implicit Values
-
-An implicit value in a package object can be made available either
-in lexical scope or in implicit scope.
-
-To be available in lexical scope, the packages must be declared as nested packages:
-
- package object p { implicit val s: String = "hello, world" }
- package p {
- package q {
- object X { def f = implicitly[String] }
- }
- }
-
-This is sensitive to name binding rules. The following example compiles
-only if the package object is in a separate file, in which case the import is used:
-
- package object p { implicit val s: String = "hello, world" }
- package p {
- package q {
- object Y {
- implicit val s: String = "bye"
- }
- object X {
- import Y._
- def f = implicitly[String]
- }
- }
- }
-
-A package object can also offer implicit values of types in subpackages:
-
- package object p { implicit val c: q.C = new q.C }
- package p.q {
- class C
- object X { def f = implicitly[C] }
- }
-
-Here, the implicit is supplied in implicit scope of `C`.
-
-### Call To Action
-
-Avoid taking this question as being the final arbiter of what is happening.
-If you do notice it has become out-of-date, do [open a ticket about it][7], or, if
-you know how to correct it, please fix it.
-
-Related questions of interest:
-
-* [Context bounds](context-bounds.html)
-* [Chaining implicits](chaining-implicits.html)
-
-This question and answer were originally submitted on [Stack Overflow][3].
-
- [1]: https://jsuereth.com/scala/2011/02/18/2011-implicits-without-tax.html
- [2]: https://issues.scala-lang.org/browse/SI-4427
- [3]: https://stackoverflow.com/q/5598085/53013
- [4]: https://stackoverflow.com/questions/5512397/passing-scala-math-integral-as-implicit-parameter
- [5]: https://scala-lang.org/files/archive/spec/2.11/06-expressions.html
- [6]: https://scala-lang.org/files/archive/spec/2.11/07-implicits.html
- [7]: https://github.com/scala/docs.scala-lang/issues
diff --git a/_overviews/FAQ/finding-symbols.md b/_overviews/FAQ/finding-symbols.md
deleted file mode 100644
index c9737400c0..0000000000
--- a/_overviews/FAQ/finding-symbols.md
+++ /dev/null
@@ -1,205 +0,0 @@
----
-layout: multipage-overview
-title: How do I find what some symbol means or does?
-overview-name: FAQ
-partof: FAQ
-
-num: 1
-
-permalink: /tutorials/FAQ/:title.html
----
-We can divide the operators in Scala, for the purpose of teaching, into four categories:
-
-* Keywords/reserved symbols
-* Normal methods or values
-* Methods provided by implicit conversion
-* Syntactic sugars/composition
-
-And let's see some arbitrary examples:
-
- <- // Keyword
- -> // Method provided by implicit conversion
- <= // Common method
- ++= // Can be a common method or syntactic sugar involving ++ method
- :: // Common method or object
- _+_ // Not really a single operator; it's parsed as _ + _
-
-The exact meaning of most of these methods depends on the class they are defined
-on. For example, `<=` on `Int` means _"less than or equal to"_, but it might
-mean something else in another class. `::` in an expression is probably the method of the class
-`List` but it can also refer to the object of the same name (and in a pattern it
-definitely does).
-
-So, let's discuss these categories.
-
-Keywords/reserved symbols
--------------------------
-
-There are a few symbols in Scala that are special and cannot be defined or used as method names.
-Two of them are considered proper keywords, while others are just "reserved". They are:
-
- // Keywords
- <- // Used on for-comprehensions, to separate pattern from generator
- => // Used for function types, function literals and import renaming
-
- // Reserved
- ( ) // Delimit expressions and parameters
- [ ] // Delimit type parameters
- { } // Delimit blocks
- . // Method call and path separator
- // /* */ // Comments
- # // Used in type notations
- : // Type ascription or context bounds
- <: >: // Upper and lower bounds
- <% // View bounds (deprecated)
- " """ // Strings
- ' // Indicate symbols and characters
- @ // Annotations and variable binding on pattern matching
- ` // Denote constant or enable arbitrary identifiers
- , // Parameter separator
- ; // Statement separator
- _* // vararg expansion
- _ // Many different meanings
-
-These are all _part of the language_, and, as such, can be found in any text
-that properly describe the language, such as [Scala Specification][1](PDF)
-itself.
-
-The last one, the underscore, deserve a special description, because it is
-widely used, and has different meanings depending on the context. Here's a sample:
-
- import scala._ // Wild card -- all of Scala is imported
- import scala.{ Predef => _, _ } // Exclusion, everything except Predef
- def f[M[_]] // Higher kinded type parameter
- def f(m: M[_]) // Existential type
- _ + _ // Anonymous function placeholder parameter
- m _ // Eta expansion of method into method value
- m(_) // Partial function application
- _ => 5 // Discarded parameter
- case _ => // Wild card pattern -- matches anything
- f(xs: _*) // Sequence xs is passed as multiple parameters to f(ys: T*)
- case Seq(xs @ _*) // Identifier xs is bound to the whole matched sequence
-
-Common methods
---------------
-
-Many symbols are simply methods of a class, a trait, or an object. For instance, if you do
-
- List(1, 2) ++ List(3, 4)
-
-You'll find the method `++` right on the Scaladoc for [List][5]. However,
-there's one convention that you must be aware when searching for methods.
-Methods ending in colon (`:`) bind _to the right_ instead of the left. In other
-words, while the above method call is equivalent to:
-
- List(1, 2).++(List(3, 4))
-
-If I had, instead `1 :: List(2, 3)`, that would be equivalent to:
-
- List(2, 3).::(1)
-
-So you need to look at the type found _on the right_ when looking for methods
-ending in colon. Consider, for instance:
-
- 1 +: List(2, 3) :+ 4
-
-The first method (`+:`) binds to the right, and is found on `List`. The second
-method (`:+`) is just a normal method, and binds to the left -- again, on
-`List`.
-
-If the name ends in `=`, look for the method called the same without `=` and
-read the last section.
-
-If you aren't sure what the type of the receiver is, you can look up the symbol
-on the Scaladoc [index page for identifiers not starting with letters][2] (for
-standard Scala library; of course, third-party libraries can add their own
-symbolic methods, for which you should look at the corresponding page of _their_
-Scaladoc).
-
-Types and objects can also have symbolic names; in particular, it should be mentioned
-that for types with two type parameters the name can be written _between_ parameters,
-so that e.g. `Int <:< Any` is the same as `<:<[Int, Any]`.
-
-Methods provided by implicit conversion
----------------------------------------
-
-If you did not find the symbol you are looking for in the list of reserved symbols, then
-it must be a method, or part of one. But, often, you'll see some symbol and the
-documentation for the class will not have that method. When this happens,
-either you are looking at a composition of one or more methods with something
-else, or the method has been imported into scope, or is available through an
-imported implicit conversion.
-
-These can also be found in Scaladoc's [index][2], as mentioned above.
-
-All Scala code has three automatic imports:
-
- // Not necessarily in this order
- import java.lang._
- import scala._
- import scala.Predef._
-
-The first two only make classes and singleton objects available, none of which
-look like operators. [`Predef`][3] is the only interesting one for this post.
-
-Looking inside `Predef` shows some symbolic names:
-
- class <:<
- class =:=
- object =:=
- object <%< // removed in Scala 2.10
- def ???
-
-There is also `::`, which doesn't appear in the Scaladoc, but is mentioned in the comments.
-In addition, `Predef` makes some methods available through _implicit conversions_. Just
-look at the methods and classes with `implicit` modifier that receive, as parameter, an
-object of type that is receiving the method. For example, consider `"a" -> 1`. We need
-to look for an implicit which works on `"a"`, and so it can take `String`, one of its
-supertypes (`AnyRef` or `Any`) or a type parameter. In this case, we find
-`implicit final class ArrowAssoc[A](private val self: A)` which makes this implicit
-available on all types.
-
-Other implicit conversions may be visible in your scope depending on imports, extended types or
-self-type annotations. See [Finding implicits](finding-implicits.html) for details.
-
-Syntactic sugars/composition
------------------------------
-
-So, here's a few syntactic sugars that may hide a method:
-
- class Example(arr: Array[Int] = Array.fill(5)(0)) {
- def apply(n: Int) = arr(n)
- def update(n: Int, v: Int) = arr(n) = v
- def a = arr(0); def a_=(v: Int) = arr(0) = v
- def b = arr(1); def b_=(v: Int) = arr(1) = v
- def c = arr(2); def c_=(v: Int) = arr(2) = v
- def d = arr(3); def d_=(v: Int) = arr(3) = v
- def e = arr(4); def e_=(v: Int) = arr(4) = v
- def +(v: Int) = new Example(arr map (_ + v))
- def unapply(n: Int) = if (arr.indices contains n) Some(arr(n)) else None
- }
-
- val ex = new Example
- println(ex(0)) // means ex.apply(0)
- ex(0) = 2 // means ex.update(0, 2)
- ex.b = 3 // means ex.b_=(3)
- val ex(c) = 2 // calls ex.unapply(2) and assigns result to c, if it's Some; throws MatchError if it's None
- ex += 1 // means ex = ex + 1; if Example had a += method, it would be used instead
-
-The last one is interesting, because *any* symbolic method can be combined with `=` in that way.
-
-And, of course, all of the above can be combined in various combinations, e.g.
-
- (_+_) // An expression, or parameter, that is an anonymous function with
- // two parameters, used exactly where the underscores appear, and
- // which calls the "+" method on the first parameter passing the
- // second parameter as argument.
-
-This answer was originally submitted in response to [this question on Stack Overflow][6].
-
- [1]: https://scala-lang.org/files/archive/spec/2.11/
- [2]: https://www.scala-lang.org/api/current/index.html#index.index-_
- [3]: https://www.scala-lang.org/api/current/scala/Predef$.html
- [4]: https://www.scala-lang.org/api/current/scala/Predef$$ArrowAssoc.html
- [5]: https://www.scala-lang.org/api/current/scala/collection/immutable/List.html
- [6]: https://stackoverflow.com/q/7888944/53013
diff --git a/_overviews/FAQ/index.md b/_overviews/FAQ/index.md
index 91ab76367b..a3aa167c98 100644
--- a/_overviews/FAQ/index.md
+++ b/_overviews/FAQ/index.md
@@ -1,19 +1,374 @@
---
layout: singlepage-overview
-title: Scala FAQs
+title: Scala FAQ
permalink: /tutorials/FAQ/index.html
+redirect_from:
+ - "/tutorials/FAQ/breakout.html"
+ - "/tutorials/FAQ/chaining-implicits.html"
+ - "/tutorials/FAQ/collections.html"
+ - "/tutorials/FAQ/context-bounds.html"
+ - "/tutorials/FAQ/finding-implicits.html"
+ - "/tutorials/FAQ/finding-symbols.html"
+ - "/tutorials/FAQ/stream-view.html"
+ - "/tutorials/FAQ/yield.html"
---
-A collection of frequently asked questions and their answers! Graciously
-provided by Daniel Sobral, adapted from his StackOverflow posts.
+Frequently asked questions, with _brief_ answers and/or links to
+longer answers.
-## FAQs
+This list only includes questions that _actually_ come up over and
+over again in Scala chat rooms and forums.
-{% assign overviews = site.overviews | sort: 'num' %}
-
-{% for overview in overviews %}
- {% if overview.partof == "FAQ" %}
-
+## General questions
+
+### Where can I ask Scala questions?
+
+See our [Community page](https://scala-lang.org/community/).
+
+### What's a good book about Scala?
+
+Our [Books page](https://docs.scala-lang.org/books.html) lists a few
+especially popular, well-known books.
+
+We don't have a list of all the Scala books that
+are out there; there are many.
+
+You can go on the \#scala-users room [on
+Discord](https://discord.com/invite/scala) or another community forum and
+ask for book recommendations. You'll get more helpful
+answers if you provide some information about your background and your
+reasons for wanting to learn Scala.
+
+### Should I learn Scala 2, or Scala 3?
+
+Don't sweat the decision too much. You can't go far wrong either
+way. It isn't that hard to switch later, in either direction.
+
+Regardless, you should choose Scala 3 unless you have a specific reason
+to need 2. Scala 3 is the future, and it's the best version for
+falling in love with the language and everything it has to offer.
+Scala 3 has plenty of books, plenty of libraries, and high quality
+tooling.
+
+That said, many Scala jobs are still Scala 2 jobs. In most cases, the
+cause of that is simply inertia, especially at large shops. (But it can
+sometimes be due to availability of specific libraries.)
+
+### Where are Scala jobs advertised?
+
+This is addressed on our [Community page](https://scala-lang.org/community/#scala-jobs).
+
+In short, the only officially sanctioned place is the \#jobs channel
+[on Discord](https://discord.com/invite/scala).
+
+### Who's behind Scala?
+
+This is answered [on the Governance page](https://www.scala-lang.org/governance/).
+
+### Can I use the Scala logo?
+
+See [scala/scala-lang#1040](https://github.com/scala/scala-lang/issues/1040).
+
+## Technical questions
+
+### What IDEs are available for Scala?
+
+See [this doc page](https://docs.scala-lang.org/getting-started/scala-ides.html).
+
+### What compiler flags are recommended?
+
+The list of available options is
+[here](https://docs.scala-lang.org/overviews/compiler-options/index.html).
+
+What flags people choose varies widely from shop to shop and from
+individual to individual. `-Xlint` is valuable to enable. Some brave
+people enable `-Werror` (formerly `-Xfatal-warnings`) to make warnings
+fatal.
+
+[sbt-tpolecat](https://github.com/typelevel/sbt-tpolecat) is an
+opinionated sbt plugin that sets many options automatically, depending
+on Scala version; you can see
+[here](https://github.com/typelevel/sbt-tpolecat/blob/main/plugin/src/main/scala/io/github/davidgregory084/TpolecatPlugin.scala)
+what it sets. Some choices it makes are oriented towards
+pure-functional programmers.
+
+### How do I find what some symbol means or does?
+
+A [Stack Overflow answer](https://stackoverflow.com/a/7890032) lays
+out what the different kinds of symbol in Scala are and explains the
+most commonly used symbols.
+
+Scala allows symbolic method names. So if you see a random-looking
+operator like `>=@=>` in Scala code, it might simply be a method in
+some library, rather than having any special meaning in the language
+itself.
+
+You can search for symbols on Google. For example, if you want to
+know what `<:<` means, searching for `scala <:<` works fine. If you
+get poor results, try surrounding the symbol with double quotes.
+
+### I want Scala 2.13 (or some other version); why does sbt say it's using Scala 2.12?
+
+sbt 1.x always uses Scala 2.12 to compile build definitions.
+Your sbt 1.x build definition is always a Scala 2.12 program.
+
+Regardless, in your `build.sbt`, you can set `scalaVersion` to whichever
+available distribution you want and your program code will be compiled with that version.
+
+### I want Scala 3. Why does `versionNumberString` say I'm on 2.13?
+
+To aid migration, Scala 3 currently uses the Scala 2.13 library as-is,
+with only minor supplements. That's why `versionString` and
+`versionNumberString` report that Scala 2 is in use:
+
+```
+Welcome to Scala 3.3.4 (17.0.3, Java OpenJDK 64-Bit Server VM).
+Type in expressions for evaluation. Or try :help.
+
+scala> util.Properties.versionNumberString
+val res0: String = 2.13.15
+```
+
+Note that even the latest Scala 3 version might not use the very
+latest Scala 2 standard library, since the 3 and 2 release schedules
+aren't coordinated.
+
+So how do you ask for the Scala 3 version number? Scala 3 offers
+`dotty.tools.dotc.config.Properties.versionNumberString`, but only if
+you have scala3-compiler on the classpath. So that works in the Scala 3
+REPL, but won't work in typical Scala 3 application code.
+
+For an alternative way to detect the Scala 3 version, see
+[this gist](https://gist.github.com/romanowski/de14691cab7340134e197419bc48919a).
+
+There is a proposal to provide something easier at [scala/scala3#22144](https://github.com/scala/scala3/issues/22144).
+
+### Why is my (abstract or overridden) `val` null?
+
+
+
+See [this]({{ site.baseurl }}/tutorials/FAQ/initialization-order.html).
+
+### Which type of collection should I choose?
+
+See the [Scala 2.13 Collections Guide](https://docs.scala-lang.org/overviews/collections-2.13/introduction.html).
+
+### What are context bounds?
+
+It's syntactic sugar for a context parameter (an `implicit` parameter in Scala 2, or a `using` parameter in Scala 3).
+
+More details in this [section of the Scala 3 Book](https://docs.scala-lang.org/scala3/book/ca-context-bounds.html) and this [Stack Overflow answer](https://stackoverflow.com/a/4467012).
+
+### How does `for / yield` work?
+
+It is syntactic sugar for nested `map`, `flatMap`, and `withFilter` calls.
+
+For an in-depth explanation
+see this [Stack Overflow answer](https://stackoverflow.com/a/1059501).
+
+### What is the difference between view, stream and iterator?
+
+[Answer on Stack Overflow](https://stackoverflow.com/a/5159356).
+
+### What does `_` mean?
+
+Many things really, depending on the context.
+[This answer on Stack Overflow](https://stackoverflow.com/a/8001065/4111404)
+has a good summary of all the meanings it has.
+
+Note that, even if the specific meaning is different,
+according to the situation, it usually means _"anything"_.
+
+### Why doesn't my function literal with `_` in it work?
+
+Not all function literals (aka lambdas) can be expressed with the `_`
+syntax.
+
+Every occurrence of `_` introduces a new variable. So `_ + _` means
+`(x, y) => x + y`, not `x => x + x`. The latter function cannot be
+written using the `_` syntax.
+
+Also, the scope of `_` is always the smallest enclosing expression.
+The scope is determined purely syntactically, during parsing, without
+regard to types. So for example, `foo(_ + 1)` always means `foo(x =>
+x + 1)`; it never means `x => foo(x + 1)`. The latter function cannot
+be written using the `_` syntax.
+
+See also [SLS 6.23.2](https://scala-lang.org/files/archive/spec/2.13/06-expressions.html#placeholder-syntax-for-anonymous-functions).
+
+### Why couldn't Scala infer the correct type in my code?
+
+It is difficult to generalize about type inference, because various features of the language
+affect how your code is construed. There may be several ways to rewrite your code to make
+the types fall out naturally.
+
+The most straightforward workaround is to supply explicit types in your code.
+
+That may involve specifying an explicit type to a definition, or a type argument to a method.
+
+Type inference is greatly improved in Scala 3. If Scala 2 doesn't compile your code, it's worth trying with Scala 3.
+
+Sometimes, using multiple parameter lists helps inference, as explained in [this section of the language tour](https://docs.scala-lang.org/tour/multiple-parameter-lists.html#drive-type-inference).
+
+For common questions about type inference involving `toSet`, see the discussions on [this ticket](https://github.com/scala/bug/issues/7743) and a related [Q&A](https://stackoverflow.com/questions/5544536/in-scala-2-type-inference-fails-on-set-made-with-toset).
+
+### Can I chain or nest implicit conversions?
+
+Not really, but you can [make it work](https://stackoverflow.com/a/5332804).
+
+However, note that implicit conversions are, in general,
+[discouraged](https://contributors.scala-lang.org/t/can-we-wean-scala-off-implicit-conversions/4388).
+
+### Where does Scala look for implicits?
+
+See this [answer on Stack Overflow](https://stackoverflow.com/a/5598107).
+
+### Why do primitive type parameters erase to `Object`?
+
+So for example, a `List[Int]` in Scala code will appear to Java as a
+`List[Object]`. The Java type system doesn't allow primitive types to
+appear as type parameters, but couldn't they appear as their boxed
+equivalents, such as `List[java.lang.Integer]`?
+
+One would hope so, but doing it that way was tried, and it proved impossible.
+[This SO question](https://stackoverflow.com/questions/11167430/why-are-primitive-types-such-as-int-erased-to-object-in-scala)
+sadly lacks a concise explanation, but it does link to past discussions.
+
+### What's the difference between methods and functions?
+
+For example, how does a method such as:
+
+ def square(x: Int): Int = x * x
+
+differ from a function value such as:
+
+ val square: Int => Int = x => x * x
+
+For **Scala 2**, there is a [complete answer on Stack Overflow](https://stackoverflow.com/a/2530007/4111404)
+and a [summary with practical differences](https://tpolecat.github.io/2014/06/09/methods-functions.html).
+
+In **Scala 3**, the differences are fewer.
+[Context functions]({{ site.scala3ref }}/contextual/context-functions.html)
+accept given parameters and
+[polymorphic functions]({{ site.scala3ref }}/new-types/polymorphic-function-types.html)
+have type parameters.
+
+It's standard to use methods most of the time,
+except when a function value is actually needed.
+[Eta-expansion](https://stackoverflow.com/questions/39445018/what-is-the-eta-expansion-in-scala),
+converts methods to functions when needed.
+For example, a method such as `map` expects a function,
+but even if you `def square` as shown above, you can
+still `xs.map(square)`.
+
+### What's the difference between types and classes?
+
+Types are primarily a compile-time concept. At compile time,
+every expression is assigned a type by the compiler.
+
+Classes are primarily a runtime concept and are platform-dependent.
+At runtime on the JVM, every value is either a primitive value
+or an instance of exactly one class.
+
+Some type information exists only at compile time,
+for multiple reasons, most notoriously
+[type erasure](https://en.wikipedia.org/wiki/Type_erasure).
+
+For an in-depth treatment of types vs. classes, see the blog post
+["There are more types than classes"](https://typelevel.org/blog/2017/02/13/more-types-than-classes.html).
+
+### Should I declare my parameterless method with or without parentheses?
+
+In other words, should one write `def foo()` or just `def foo`?
+
+Answer: by convention, the former is used to indicate that a method
+has side effects.
+
+For more details, see the Scala Style Guide, [here](https://docs.scala-lang.org/style/naming-conventions.html#parentheses).
+
+### How can a method in a superclass return a value of the “current” type?
+
+Using `this.type` will only work if you are returning `this` itself.
+`this.type` means "the singleton type of this instance". Only `this`
+itself has the type `this.type`; other instances of the same class do
+not.
+
+What does work for returning other values of the same type?
+
+Possible solutions include F-bounded polymorphism _(familiar to Java
+programmers)_, type members, and the [typeclass
+pattern](http://tpolecat.github.io/2013/10/12/typeclass.html).
+
+This [blog post](http://tpolecat.github.io/2015/04/29/f-bounds.html)
+argues against F-bounds and in favor of typeclasses;
+see also [this Stack Overflow post](https://stackoverflow.com/questions/59813323/advantages-of-f-bounded-polymorphism-over-typeclass-for-return-current-type-prob) for some counterpoint.
+
+### What does `<:<` mean?
+
+It's a "type constraint", and it comes from the standard library,
+not from the language itself.
+See [this blog post](https://blog.bruchez.name/2015/11/generalized-type-constraints-in-scala.html).
+
+### I dislike requiring callers to wrap optional arguments in `Some(...)`; is there a better way?
+
+Not really. See [this answer on Stack Overflow](https://stackoverflow.com/a/65256691/4111404).
+
+### Why is `implicit val` usually recommended over `implicit object`?
+
+The latter has a singleton type, which is too specific.
+See [answer on Stack Overflow](https://stackoverflow.com/a/65258340/4111404).
+
+### I got a `StackOverflowError` while compiling my code. Is it a compiler bug?
+
+It might be.
+
+To find out, try giving the compiler more stack and see if the
+error goes away.
+
+It's possible for the compiler to run out of stack when compiling some
+kinds of heavily nested code. The JVM's default stack size is rather
+small, so this can happen sooner than you might expect.
+
+The stack size can be changed by passing `-Xss...` at JVM startup, for
+example `-Xss16M`. How to do this depends on what IDE and/or build
+tool you are using. For sbt, add it to `.jvmopts`.
+
+If the stack overflow doesn't go away no matter how much stack you
+give the compiler, then it's a compiler bug. Please report it on the
+[Scala 2 bug tracker](https://github.com/scala/bug/issues) or [Scala 3
+bug tracker](https://github.com/scala/scala3/issues), but check
+first if it's a duplicate of an existing ticket.
+
+### I set a setting in sbt but nothing happened. Why?
+
+There could be a lot of reasons. An extremely common one, that
+almost everyone runs into sooner or later, is that you have a bare
+setting in a multi-project build.
+
+For example, if you add this to your `build.sbt`:
+
+ scalaVersion := "2.13.16"
+
+that's a "bare" setting, and you might expect it to apply build-wide.
+But it doesn't. _It only applies to the root project._
+
+In many cases one should instead write:
+
+ ThisBuild / scalaVersion := "2.13.16"
+
+Other possibilities include:
+
+* the common settings pattern, where you put shared settings
+ in a `val`, typically named `commonSettings`, and then
+ `.settings(commonSettings)` in every project you want to
+ apply to them to.
+* in interactive usage only, `set every`
+
+Here's some further reading:
+
+* [documentation on multi-project builds](https://www.scala-sbt.org/1.x/docs/Multi-Project.html#ThisBuild)
+* [issue about bare settings](https://github.com/sbt/sbt/issues/6217)
diff --git a/_overviews/FAQ/initialization-order.md b/_overviews/FAQ/initialization-order.md
index fcaf6d9471..ebe07308c6 100644
--- a/_overviews/FAQ/initialization-order.md
+++ b/_overviews/FAQ/initialization-order.md
@@ -2,87 +2,94 @@
layout: multipage-overview
title: Why is my abstract or overridden val null?
overview-name: FAQ
-partof: FAQ
-
-num: 9
permalink: /tutorials/FAQ/:title.html
---
## Example
-To understand the problem, let's pick the following concrete example.
+
+The following example illustrates how classes in a subclass relation
+witness the initialization of two fields which are inherited from
+their top-most parent. The values are printed during the constructor
+of each class, that is, when an instance is initialized.
abstract class A {
val x1: String
val x2: String = "mom"
- println("A: " + x1 + ", " + x2)
+ println(s"A: $x1, $x2")
}
class B extends A {
val x1: String = "hello"
- println("B: " + x1 + ", " + x2)
+ println(s"B: $x1, $x2")
}
class C extends B {
override val x2: String = "dad"
- println("C: " + x1 + ", " + x2)
+ println(s"C: $x1, $x2")
}
-Let's observe the initialization order through the Scala REPL:
+In the Scala REPL we observe:
scala> new C
A: null, null
B: hello, null
C: hello, dad
-Only when we get to the constructor of `C` are both `x1` and `x2` initialized. Therefore, constructors of `A` and `B` risk running into `NullPointerException`s.
+Only when we get to the constructor of `C` are both `x1` and `x2` properly initialized.
+Therefore, constructors of `A` and `B` risk running into `NullPointerException`s,
+since fields are null-valued until set by a constructor.
## Explanation
-A 'strict' or 'eager' val is one which is not marked lazy.
-In the absence of "early definitions" (see below), initialization of strict vals is done in the following order.
+A "strict" or "eager" val is a `val` which is not a `lazy val`.
+Initialization of strict vals is done in the following order:
1. Superclasses are fully initialized before subclasses.
-2. Otherwise, in declaration order.
-
-Naturally when a val is overridden, it is not initialized more than once. So though x2 in the above example is seemingly defined at every point, this is not the case: an overridden val will appear to be null during the construction of superclasses, as will an abstract val.
-
-There is a compiler flag which can be useful for identifying this situation:
-
-**-Xcheckinit**: Add runtime check to field accessors.
-
-It is inadvisable to use this flag outside of testing. It adds significantly to the code size by putting a wrapper around all potentially uninitialized field accesses: the wrapper will throw an exception rather than allow a null (or 0/false in the case of primitive types) to silently appear. Note also that this adds a *runtime* check: it can only tell you anything about code paths which you exercise with it in place.
-
-Using it on the opening example:
-
- % scalac -Xcheckinit a.scala
- % scala -e 'new C'
- scala.UninitializedFieldError: Uninitialized field: a.scala: 13
- at C.x2(a.scala:13)
- at A.(a.scala:5)
- at B.(a.scala:7)
- at C.(a.scala:12)
-
-### Solutions ###
+2. Within the body or "template" of a class, vals are initialized in declaration order,
+ the order in which they are written in source.
+
+When a `val` is overridden, it's more precise to say that its accessor method (the "getter") is overridden.
+So the access to `x2` in class `A` invokes the overridden getter in class `C`.
+That getter reads the underlying field `C.x2`.
+This field is not yet initialized during the construction of `A`.
+
+## Mitigation
+
+The [`-Wsafe-init` compiler flag](https://docs.scala-lang.org/scala3/reference/other-new-features/safe-initialization.html)
+in Scala 3 enables a compile-time warning for accesses to uninitialized fields:
+
+ -- Warning: Test.scala:8:6 -----------------------------------------------------
+ 8 | val x1: String = "hello"
+ | ^
+ | Access non-initialized value x1. Calling trace:
+ | ├── class B extends A { [ Test.scala:7 ]
+ | │ ^
+ | ├── abstract class A { [ Test.scala:1 ]
+ | │ ^
+ | └── println(s"A: $x1, $x2") [ Test.scala:5 ]
+ | ^^
+
+In Scala 2, the `-Xcheckinit` flag adds runtime checks in the generated bytecode to identify accesses of uninitialized fields.
+That code throws an exception when an uninitialized field is referenced
+that would otherwise be used as a `null` value (or `0` or `false` in the case of primitive types).
+Note that these runtime checks only report code that is actually executed at runtime.
+Although these checks can be helpful to find accesses to uninitialized fields during development,
+it is never advisable to enable them in production code due to the performance cost.
+
+## Solutions
Approaches for avoiding null values include:
-#### Use lazy vals ####
-
- abstract class A {
- val x1: String
- lazy val x2: String = "mom"
+### Use class / trait parameters
+ abstract class A(val x1: String, val x2: String = "mom") {
println("A: " + x1 + ", " + x2)
}
- class B extends A {
- lazy val x1: String = "hello"
-
+ class B(x1: String = "hello", x2: String = "mom") extends A(x1, x2) {
println("B: " + x1 + ", " + x2)
}
- class C extends B {
- override lazy val x2: String = "dad"
-
+ class C(x2: String = "dad") extends B(x2 = x2) {
println("C: " + x1 + ", " + x2)
}
// scala> new C
@@ -90,31 +97,29 @@ Approaches for avoiding null values include:
// B: hello, dad
// C: hello, dad
-Usually the best answer. Unfortunately you cannot declare an abstract lazy val. If that is what you're after, your options include:
+Values passed as parameters to the superclass constructor are available in its body.
-1. Declare an abstract strict val, and hope subclasses will implement it as a lazy val or with an early definition. If they do not, it will appear to be uninitialized at some points during construction.
-2. Declare an abstract def, and hope subclasses will implement it as a lazy val. If they do not, it will be re-evaluated on every access.
-3. Declare a concrete lazy val which throws an exception, and hope subclasses override it. If they do not, it will... throw an exception.
+Scala 3 also [supports trait parameters](https://docs.scala-lang.org/scala3/reference/other-new-features/trait-parameters.html).
-An exception during initialization of a lazy val will cause the right hand side to be re-evaluated on the next access: see SLS 5.2.
+Note that overriding a `val` class parameter is deprecated / disallowed in Scala 3.
+Doing so in Scala 2 can lead to surprising behavior.
-Note that using multiple lazy vals creates a new risk: cycles among lazy vals can result in a stack overflow on first access.
+### Use lazy vals
-#### Use early definitions ####
abstract class A {
- val x1: String
- val x2: String = "mom"
+ lazy val x1: String
+ lazy val x2: String = "mom"
println("A: " + x1 + ", " + x2)
}
- class B extends {
- val x1: String = "hello"
- } with A {
+ class B extends A {
+ lazy val x1: String = "hello"
+
println("B: " + x1 + ", " + x2)
}
- class C extends {
- override val x2: String = "dad"
- } with B {
+ class C extends B {
+ override lazy val x2: String = "dad"
+
println("C: " + x1 + ", " + x2)
}
// scala> new C
@@ -122,45 +127,54 @@ Note that using multiple lazy vals creates a new risk: cycles among lazy vals ca
// B: hello, dad
// C: hello, dad
-Early definitions are a bit unwieldy, there are limitations as to what can appear and what can be referenced in an early definitions block, and they don't compose as well as lazy vals: but if a lazy val is undesirable, they present another option. They are specified in SLS 5.1.6.
+Note that abstract `lazy val`s are supported in Scala 3, but not in Scala 2.
+In Scala 2, you can define an abstract `val` or `def` instead.
-Note that early definitions are deprecated in Scala 2.13; they will be replaced by trait parameters in Scala 3. So, early definitions are not recommended for use if future compatibility is a concern.
+An exception during initialization of a lazy val will cause the right-hand side to be re-evaluated on the next access; see SLS 5.2.
-#### Use constant value definitions ####
- abstract class A {
- val x1: String
- val x2: String = "mom"
+Note that using multiple lazy vals incurs a new risk: cycles among lazy vals can result in a stack overflow on first access.
+When lazy vals are annotated as thread-safe in Scala 3, they risk deadlock.
- println("A: " + x1 + ", " + x2)
- }
- class B extends A {
- val x1: String = "hello"
- final val x3 = "goodbye"
+### Use a nested object
- println("B: " + x1 + ", " + x2)
- }
- class C extends B {
- override val x2: String = "dad"
+For purposes of initialization, an object that is not top-level is the same as a lazy val.
- println("C: " + x1 + ", " + x2)
+There may be reasons to prefer a lazy val, for example to specify the type of an implicit value,
+or an object where it is a companion to a class. Otherwise, the most convenient syntax may be preferred.
+
+As an example, uninitialized state in a subclass may be accessed during construction of a superclass:
+
+ class Adder {
+ var sum = 0
+ def add(x: Int): Unit = sum += x
+ add(1) // in LogAdder, the `added` set is not initialized yet
+ }
+ class LogAdder extends Adder {
+ private var added: Set[Int] = Set.empty
+ override def add(x: Int): Unit = { added += x; super.add(x) }
}
- abstract class D {
- val c: C
- val x3 = c.x3 // no exceptions!
- println("D: " + c + " but " + x3)
+
+In this case, the state can be initialized on demand by wrapping it in a local object:
+
+ class Adder {
+ var sum = 0
+ def add(x: Int): Unit = sum += x
+ add(1)
}
- class E extends D {
- val c = new C
- println(s"E: ${c.x1}, ${c.x2}, and $x3...")
+ class LogAdder extends Adder {
+ private object state {
+ var added: Set[Int] = Set.empty
+ }
+ import state._
+ override def add(x: Int): Unit = { added += x; super.add(x) }
}
- //scala> new E
- //D: null but goodbye
- //A: null, null
- //B: hello, null
- //C: hello, dad
- //E: hello, dad, and goodbye...
-Sometimes all you need from an interface is a compile-time constant.
+### Early definitions: deprecated
+
+Scala 2 supports early definitions, but they are deprecated in Scala 2.13 and unsupported in Scala 3.
+See the [migration guide](https://docs.scala-lang.org/scala3/guides/migration/incompat-dropped-features.html#early-initializer) for more information.
+
+Constant value definitions (specified in SLS 4.1 and available in Scala 2)
+and inlined definitions (in Scala 3) can work around initialization order issues
+because they can supply constant values without evaluating an instance that is not yet initialized.
-Constant values are stricter than strict and earlier than early definitions and have even more limitations,
-as they must be constants. They are specified in SLS 4.1.
diff --git a/_overviews/FAQ/stream-view-iterator.md b/_overviews/FAQ/stream-view-iterator.md
deleted file mode 100644
index 5942312a4f..0000000000
--- a/_overviews/FAQ/stream-view-iterator.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-layout: multipage-overview
-title: What is the difference between view, stream and iterator?
-overview-name: FAQ
-partof: FAQ
-
-num: 4
-permalink: /tutorials/FAQ/:title.html
----
-First, they are all _non-strict_. That has a particular mathematical meaning
-related to functions, but, basically, means they are computed on-demand instead
-of in advance.
-
-`Stream` is a lazy list indeed. In fact, in Scala, a `Stream` is a `List` whose
-`tail` is a `lazy val`. Once computed, a value stays computed and is reused.
-Or, as you say, the values are cached.
-
-An `Iterator` can only be used once because it is a _traversal pointer_ into a
-collection, and not a collection in itself. What makes it special in Scala is
-the fact that you can apply transformation such as `map` and `filter` and
-simply get a new `Iterator` which will only apply these transformations when
-you ask for the next element.
-
-Scala used to provide iterators which could be reset, but that is very hard to
-support in a general manner, and they didn't make version 2.8.0.
-
-Views are meant to be viewed much like a database view. It is a series of
-transformation which one applies to a collection to produce a "virtual"
-collection. As you said, all transformations are re-applied each time you need
-to fetch elements from it.
-
-Both `Iterator` and views have excellent memory characteristics. `Stream` is
-nice, but, in Scala, its main benefit is writing infinite sequences
-(particularly sequences recursively defined). One _can_ avoid keeping all of
-the `Stream` in memory, though, by making sure you don't keep a reference to
-its `head` (for example, by using `def` instead of `val` to define the
-`Stream`).
-
-Because of the penalties incurred by views, one should usually `force` it after
-applying the transformations, or keep it as a view if only few elements are
-expected to ever be fetched, compared to the total size of the view.
-
-This answer was originally submitted in response to [this question on Stack Overflow][1].
-
- [1]: https://stackoverflow.com/q/5159000/53013
diff --git a/_overviews/FAQ/yield.md b/_overviews/FAQ/yield.md
deleted file mode 100644
index 6b830f9396..0000000000
--- a/_overviews/FAQ/yield.md
+++ /dev/null
@@ -1,179 +0,0 @@
----
-layout: multipage-overview
-title: How does yield work?
-partof: FAQ
-num: 2
-permalink: /tutorials/FAQ/:title.html
----
-Though there's a `yield` in other languages such as Python and Ruby, Scala's
-`yield` does something very different from them. In Scala, `yield` is part
-of for comprehensions -- a generalization of Ruby and Python's list-comprehensions.
-
-Scala's "for comprehensions" are equivalent to Haskell's "do" notation, and it
-is nothing more than a syntactic sugar for composition of multiple monadic
-operations. As this statement will most likely not help anyone who needs help,
-let's try again...
-
-Translating for-comprehensions
-------------------------------
-
-Scala's "for comprehensions" are syntactic sugar for composition of multiple
-operations with `foreach`, `map`, `flatMap`, `filter` or `withFilter`.
-Scala actually translates a for-expression into calls to those methods,
-so any class providing them, or a subset of them, can be used with for comprehensions.
-
-First, let's talk about the translations. There are very simple rules:
-
-#### Example 1
-
- for(x <- c1; y <- c2; z <-c3) {...}
-
-is translated into
-
- c1.foreach(x => c2.foreach(y => c3.foreach(z => {...})))
-
-#### Example 2
-
- for(x <- c1; y <- c2; z <- c3) yield {...}
-
-is translated into
-
- c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))
-
-#### Example 3
-
- for(x <- c; if cond) yield {...}
-
-is translated into
-
- c.withFilter(x => cond).map(x => {...})
-
-with a fallback into
-
- c.filter(x => cond).map(x => {...})
-
-if method `withFilter` is not available but `filter` is.
-The next chapter has more information on this.
-
-#### Example 4
-
- for(x <- c; y = ...) yield {...}
-
-is translated into
-
- c.map(x => (x, ...)).map((x,y) => {...})
-
-#### Example 5
-
-When pattern matching is used in for-comprehensions on objects which do not
-implement `filter` or `withFilter` compilation fails with the following error
-
- value withFilter is not a member of ...
-
-That is because, for example, the following statement
-
- for((a, b) <- c) yield {...}
-
-is translated into
-
- c.withFilter{
- case (a, b) => true
- case _ => false
- }.map{case (a, b) => {...}}
-
-where the `withFilter` ensures that the pattern in the subsequent function is
-always satisfied.
-
-Clarity
-----------------------------------
-
-When you look at very simple for comprehensions, the `map`/`foreach` alternatives
-look, indeed, better. Once you start composing them, though, you can easily get
-lost in parenthesis and nesting levels. When that happens, for comprehensions
-are usually much clearer.
-
-I'll show one simple example, and intentionally omit any explanation. You can
-decide which syntax is easier to understand.
-
- l.flatMap(sl => sl.filter(el => el > 0).map(el => el.toString.length))
-
-or
-
- for{
- sl <- l
- el <- sl
- if el > 0
- } yield el.toString.length
-
-
-About withFilter, and strictness
-----------------------------------
-
-Scala 2.8 introduced a method called `withFilter`, whose main difference is
-that, instead of returning a new, filtered, collection, it filters on-demand.
-The `filter` method has its behavior defined based on the strictness of the
-collection. To understand this better, let's take a look at some Scala 2.7 with
-`List` (strict) and `Stream` (non-strict):
-
- scala> var found = false
- found: Boolean = false
-
- scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
- 1
- 3
- 7
- 9
-
- scala> found = false
- found: Boolean = false
-
- scala> Stream.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
- 1
- 3
-
-The difference happens because filter is immediately applied with `List`,
-returning a list of odds -- since `found` is `false`. Only then `foreach` is
-executed, but, by this time, changing `found` is meaningless, as `filter` has
-already executed.
-
-In the case of `Stream`, the condition is not immediately applied. Instead, as
-each element is requested by `foreach`, `filter` tests the condition, which
-enables `foreach` to influence it through `found`. Just to make it clear, here
-is the equivalent for-comprehension code:
-
- for (x <- List.range(1, 10); if x % 2 == 1 && !found)
- if (x == 5) found = true else println(x)
-
- for (x <- Stream.range(1, 10); if x % 2 == 1 && !found)
- if (x == 5) found = true else println(x)
-
-This caused many problems, because people expected the `if` to be considered
-on-demand, instead of being applied to the whole collection beforehand.
-
-Scala 2.8 introduced `withFilter`, which is _always_ non-strict, no matter the
-strictness of the collection. The following example shows `List` with both
-methods on Scala 2.8:
-
- scala> var found = false
- found: Boolean = false
-
- scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
- 1
- 3
- 7
- 9
-
- scala> found = false
- found: Boolean = false
-
- scala> List.range(1,10).withFilter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
- 1
- 3
-
-This produces the result most people expect, without changing how `filter`
-behaves. As a side note, `Range` was changed from non-strict to strict between
-Scala 2.7 and Scala 2.8.
-
-This answer was originally submitted in response to [this question on Stack Overflow][1].
-
- [1]: https://stackoverflow.com/questions/1052476/can-someone-explain-scalas-yield/1052510#1052510
diff --git a/_overviews/collections-2.13/arrays.md b/_overviews/collections-2.13/arrays.md
index 64d96a95db..32f9fb0584 100644
--- a/_overviews/collections-2.13/arrays.md
+++ b/_overviews/collections-2.13/arrays.md
@@ -14,23 +14,40 @@ permalink: /overviews/collections-2.13/:title.html
[Array](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/Array.html) is a special kind of collection in Scala. On the one hand, Scala arrays correspond one-to-one to Java arrays. That is, a Scala array `Array[Int]` is represented as a Java `int[]`, an `Array[Double]` is represented as a Java `double[]` and a `Array[String]` is represented as a Java `String[]`. But at the same time, Scala arrays offer much more than their Java analogues. First, Scala arrays can be _generic_. That is, you can have an `Array[T]`, where `T` is a type parameter or abstract type. Second, Scala arrays are compatible with Scala sequences - you can pass an `Array[T]` where a `Seq[T]` is required. Finally, Scala arrays also support all sequence operations. Here's an example of this in action:
- scala> val a1 = Array(1, 2, 3)
- a1: Array[Int] = Array(1, 2, 3)
- scala> val a2 = a1 map (_ * 3)
- a2: Array[Int] = Array(3, 6, 9)
- scala> val a3 = a2 filter (_ % 2 != 0)
- a3: Array[Int] = Array(3, 9)
- scala> a3.reverse
- res0: Array[Int] = Array(9, 3)
+{% tabs arrays_1 %}
+{% tab 'Scala 2 and 3' for=arrays_1 %}
+```scala
+scala> val a1 = Array(1, 2, 3)
+val a1: Array[Int] = Array(1, 2, 3)
+
+scala> val a2 = a1.map(_ * 3)
+val a2: Array[Int] = Array(3, 6, 9)
+
+scala> val a3 = a2.filter(_ % 2 != 0)
+val a3: Array[Int] = Array(3, 9)
+
+scala> a3.reverse
+val res0: Array[Int] = Array(9, 3)
+```
+{% endtab %}
+{% endtabs %}
Given that Scala arrays are represented just like Java arrays, how can these additional features be supported in Scala? The Scala array implementation makes systematic use of implicit conversions. In Scala, an array does not pretend to _be_ a sequence. It can't really be that because the data type representation of a native array is not a subtype of `Seq`. Instead there is an implicit "wrapping" conversion between arrays and instances of class `scala.collection.mutable.ArraySeq`, which is a subclass of `Seq`. Here you see it in action:
- scala> val seq: collection.Seq[Int] = a1
- seq: scala.collection.Seq[Int] = ArraySeq(1, 2, 3)
- scala> val a4: Array[Int] = seq.toArray
- a4: Array[Int] = Array(1, 2, 3)
- scala> a1 eq a4
- res1: Boolean = false
+{% tabs arrays_2 %}
+{% tab 'Scala 2 and 3' for=arrays_2 %}
+```scala
+scala> val seq: collection.Seq[Int] = a1
+val seq: scala.collection.Seq[Int] = ArraySeq(1, 2, 3)
+
+scala> val a4: Array[Int] = seq.toArray
+val a4: Array[Int] = Array(1, 2, 3)
+
+scala> a1 eq a4
+val res1: Boolean = false
+```
+{% endtab %}
+{% endtabs %}
The interaction above demonstrates that arrays are compatible with sequences, because there's an implicit conversion from arrays to `ArraySeq`s. To go the other way, from an `ArraySeq` to an `Array`, you can use the `toArray` method defined in `Iterable`. The last REPL line above shows that wrapping and then unwrapping with `toArray` produces a copy of the original array.
@@ -38,82 +55,188 @@ There is yet another implicit conversion that gets applied to arrays. This conve
The difference between the two implicit conversions on arrays is shown in the next REPL dialogue:
- scala> val seq: collection.Seq[Int] = a1
- seq: scala.collection.Seq[Int] = ArraySeq(1, 2, 3)
- scala> seq.reverse
- res2: scala.collection.Seq[Int] = ArraySeq(3, 2, 1)
- scala> val ops: collection.ArrayOps[Int] = a1
- ops: scala.collection.ArrayOps[Int] = scala.collection.ArrayOps@2d7df55
- scala> ops.reverse
- res3: Array[Int] = Array(3, 2, 1)
-
-You see that calling reverse on `seq`, which is an `ArraySeq`, will give again a `ArraySeq`. That's logical, because arrayseqs are `Seqs`, and calling reverse on any `Seq` will give again a `Seq`. On the other hand, calling reverse on the ops value of class `ArrayOps` will give an `Array`, not a `Seq`.
-
-The `ArrayOps` example above was quite artificial, intended only to show the difference to `ArraySeq`. Normally, you'd never define a value of class `ArrayOps`. You'd just call a `Seq` method on an array:
+{% tabs arrays_3 %}
+{% tab 'Scala 2 and 3' for=arrays_3 %}
+```scala
+scala> val seq: collection.Seq[Int] = a1
+val seq: scala.collection.Seq[Int] = ArraySeq(1, 2, 3)
- scala> a1.reverse
- res4: Array[Int] = Array(3, 2, 1)
+scala> seq.reverse
+val res2: scala.collection.Seq[Int] = ArraySeq(3, 2, 1)
-The `ArrayOps` object gets inserted automatically by the implicit conversion. So the line above is equivalent to
+scala> val ops: collection.ArrayOps[Int] = a1
+val ops: scala.collection.ArrayOps[Int] = scala.collection.ArrayOps@2d7df55
- scala> intArrayOps(a1).reverse
- res5: Array[Int] = Array(3, 2, 1)
+scala> ops.reverse
+val res3: Array[Int] = Array(3, 2, 1)
+```
+{% endtab %}
+{% endtabs %}
-where `intArrayOps` is the implicit conversion that was inserted previously. This raises the question how the compiler picked `intArrayOps` over the other implicit conversion to `ArraySeq` in the line above. After all, both conversions map an array to a type that supports a reverse method, which is what the input specified. The answer to that question is that the two implicit conversions are prioritized. The `ArrayOps` conversion has a higher priority than the `ArraySeq` conversion. The first is defined in the `Predef` object whereas the second is defined in a class `scala.LowPriorityImplicits`, which is inherited by `Predef`. Implicits in subclasses and subobjects take precedence over implicits in base classes. So if both conversions are applicable, the one in `Predef` is chosen. A very similar scheme works for strings.
+You see that calling reverse on `seq`, which is an `ArraySeq`, will give again a `ArraySeq`. That's logical, because arrayseqs are `Seqs`, and calling reverse on any `Seq` will give again a `Seq`. On the other hand, calling reverse on the ops value of class `ArrayOps` will give an `Array`, not a `Seq`.
-So now you know how arrays can be compatible with sequences and how they can support all sequence operations. What about genericity? In Java you cannot write a `T[]` where `T` is a type parameter. How then is Scala's `Array[T]` represented? In fact a generic array like `Array[T]` could be at run-time any of Java's eight primitive array types `byte[]`, `short[]`, `char[]`, `int[]`, `long[]`, `float[]`, `double[]`, `boolean[]`, or it could be an array of objects. The only common run-time type encompassing all of these types is `AnyRef` (or, equivalently `java.lang.Object`), so that's the type to which the Scala compiler maps `Array[T]`. At run-time, when an element of an array of type `Array[T]` is accessed or updated there is a sequence of type tests that determine the actual array type, followed by the correct array operation on the Java array. These type tests slow down array operations somewhat. You can expect accesses to generic arrays to be three to four times slower than accesses to primitive or object arrays. This means that if you need maximal performance, you should prefer concrete over generic arrays. Representing the generic array type is not enough, however, there must also be a way to create generic arrays. This is an even harder problem, which requires a little bit of help from you. To illustrate the problem, consider the following attempt to write a generic method that creates an array.
+The `ArrayOps` example above was quite artificial, intended only to show the difference to `ArraySeq`. Normally, you'd never define a value of class `ArrayOps`. You'd just call a `Seq` method on an array:
- // this is wrong!
- def evenElems[T](xs: Vector[T]): Array[T] = {
- val arr = new Array[T]((xs.length + 1) / 2)
- for (i <- 0 until xs.length by 2)
- arr(i / 2) = xs(i)
- arr
- }
+{% tabs arrays_4 %}
+{% tab 'Scala 2 and 3' for=arrays_4 %}
+```scala
+scala> a1.reverse
+val res4: Array[Int] = Array(3, 2, 1)
+```
+{% endtab %}
+{% endtabs %}
-The `evenElems` method returns a new array that consist of all elements of the argument vector `xs` which are at even positions in the vector. The first line of the body of `evenElems` creates the result array, which has the same element type as the argument. So depending on the actual type parameter for `T`, this could be an `Array[Int]`, or an `Array[Boolean]`, or an array of some of the other primitive types in Java, or an array of some reference type. But these types have all different runtime representations, so how is the Scala runtime going to pick the correct one? In fact, it can't do that based on the information it is given, because the actual type that corresponds to the type parameter `T` is erased at runtime. That's why you will get the following error message if you compile the code above:
+The `ArrayOps` object gets inserted automatically by the implicit conversion. So the line above is equivalent to
- error: cannot find class manifest for element type T
- val arr = new Array[T]((arr.length + 1) / 2)
- ^
+{% tabs arrays_5 %}
+{% tab 'Scala 2 and 3' for=arrays_5 %}
+```scala
+scala> intArrayOps(a1).reverse
+val res5: Array[Int] = Array(3, 2, 1)
+```
+{% endtab %}
+{% endtabs %}
+
+where `intArrayOps` is the implicit conversion that was inserted previously. This raises the question of how the compiler picked `intArrayOps` over the other implicit conversion to `ArraySeq` in the line above. After all, both conversions map an array to a type that supports a reverse method, which is what the input specified. The answer to that question is that the two implicit conversions are prioritized. The `ArrayOps` conversion has a higher priority than the `ArraySeq` conversion. The first is defined in the `Predef` object whereas the second is defined in a class `scala.LowPriorityImplicits`, which is inherited by `Predef`. Implicits in subclasses and subobjects take precedence over implicits in base classes. So if both conversions are applicable, the one in `Predef` is chosen. A very similar scheme works for strings.
+
+So now you know how arrays can be compatible with sequences and how they can support all sequence operations. What about genericity? In Java, you cannot write a `T[]` where `T` is a type parameter. How then is Scala's `Array[T]` represented? In fact a generic array like `Array[T]` could be at run-time any of Java's eight primitive array types `byte[]`, `short[]`, `char[]`, `int[]`, `long[]`, `float[]`, `double[]`, `boolean[]`, or it could be an array of objects. The only common run-time type encompassing all of these types is `AnyRef` (or, equivalently `java.lang.Object`), so that's the type to which the Scala compiler maps `Array[T]`. At run-time, when an element of an array of type `Array[T]` is accessed or updated there is a sequence of type tests that determine the actual array type, followed by the correct array operation on the Java array. These type tests slow down array operations somewhat. You can expect accesses to generic arrays to be three to four times slower than accesses to primitive or object arrays. This means that if you need maximal performance, you should prefer concrete to generic arrays. Representing the generic array type is not enough, however, there must also be a way to create generic arrays. This is an even harder problem, which requires a little of help from you. To illustrate the issue, consider the following attempt to write a generic method that creates an array.
+
+{% tabs arrays_6 class=tabs-scala-version %}
+{% tab 'Scala 2' for=arrays_6 %}
+```scala mdoc:fail
+// this is wrong!
+def evenElems[T](xs: Vector[T]): Array[T] = {
+ val arr = new Array[T]((xs.length + 1) / 2)
+ for (i <- 0 until xs.length by 2)
+ arr(i / 2) = xs(i)
+ arr
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=arrays_6 %}
+```scala
+// this is wrong!
+def evenElems[T](xs: Vector[T]): Array[T] =
+ val arr = new Array[T]((xs.length + 1) / 2)
+ for i <- 0 until xs.length by 2 do
+ arr(i / 2) = xs(i)
+ arr
+```
+{% endtab %}
+{% endtabs %}
+
+The `evenElems` method returns a new array that consist of all elements of the argument vector `xs` which are at even positions in the vector. The first line of the body of `evenElems` creates the result array, which has the same element type as the argument. So depending on the actual type parameter for `T`, this could be an `Array[Int]`, or an `Array[Boolean]`, or an array of some other primitive types in Java, or an array of some reference type. But these types have all different runtime representations, so how is the Scala runtime going to pick the correct one? In fact, it can't do that based on the information it is given, because the actual type that corresponds to the type parameter `T` is erased at runtime. That's why you will get the following error message if you compile the code above:
+
+{% tabs arrays_7 class=tabs-scala-version %}
+{% tab 'Scala 2' for=arrays_7 %}
+```scala
+error: cannot find class manifest for element type T
+ val arr = new Array[T]((arr.length + 1) / 2)
+ ^
+```
+{% endtab %}
+{% tab 'Scala 3' for=arrays_7 %}
+```scala
+-- Error: ----------------------------------------------------------------------
+3 | val arr = new Array[T]((xs.length + 1) / 2)
+ | ^
+ | No ClassTag available for T
+```
+{% endtab %}
+{% endtabs %}
What's required here is that you help the compiler out by providing some runtime hint what the actual type parameter of `evenElems` is. This runtime hint takes the form of a class manifest of type `scala.reflect.ClassTag`. A class manifest is a type descriptor object which describes what the top-level class of a type is. Alternatively to class manifests there are also full manifests of type `scala.reflect.Manifest`, which describe all aspects of a type. But for array creation, only class manifests are needed.
The Scala compiler will construct class manifests automatically if you instruct it to do so. "Instructing" means that you demand a class manifest as an implicit parameter, like this:
- def evenElems[T](xs: Vector[T])(implicit m: ClassTag[T]): Array[T] = ...
+{% tabs arrays_8 class=tabs-scala-version %}
+{% tab 'Scala 2' for=arrays_8 %}
+```scala
+def evenElems[T](xs: Vector[T])(implicit m: ClassTag[T]): Array[T] = ...
+```
+{% endtab %}
+{% tab 'Scala 3' for=arrays_8 %}
+```scala
+def evenElems[T](xs: Vector[T])(using m: ClassTag[T]): Array[T] = ...
+```
+{% endtab %}
+{% endtabs %}
Using an alternative and shorter syntax, you can also demand that the type comes with a class manifest by using a context bound. This means following the type with a colon and the class name `ClassTag`, like this:
- import scala.reflect.ClassTag
- // this works
- def evenElems[T: ClassTag](xs: Vector[T]): Array[T] = {
- val arr = new Array[T]((xs.length + 1) / 2)
- for (i <- 0 until xs.length by 2)
- arr(i / 2) = xs(i)
- arr
- }
+{% tabs arrays_9 class=tabs-scala-version %}
+{% tab 'Scala 2' for=arrays_9 %}
+```scala
+import scala.reflect.ClassTag
+// this works
+def evenElems[T: ClassTag](xs: Vector[T]): Array[T] = {
+ val arr = new Array[T]((xs.length + 1) / 2)
+ for (i <- 0 until xs.length by 2)
+ arr(i / 2) = xs(i)
+ arr
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=arrays_9 %}
+```scala
+import scala.reflect.ClassTag
+// this works
+def evenElems[T: ClassTag](xs: Vector[T]): Array[T] =
+ val arr = new Array[T]((xs.length + 1) / 2)
+ for i <- 0 until xs.length by 2 do
+ arr(i / 2) = xs(i)
+ arr
+```
+{% endtab %}
+{% endtabs %}
The two revised versions of `evenElems` mean exactly the same. What happens in either case is that when the `Array[T]` is constructed, the compiler will look for a class manifest for the type parameter T, that is, it will look for an implicit value of type `ClassTag[T]`. If such a value is found, the manifest is used to construct the right kind of array. Otherwise, you'll see an error message like the one above.
Here is some REPL interaction that uses the `evenElems` method.
- scala> evenElems(Vector(1, 2, 3, 4, 5))
- res6: Array[Int] = Array(1, 3, 5)
- scala> evenElems(Vector("this", "is", "a", "test", "run"))
- res7: Array[java.lang.String] = Array(this, a, run)
+{% tabs arrays_10 %}
+{% tab 'Scala 2 and 3' for=arrays_10 %}
+```scala
+scala> evenElems(Vector(1, 2, 3, 4, 5))
+val res6: Array[Int] = Array(1, 3, 5)
+
+scala> evenElems(Vector("this", "is", "a", "test", "run"))
+val res7: Array[java.lang.String] = Array(this, a, run)
+```
+{% endtab %}
+{% endtabs %}
In both cases, the Scala compiler automatically constructed a class manifest for the element type (first, `Int`, then `String`) and passed it to the implicit parameter of the `evenElems` method. The compiler can do that for all concrete types, but not if the argument is itself another type parameter without its class manifest. For instance, the following fails:
- scala> def wrap[U](xs: Vector[U]) = evenElems(xs)
- :6: error: No ClassTag available for U.
- def wrap[U](xs: Vector[U]) = evenElems(xs)
- ^
+{% tabs arrays_11 class=tabs-scala-version %}
+{% tab 'Scala 2' for=arrays_11 %}
+```scala
+scala> def wrap[U](xs: Vector[U]) = evenElems(xs)
+:6: error: No ClassTag available for U.
+ def wrap[U](xs: Vector[U]) = evenElems(xs)
+ ^
+```
+{% endtab %}
+{% tab 'Scala 3' for=arrays_11 %}
+```scala
+-- Error: ----------------------------------------------------------------------
+6 |def wrap[U](xs: Vector[U]) = evenElems(xs)
+ | ^
+ | No ClassTag available for U
+```
+{% endtab %}
+{% endtabs %}
What happened here is that the `evenElems` demands a class manifest for the type parameter `U`, but none was found. The solution in this case is, of course, to demand another implicit class manifest for `U`. So the following works:
- scala> def wrap[U: ClassTag](xs: Vector[U]) = evenElems(xs)
- wrap: [U](xs: Vector[U])(implicit evidence$1: scala.reflect.ClassTag[U])Array[U]
+{% tabs arrays_12 %}
+{% tab 'Scala 2 and 3' for=arrays_12 %}
+```scala
+scala> def wrap[U: ClassTag](xs: Vector[U]) = evenElems(xs)
+def wrap[U](xs: Vector[U])(implicit evidence$1: scala.reflect.ClassTag[U]): Array[U]
+```
+{% endtab %}
+{% endtabs %}
This example also shows that the context bound in the definition of `U` is just a shorthand for an implicit parameter named here `evidence$1` of type `ClassTag[U]`.
diff --git a/_overviews/collections-2.13/concrete-immutable-collection-classes.md b/_overviews/collections-2.13/concrete-immutable-collection-classes.md
index 166f3e280d..f4d746de58 100644
--- a/_overviews/collections-2.13/concrete-immutable-collection-classes.md
+++ b/_overviews/collections-2.13/concrete-immutable-collection-classes.md
@@ -24,25 +24,42 @@ A [LazyList](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/colle
Whereas lists are constructed with the `::` operator, lazy lists are constructed with the similar-looking `#::`. Here is a simple example of a lazy list containing the integers 1, 2, and 3:
- scala> val lazyList = 1 #:: 2 #:: 3 #:: LazyList.empty
- lazyList: scala.collection.immutable.LazyList[Int] = LazyList()
+{% tabs LazyList_1 %}
+{% tab 'Scala 2 and 3' for=LazyList_1 %}
+~~~scala
+scala> val lazyList = 1 #:: 2 #:: 3 #:: LazyList.empty
+lazyList: scala.collection.immutable.LazyList[Int] = LazyList()
+~~~
+{% endtab %}
+{% endtabs %}
The head of this lazy list is 1, and the tail of it has 2 and 3. None of the elements are printed here, though, because the list
hasn’t been computed yet! Lazy lists are specified to compute lazily, and the `toString` method of a lazy list is careful not to force any extra evaluation.
Below is a more complex example. It computes a lazy list that contains a Fibonacci sequence starting with the given two numbers. A Fibonacci sequence is one where each element is the sum of the previous two elements in the series.
-
- scala> def fibFrom(a: Int, b: Int): LazyList[Int] = a #:: fibFrom(b, a + b)
- fibFrom: (a: Int,b: Int)LazyList[Int]
+{% tabs LazyList_2 %}
+{% tab 'Scala 2 and 3' for=LazyList_2 %}
+~~~scala
+scala> def fibFrom(a: Int, b: Int): LazyList[Int] = a #:: fibFrom(b, a + b)
+fibFrom: (a: Int,b: Int)LazyList[Int]
+~~~
+{% endtab %}
+{% endtabs %}
This function is deceptively simple. The first element of the sequence is clearly `a`, and the rest of the sequence is the Fibonacci sequence starting with `b` followed by `a + b`. The tricky part is computing this sequence without causing an infinite recursion. If the function used `::` instead of `#::`, then every call to the function would result in another call, thus causing an infinite recursion. Since it uses `#::`, though, the right-hand side is not evaluated until it is requested.
Here are the first few elements of the Fibonacci sequence starting with two ones:
- scala> val fibs = fibFrom(1, 1).take(7)
- fibs: scala.collection.immutable.LazyList[Int] = LazyList()
- scala> fibs.toList
- res9: List[Int] = List(1, 1, 2, 3, 5, 8, 13)
+{% tabs LazyList_3 %}
+{% tab 'Scala 2 and 3' for=LazyList_3 %}
+~~~scala
+scala> val fibs = fibFrom(1, 1).take(7)
+fibs: scala.collection.immutable.LazyList[Int] = LazyList()
+scala> fibs.toList
+res9: List[Int] = List(1, 1, 2, 3, 5, 8, 13)
+~~~
+{% endtab %}
+{% endtabs %}
## Immutable ArraySeqs
@@ -56,7 +73,9 @@ and thus they can be much more convenient to write.
ArraySeqs are built and updated just like any other sequence.
-~~~
+{% tabs ArraySeq_1 %}
+{% tab 'Scala 2 and 3' for=ArraySeq_1 %}
+~~~scala
scala> val arr = scala.collection.immutable.ArraySeq(1, 2, 3)
arr: scala.collection.immutable.ArraySeq[Int] = ArraySeq(1, 2, 3)
scala> val arr2 = arr :+ 4
@@ -64,43 +83,55 @@ arr2: scala.collection.immutable.ArraySeq[Int] = ArraySeq(1, 2, 3, 4)
scala> arr2(0)
res22: Int = 1
~~~
+{% endtab %}
+{% endtabs %}
ArraySeqs are immutable, so you cannot change an element in place. However, the `updated`, `appended` and `prepended`
operations create new ArraySeqs that differ from a given ArraySeq only in a single element:
-~~~
+{% tabs ArraySeq_2 %}
+{% tab 'Scala 2 and 3' for=ArraySeq_2 %}
+~~~scala
scala> arr.updated(2, 4)
res26: scala.collection.immutable.ArraySeq[Int] = ArraySeq(1, 2, 4)
scala> arr
res27: scala.collection.immutable.ArraySeq[Int] = ArraySeq(1, 2, 3)
~~~
+{% endtab %}
+{% endtabs %}
As the last line above shows, a call to `updated` has no effect on the original ArraySeq `arr`.
-ArraySeqs store their elements in a private [Array](arrays.html). This is a compact representation that supports fast
+ArraySeqs store their elements in a private [Array]({% link _overviews/collections-2.13/arrays.md %}). This is a compact representation that supports fast
indexed access, but updating or adding one element is linear since it requires creating another array and copying all
the original array’s elements.
## Vectors
We have seen in the previous sections that `List` and `ArraySeq` are efficient data structures in some specific
-use cases but they are also inefficient in other use cases: for instance, prepending an element is constant for `List`,
+use cases, but they are also inefficient in other use cases: for instance, prepending an element is constant for `List`,
but linear for `ArraySeq`, and, conversely, indexed access is constant for `ArraySeq` but linear for `List`.
[Vector](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Vector.html) is a collection type that provides good performance for all its operations. Vectors allow accessing any element of the sequence in "effectively" constant time. It's a larger constant than for access to the head of a List or for reading an element of an ArraySeq, but it's a constant nonetheless. As a result, algorithms using vectors do not have to be careful about accessing just the head of the sequence. They can access and modify elements at arbitrary locations, and thus they can be much more convenient to write.
Vectors are built and modified just like any other sequence.
- scala> val vec = scala.collection.immutable.Vector.empty
- vec: scala.collection.immutable.Vector[Nothing] = Vector()
- scala> val vec2 = vec :+ 1 :+ 2
- vec2: scala.collection.immutable.Vector[Int] = Vector(1, 2)
- scala> val vec3 = 100 +: vec2
- vec3: scala.collection.immutable.Vector[Int] = Vector(100, 1, 2)
- scala> vec3(0)
- res1: Int = 100
+{% tabs Vector_1 %}
+{% tab 'Scala 2 and 3' for=Vector_1 %}
+~~~scala
+scala> val vec = scala.collection.immutable.Vector.empty
+vec: scala.collection.immutable.Vector[Nothing] = Vector()
+scala> val vec2 = vec :+ 1 :+ 2
+vec2: scala.collection.immutable.Vector[Int] = Vector(1, 2)
+scala> val vec3 = 100 +: vec2
+vec3: scala.collection.immutable.Vector[Int] = Vector(100, 1, 2)
+scala> vec3(0)
+res1: Int = 100
+~~~
+{% endtab %}
+{% endtabs %}
-Vectors are represented as trees with a high branching factor. (The branching factor of a tree or a graph is the number of children at each node.) The details of how this is accomplished [changed](https://github.com/scala/scala/pull/8534) in Scala 2.13.2, but the basic idea remains the same, as follows.
+Vectors are represented as trees with a high branching factor (The branching factor of a tree or a graph is the number of children at each node). The details of how this is accomplished [changed](https://github.com/scala/scala/pull/8534) in Scala 2.13.2, but the basic idea remains the same, as follows.
Every tree node contains up to 32 elements of the vector or contains up to 32 other tree nodes. Vectors with up to 32 elements can be represented in a single node. Vectors with up to `32 * 32 = 1024` elements can be represented with a single indirection. Two hops from the root of the tree to the final element node are sufficient for vectors with up to 215 elements, three hops for vectors with 220, four hops for vectors with 225 elements and five hops for vectors with up to 230 elements. So for all vectors of reasonable size, an element selection involves up to 5 primitive array selections. This is what we meant when we wrote that element access is "effectively constant time".
@@ -108,8 +139,14 @@ Like selection, functional vector updates are also "effectively constant time".
Because vectors strike a good balance between fast random selections and fast random functional updates, they are currently the default implementation of immutable indexed sequences:
- scala> collection.immutable.IndexedSeq(1, 2, 3)
- res2: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3)
+{% tabs Vector_2 %}
+{% tab 'Scala 2 and 3' for=Vector_2 %}
+~~~scala
+scala> collection.immutable.IndexedSeq(1, 2, 3)
+res2: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3)
+~~~
+{% endtab %}
+{% endtabs %}
## Immutable Queues
@@ -117,25 +154,49 @@ A [Queue](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collecti
Here's how you can create an empty immutable queue:
- scala> val empty = scala.collection.immutable.Queue[Int]()
- empty: scala.collection.immutable.Queue[Int] = Queue()
+{% tabs Queue_1 %}
+{% tab 'Scala 2 and 3' for=Queue_1 %}
+~~~scala
+scala> val empty = scala.collection.immutable.Queue[Int]()
+empty: scala.collection.immutable.Queue[Int] = Queue()
+~~~
+{% endtab %}
+{% endtabs %}
You can append an element to an immutable queue with `enqueue`:
- scala> val has1 = empty.enqueue(1)
- has1: scala.collection.immutable.Queue[Int] = Queue(1)
+{% tabs Queue_2 %}
+{% tab 'Scala 2 and 3' for=Queue_2 %}
+~~~scala
+scala> val has1 = empty.enqueue(1)
+has1: scala.collection.immutable.Queue[Int] = Queue(1)
+~~~
+{% endtab %}
+{% endtabs %}
To append multiple elements to a queue, call `enqueueAll` with a collection as its argument:
- scala> val has123 = has1.enqueueAll(List(2, 3))
- has123: scala.collection.immutable.Queue[Int]
- = Queue(1, 2, 3)
+{% tabs Queue_3 %}
+{% tab 'Scala 2 and 3' for=Queue_3 %}
+~~~scala
+scala> val has123 = has1.enqueueAll(List(2, 3))
+has123: scala.collection.immutable.Queue[Int]
+ = Queue(1, 2, 3)
+~~~
+{% endtab %}
+{% endtabs %}
To remove an element from the head of the queue, you use `dequeue`:
- scala> val (element, has23) = has123.dequeue
- element: Int = 1
- has23: scala.collection.immutable.Queue[Int] = Queue(2, 3)
+{% tabs Queue_4 %}
+{% tab 'Scala 2 and 3' for=Queue_4 %}
+~~~scala
+scala> val (element, has23) = has123.dequeue
+element: Int = 1
+has23: scala.collection.immutable.Queue[Int] = Queue(2, 3)
+~~~
+{% endtab %}
+{% endtabs %}
Note that `dequeue` returns a pair consisting of the element removed and the rest of the queue.
@@ -143,15 +204,27 @@ Note that `dequeue` returns a pair consisting of the element removed and the res
A [Range](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Range.html) is an ordered sequence of integers that are equally spaced apart. For example, "1, 2, 3," is a range, as is "5, 8, 11, 14." To create a range in Scala, use the predefined methods `to` and `by`.
- scala> 1 to 3
- res2: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3)
- scala> 5 to 14 by 3
- res3: scala.collection.immutable.Range = Range(5, 8, 11, 14)
+{% tabs Range_1 %}
+{% tab 'Scala 2 and 3' for=Range_1 %}
+~~~scala
+scala> 1 to 3
+res2: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3)
+scala> 5 to 14 by 3
+res3: scala.collection.immutable.Range = Range(5, 8, 11, 14)
+~~~
+{% endtab %}
+{% endtabs %}
If you want to create a range that is exclusive of its upper limit, then use the convenience method `until` instead of `to`:
- scala> 1 until 3
- res2: scala.collection.immutable.Range = Range(1, 2)
+{% tabs Range_2 %}
+{% tab 'Scala 2 and 3' for=Range_2 %}
+~~~scala
+scala> 1 until 3
+res2: scala.collection.immutable.Range = Range(1, 2)
+~~~
+{% endtab %}
+{% endtabs %}
Ranges are represented in constant space, because they can be defined by just three numbers: their start, their end, and the stepping value. Because of this representation, most operations on ranges are extremely fast.
@@ -159,7 +232,7 @@ Ranges are represented in constant space, because they can be defined by just th
Hash tries are a standard way to implement immutable sets and maps efficiently. [Compressed Hash-Array Mapped Prefix-trees](https://github.com/msteindorfer/oopsla15-artifact/) are a design for hash tries on the JVM which improves locality and makes sure the trees remain in a canonical and compact representation. They are supported by class [immutable.HashMap](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/HashMap.html). Their representation is similar to vectors in that they are also trees where every node has 32 elements or 32 subtrees. But the selection of these keys is now done based on hash code. For instance, to find a given key in a map, one first takes the hash code of the key. Then, the lowest 5 bits of the hash code are used to select the first subtree, followed by the next 5 bits and so on. The selection stops once all elements stored in a node have hash codes that differ from each other in the bits that are selected up to this level.
-Hash tries strike a nice balance between reasonably fast lookups and reasonably efficient functional insertions (`+`) and deletions (`-`). That's why they underly Scala's default implementations of immutable maps and sets. In fact, Scala has a further optimization for immutable sets and maps that contain less than five elements. Sets and maps with one to four elements are stored as single objects that just contain the elements (or key/value pairs in the case of a map) as fields. The empty immutable set and the empty immutable map is in each case a single object - there's no need to duplicate storage for those because an empty immutable set or map will always stay empty.
+Hash tries strike a nice balance between reasonably fast lookups and reasonably efficient functional insertions (`+`) and deletions (`-`). That's why they underlie Scala's default implementations of immutable maps and sets. In fact, Scala has a further optimization for immutable sets and maps that contain less than five elements. Sets and maps with one to four elements are stored as single objects that just contain the elements (or key/value pairs in the case of a map) as fields. The empty immutable set and the empty immutable map is in each case a single object - there's no need to duplicate storage for those because an empty immutable set or map will always stay empty.
## Red-Black Trees
@@ -167,11 +240,16 @@ Red-black trees are a form of balanced binary tree where some nodes are designat
Scala provides implementations of immutable sets and maps that use a red-black tree internally. Access them under the names [TreeSet](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/TreeSet.html) and [TreeMap](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/TreeMap.html).
-
- scala> scala.collection.immutable.TreeSet.empty[Int]
- res11: scala.collection.immutable.TreeSet[Int] = TreeSet()
- scala> res11 + 1 + 3 + 3
- res12: scala.collection.immutable.TreeSet[Int] = TreeSet(1, 3)
+{% tabs Red-Black_1 %}
+{% tab 'Scala 2 and 3' for=Red-Black_1 %}
+~~~scala
+scala> scala.collection.immutable.TreeSet.empty[Int]
+res11: scala.collection.immutable.TreeSet[Int] = TreeSet()
+scala> res11 + 1 + 3 + 3
+res12: scala.collection.immutable.TreeSet[Int] = TreeSet(1, 3)
+~~~
+{% endtab %}
+{% endtabs %}
Red-black trees are the standard implementation of `SortedSet` in Scala, because they provide an efficient iterator that returns all elements in sorted order.
@@ -183,14 +261,20 @@ Internally, bit sets use an array of 64-bit `Long`s. The first `Long` in the arr
Operations on bit sets are very fast. Testing for inclusion takes constant time. Adding an item to the set takes time proportional to the number of `Long`s in the bit set's array, which is typically a small number. Here are some simple examples of the use of a bit set:
- scala> val bits = scala.collection.immutable.BitSet.empty
- bits: scala.collection.immutable.BitSet = BitSet()
- scala> val moreBits = bits + 3 + 4 + 4
- moreBits: scala.collection.immutable.BitSet = BitSet(3, 4)
- scala> moreBits(3)
- res26: Boolean = true
- scala> moreBits(0)
- res27: Boolean = false
+{% tabs BitSet_1 %}
+{% tab 'Scala 2 and 3' for=BitSet_1 %}
+~~~scala
+scala> val bits = scala.collection.immutable.BitSet.empty
+bits: scala.collection.immutable.BitSet = BitSet()
+scala> val moreBits = bits + 3 + 4 + 4
+moreBits: scala.collection.immutable.BitSet = BitSet(3, 4)
+scala> moreBits(3)
+res26: Boolean = true
+scala> moreBits(0)
+res27: Boolean = false
+~~~
+{% endtab %}
+{% endtabs %}
## VectorMaps
@@ -198,7 +282,9 @@ A [VectorMap](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/coll
a map using both a `Vector` of keys and a `HashMap`. It provides an iterator that returns all the entries in their
insertion order.
-~~~
+{% tabs VectorMap_1 %}
+{% tab 'Scala 2 and 3' for=VectorMap_1 %}
+~~~scala
scala> val vm = scala.collection.immutable.VectorMap.empty[Int, String]
vm: scala.collection.immutable.VectorMap[Int,String] =
VectorMap()
@@ -211,6 +297,8 @@ vm2: scala.collection.immutable.VectorMap[Int,String] =
scala> vm2 == Map(2 -> "two", 1 -> "one")
res29: Boolean = true
~~~
+{% endtab %}
+{% endtabs %}
The first lines show that the content of the `VectorMap` keeps the insertion order, and the last line
shows that `VectorMap`s are comparable with other `Map`s and that this comparison does not take the
@@ -220,8 +308,14 @@ order of elements into account.
A [ListMap](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/ListMap.html) represents a map as a linked list of key-value pairs. In general, operations on a list map might have to iterate through the entire list. Thus, operations on a list map take time linear in the size of the map. In fact there is little usage for list maps in Scala because standard immutable maps are almost always faster. The only possible exception to this is if the map is for some reason constructed in such a way that the first elements in the list are selected much more often than the other elements.
- scala> val map = scala.collection.immutable.ListMap(1->"one", 2->"two")
- map: scala.collection.immutable.ListMap[Int,java.lang.String] =
- Map(1 -> one, 2 -> two)
- scala> map(2)
- res30: String = "two"
+{% tabs ListMap_1 %}
+{% tab 'Scala 2 and 3' for=ListMap_1 %}
+~~~scala
+scala> val map = scala.collection.immutable.ListMap(1->"one", 2->"two")
+map: scala.collection.immutable.ListMap[Int,java.lang.String] =
+ Map(1 -> one, 2 -> two)
+scala> map(2)
+res30: String = "two"
+~~~
+{% endtab %}
+{% endtabs %}
diff --git a/_overviews/collections-2.13/concrete-mutable-collection-classes.md b/_overviews/collections-2.13/concrete-mutable-collection-classes.md
index 883d1978ca..0de0bb1996 100644
--- a/_overviews/collections-2.13/concrete-mutable-collection-classes.md
+++ b/_overviews/collections-2.13/concrete-mutable-collection-classes.md
@@ -16,42 +16,72 @@ You've now seen the most commonly used immutable collection classes that Scala p
## Array Buffers
-An [ArrayBuffer](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/ArrayBuffer.html) buffer holds an array and a size. Most operations on an array buffer have the same speed as for an array, because the operations simply access and modify the underlying array. Additionally, array buffers can have data efficiently added to the end. Appending an item to an array buffer takes amortized constant time. Thus, array buffers are useful for efficiently building up a large collection whenever the new items are always added to the end.
-
- scala> val buf = scala.collection.mutable.ArrayBuffer.empty[Int]
- buf: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
- scala> buf += 1
- res32: buf.type = ArrayBuffer(1)
- scala> buf += 10
- res33: buf.type = ArrayBuffer(1, 10)
- scala> buf.toArray
- res34: Array[Int] = Array(1, 10)
+An [ArrayBuffer](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/ArrayBuffer.html) holds an array and a size. Most operations on an array buffer have the same speed as for an array, because the operations simply access and modify the underlying array. Additionally, array buffers can have data efficiently added to the end. Appending an item to an array buffer takes amortized constant time. Thus, array buffers are useful for efficiently building up a large collection whenever the new items are always added to the end.
+
+{% tabs ArrayBuffer_1 %}
+{% tab 'Scala 2 and 3' for=ArrayBuffer_1 %}
+~~~scala
+scala> val buf = scala.collection.mutable.ArrayBuffer.empty[Int]
+buf: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
+scala> buf += 1
+res32: buf.type = ArrayBuffer(1)
+scala> buf += 10
+res33: buf.type = ArrayBuffer(1, 10)
+scala> buf.toArray
+res34: Array[Int] = Array(1, 10)
+~~~
+{% endtab %}
+{% endtabs %}
## List Buffers
A [ListBuffer](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/ListBuffer.html) is like an array buffer except that it uses a linked list internally instead of an array. If you plan to convert the buffer to a list once it is built up, use a list buffer instead of an array buffer.
- scala> val buf = scala.collection.mutable.ListBuffer.empty[Int]
- buf: scala.collection.mutable.ListBuffer[Int] = ListBuffer()
- scala> buf += 1
- res35: buf.type = ListBuffer(1)
- scala> buf += 10
- res36: buf.type = ListBuffer(1, 10)
- scala> buf.toList
- res37: List[Int] = List(1, 10)
+{% tabs ListBuffer_1 %}
+{% tab 'Scala 2 and 3' for=ListBuffer_1 %}
+~~~scala
+scala> val buf = scala.collection.mutable.ListBuffer.empty[Int]
+buf: scala.collection.mutable.ListBuffer[Int] = ListBuffer()
+scala> buf += 1
+res35: buf.type = ListBuffer(1)
+scala> buf += 10
+res36: buf.type = ListBuffer(1, 10)
+scala> buf.to(List)
+res37: List[Int] = List(1, 10)
+~~~
+{% endtab %}
+{% endtabs %}
## StringBuilders
Just like an array buffer is useful for building arrays, and a list buffer is useful for building lists, a [StringBuilder](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/StringBuilder.html) is useful for building strings. String builders are so commonly used that they are already imported into the default namespace. Create them with a simple `new StringBuilder`, like this:
- scala> val buf = new StringBuilder
- buf: StringBuilder =
- scala> buf += 'a'
- res38: buf.type = a
- scala> buf ++= "bcdef"
- res39: buf.type = abcdef
- scala> buf.toString
- res41: String = abcdef
+{% tabs StringBuilders_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=StringBuilders_1 %}
+~~~scala
+scala> val buf = new StringBuilder
+buf: StringBuilder =
+scala> buf += 'a'
+res38: buf.type = a
+scala> buf ++= "bcdef"
+res39: buf.type = abcdef
+scala> buf.toString
+res41: String = abcdef
+~~~
+{% endtab %}
+{% tab 'Scala 3' for=StringBuilders_1 %}
+~~~scala
+scala> val buf = StringBuilder()
+buf: StringBuilder =
+scala> buf += 'a'
+res38: buf.type = a
+scala> buf ++= "bcdef"
+res39: buf.type = abcdef
+scala> buf.toString
+res41: String = abcdef
+~~~
+{% endtab %}
+{% endtabs %}
## ArrayDeque
@@ -66,48 +96,98 @@ an `ArrayBuffer`.
Scala provides mutable queues in addition to immutable ones. You use a `mQueue` similarly to how you use an immutable one, but instead of `enqueue`, you use the `+=` and `++=` operators to append. Also, on a mutable queue, the `dequeue` method will just remove the head element from the queue and return it. Here's an example:
- scala> val queue = new scala.collection.mutable.Queue[String]
- queue: scala.collection.mutable.Queue[String] = Queue()
- scala> queue += "a"
- res10: queue.type = Queue(a)
- scala> queue ++= List("b", "c")
- res11: queue.type = Queue(a, b, c)
- scala> queue
- res12: scala.collection.mutable.Queue[String] = Queue(a, b, c)
- scala> queue.dequeue
- res13: String = a
- scala> queue
- res14: scala.collection.mutable.Queue[String] = Queue(b, c)
+{% tabs Queues_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=Queues_1 %}
+~~~scala
+scala> val queue = new scala.collection.mutable.Queue[String]
+queue: scala.collection.mutable.Queue[String] = Queue()
+scala> queue += "a"
+res10: queue.type = Queue(a)
+scala> queue ++= List("b", "c")
+res11: queue.type = Queue(a, b, c)
+scala> queue
+res12: scala.collection.mutable.Queue[String] = Queue(a, b, c)
+scala> queue.dequeue
+res13: String = a
+scala> queue
+res14: scala.collection.mutable.Queue[String] = Queue(b, c)
+~~~
+{% endtab %}
+{% tab 'Scala 3' for=Queues_1 %}
+~~~scala
+scala> val queue = scala.collection.mutable.Queue[String]()
+queue: scala.collection.mutable.Queue[String] = Queue()
+scala> queue += "a"
+res10: queue.type = Queue(a)
+scala> queue ++= List("b", "c")
+res11: queue.type = Queue(a, b, c)
+scala> queue
+res12: scala.collection.mutable.Queue[String] = Queue(a, b, c)
+scala> queue.dequeue
+res13: String = a
+scala> queue
+res14: scala.collection.mutable.Queue[String] = Queue(b, c)
+~~~
+{% endtab %}
+{% endtabs %}
## Stacks
A stack implements a data structure which allows to store and retrieve objects in a last-in-first-out (LIFO) fashion.
It is supported by class [mutable.Stack](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/Stack.html).
- scala> val stack = new scala.collection.mutable.Stack[Int]
- stack: scala.collection.mutable.Stack[Int] = Stack()
- scala> stack.push(1)
- res0: stack.type = Stack(1)
- scala> stack
- res1: scala.collection.mutable.Stack[Int] = Stack(1)
- scala> stack.push(2)
- res0: stack.type = Stack(1, 2)
- scala> stack
- res3: scala.collection.mutable.Stack[Int] = Stack(1, 2)
- scala> stack.top
- res8: Int = 2
- scala> stack
- res9: scala.collection.mutable.Stack[Int] = Stack(1, 2)
- scala> stack.pop
- res10: Int = 2
- scala> stack
- res11: scala.collection.mutable.Stack[Int] = Stack(1)
+{% tabs Stacks_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=Stacks_1 %}
+~~~scala
+scala> val stack = new scala.collection.mutable.Stack[Int]
+stack: scala.collection.mutable.Stack[Int] = Stack()
+scala> stack.push(1)
+res0: stack.type = Stack(1)
+scala> stack
+res1: scala.collection.mutable.Stack[Int] = Stack(1)
+scala> stack.push(2)
+res0: stack.type = Stack(1, 2)
+scala> stack
+res3: scala.collection.mutable.Stack[Int] = Stack(2, 1)
+scala> stack.top
+res8: Int = 2
+scala> stack
+res9: scala.collection.mutable.Stack[Int] = Stack(2, 1)
+scala> stack.pop
+res10: Int = 2
+scala> stack
+res11: scala.collection.mutable.Stack[Int] = Stack(1)
+~~~
+{% endtab %}
+{% tab 'Scala 3' for=Stacks_1 %}
+~~~scala
+scala> val stack = scala.collection.mutable.Stack[Int]()
+stack: scala.collection.mutable.Stack[Int] = Stack()
+scala> stack.push(1)
+res0: stack.type = Stack(1)
+scala> stack
+res1: scala.collection.mutable.Stack[Int] = Stack(1)
+scala> stack.push(2)
+res0: stack.type = Stack(1, 2)
+scala> stack
+res3: scala.collection.mutable.Stack[Int] = Stack(2, 1)
+scala> stack.top
+res8: Int = 2
+scala> stack
+res9: scala.collection.mutable.Stack[Int] = Stack(2, 1)
+scala> stack.pop
+res10: Int = 2
+scala> stack
+res11: scala.collection.mutable.Stack[Int] = Stack(1)
+~~~
+{% endtab %}
+{% endtabs %}
## Mutable ArraySeqs
Array sequences are mutable sequences of fixed size which store their elements internally in an `Array[Object]`. They are implemented in Scala by class [ArraySeq](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/ArraySeq.html).
-You would typically use an `ArraySeq` if you want an array for its performance characteristics, but you also want to create generic instances of the sequence where you do not know the type of the elements and you do not have a `ClassTag` to provide it at run-time. These issues are explained in the section on [arrays]({{ site.baseurl }}/overviews/collections/arrays.html).
+You would typically use an `ArraySeq` if you want an array for its performance characteristics, but you also want to create generic instances of the sequence where you do not know the type of the elements, and you do not have a `ClassTag` to provide it at run-time. These issues are explained in the section on [arrays]({% link _overviews/collections-2.13/arrays.md %}).
## Hash Tables
@@ -115,16 +195,22 @@ A hash table stores its elements in an underlying array, placing each item at a
Hash sets and maps are used just like any other set or map. Here are some simple examples:
- scala> val map = scala.collection.mutable.HashMap.empty[Int,String]
- map: scala.collection.mutable.HashMap[Int,String] = Map()
- scala> map += (1 -> "make a web site")
- res42: map.type = Map(1 -> make a web site)
- scala> map += (3 -> "profit!")
- res43: map.type = Map(1 -> make a web site, 3 -> profit!)
- scala> map(1)
- res44: String = make a web site
- scala> map contains 2
- res46: Boolean = false
+{% tabs Hash-Tables_1 %}
+{% tab 'Scala 2 and 3' for=Hash-Tables_1 %}
+~~~scala
+scala> val map = scala.collection.mutable.HashMap.empty[Int,String]
+map: scala.collection.mutable.HashMap[Int,String] = Map()
+scala> map += (1 -> "make a web site")
+res42: map.type = Map(1 -> make a web site)
+scala> map += (3 -> "profit!")
+res43: map.type = Map(1 -> make a web site, 3 -> profit!)
+scala> map(1)
+res44: String = make a web site
+scala> map contains 2
+res46: Boolean = false
+~~~
+{% endtab %}
+{% endtabs %}
Iteration over a hash table is not guaranteed to occur in any particular order. Iteration simply proceeds through the underlying array in whichever order it happens to be in. To get a guaranteed iteration order, use a _linked_ hash map or set instead of a regular one. A linked hash map or set is just like a regular hash map or set except that it also includes a linked list of the elements in the order they were added. Iteration over such a collection is always in the same order that the elements were initially added.
@@ -145,17 +231,23 @@ A concurrent map can be accessed by several threads at once. In addition to the
| `m.replace(k, old, new)` |Replaces value associated with key `k` to `new`, if it was previously bound to `old`. |
| `m.replace (k, v)` |Replaces value associated with key `k` to `v`, if it was previously bound to some value.|
-`concurrent.Map` is a trait in the Scala collections library. Currently, it has two implementations. The first one is Java's `java.util.concurrent.ConcurrentMap`, which can be converted automatically into a Scala map using the [standard Java/Scala collection conversions]({{ site.baseurl }}/overviews/collections/conversions-between-java-and-scala-collections.html). The second implementation is [TrieMap](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/concurrent/TrieMap.html), which is a lock-free implementation of a hash array mapped trie.
+`concurrent.Map` is a trait in the Scala collections library. Currently, it has two implementations. The first one is Java's `java.util.concurrent.ConcurrentMap`, which can be converted automatically into a Scala map using the [standard Java/Scala collection conversions]({% link _overviews/collections-2.13/conversions-between-java-and-scala-collections.md %}). The second implementation is [TrieMap](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/concurrent/TrieMap.html), which is a lock-free implementation of a hash array mapped trie.
## Mutable Bitsets
A mutable bit of type [mutable.BitSet](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/BitSet.html) set is just like an immutable one, except that it is modified in place. Mutable bit sets are slightly more efficient at updating than immutable ones, because they don't have to copy around `Long`s that haven't changed.
- scala> val bits = scala.collection.mutable.BitSet.empty
- bits: scala.collection.mutable.BitSet = BitSet()
- scala> bits += 1
- res49: bits.type = BitSet(1)
- scala> bits += 3
- res50: bits.type = BitSet(1, 3)
- scala> bits
- res51: scala.collection.mutable.BitSet = BitSet(1, 3)
+{% tabs BitSet_1 %}
+{% tab 'Scala 2 and 3' for=BitSet_1 %}
+~~~scala
+scala> val bits = scala.collection.mutable.BitSet.empty
+bits: scala.collection.mutable.BitSet = BitSet()
+scala> bits += 1
+res49: bits.type = BitSet(1)
+scala> bits += 3
+res50: bits.type = BitSet(1, 3)
+scala> bits
+res51: scala.collection.mutable.BitSet = BitSet(1, 3)
+~~~
+{% endtab %}
+{% endtabs %}
diff --git a/_overviews/collections-2.13/conversion-between-option-and-the-collections.md b/_overviews/collections-2.13/conversion-between-option-and-the-collections.md
new file mode 100644
index 0000000000..d1b2e771cf
--- /dev/null
+++ b/_overviews/collections-2.13/conversion-between-option-and-the-collections.md
@@ -0,0 +1,81 @@
+---
+layout: multipage-overview
+title: Conversion Between Option and the Collections
+partof: collections-213
+overview-name: Collections
+
+num: 18
+previous-page: conversions-between-java-and-scala-collections
+
+permalink: /overviews/collections-2.13/:title.html
+---
+`Option` can be seen as a collection that has zero or exactly one element, and it provides a degree of interoperability with the collection types found in the package `scala.collection`. In particular, it implements the interface `IterableOnce`, which models the simplest form of collections: something that can be iterated over, at least once. However, `Option` does not implement the more comprehensive interface of `Iterable`. Indeed, we cannot provide a sensible implementation for the operation [`fromSpecific`](https://github.com/scala/scala/blob/6c68c2825e893bb71d6dc78465ac8c6f415cbd93/src/library/scala/collection/Iterable.scala#L173), which is supposed to create an `Option` from a collection of possibly more than one element. Starting from [Scala 2.13](https://github.com/scala/scala/pull/8038), `Option` was made an `IterableOnce` but not an `Iterable`.
+
+Hence `Option` can be used everywhere an `IterableOnce` is expected, for example, when calling `flatMap` on a collection (or inside a for-comprehension)
+
+{% tabs options_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=options_1 %}
+```scala mdoc
+for {
+ a <- Set(1)
+ b <- Option(41)
+} yield (a + b)
+// : Set[Int] = Set(42)
+```
+{% endtab %}
+{% tab 'Scala 3' for=options_1 %}
+```scala
+for
+ a <- Set(1)
+ b <- Option(41)
+yield (a + b)
+// : Set[Int] = Set(42)
+```
+{% endtab %}
+{% endtabs %}
+
+since the operation `flatMap` on the type `Set[Int]` takes a function returning an `IterableOnce`:
+
+{% tabs options_2 %}
+{% tab 'Scala 2 and 3' for=options_2 %}
+```
+def flatMap[B](f: Int => IterableOnce[B]): Set[B]
+```
+{% endtab %}
+{% endtabs %}
+
+Although `Option` does not extend `Iterable`, there exists an [implicit conversion](https://github.com/scala/scala/blob/6c68c2825e893bb71d6dc78465ac8c6f415cbd93/src/library/scala/Option.scala#L19) between `Option` and `Iterable`
+
+{% tabs options_3 %}
+{% tab 'Scala 2 and 3' for=options_3 %}
+```
+implicit def option2Iterable[A](xo: Option[A]): Iterable[A]
+```
+{% endtab %}
+{% endtabs %}
+
+so although `Option[A]` is not a full collection it can be _viewed_ as one. For example,
+
+{% tabs options_4 %}
+{% tab 'Scala 2 and 3' for=options_4 %}
+```scala mdoc
+Some(42).drop(1)
+// : Iterable[Int] = List()
+```
+{% endtab %}
+{% endtabs %}
+
+expands to
+
+{% tabs options_5 %}
+{% tab 'Scala 2 and 3' for=options_5 %}
+```scala mdoc
+Option.option2Iterable(Some(42)).drop(1)
+// : Iterable[Int] = List()
+```
+{% endtab %}
+{% endtabs %}
+
+because `drop` is not defined on `Option`. A downside of the above implicit conversion is that instead of getting back an `Option[A]` we are left with an `Iterable[A]`. For this reason, `Option`’s documentation carries the following note:
+
+> Many of the methods in `Option` are duplicative with those in the `Iterable` hierarchy, but they are duplicated for a reason: the implicit conversion tends to leave one with an `Iterable` in situations where one could have retained an `Option`.
diff --git a/_overviews/collections-2.13/conversions-between-java-and-scala-collections.md b/_overviews/collections-2.13/conversions-between-java-and-scala-collections.md
index 86070db314..d66183d84a 100644
--- a/_overviews/collections-2.13/conversions-between-java-and-scala-collections.md
+++ b/_overviews/collections-2.13/conversions-between-java-and-scala-collections.md
@@ -6,6 +6,7 @@ overview-name: Collections
num: 17
previous-page: creating-collections-from-scratch
+next-page: conversion-between-option-and-the-collections
languages: [ru]
permalink: /overviews/collections-2.13/:title.html
@@ -15,49 +16,101 @@ Like Scala, Java also has a rich collections library. There are many similaritie
Sometimes you might need to pass from one collection framework to the other. For instance, you might want to access an existing Java collection as if it were a Scala collection. Or you might want to pass one of Scala's collections to a Java method that expects its Java counterpart. It is quite easy to do this, because Scala offers implicit conversions between all the major collection types in the [CollectionConverters](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/jdk/CollectionConverters$.html) object. In particular, you will find bidirectional conversions between the following types.
+```
+Iterator <=> java.util.Iterator
+Iterator <=> java.util.Enumeration
+Iterable <=> java.lang.Iterable
+Iterable <=> java.util.Collection
+mutable.Buffer <=> java.util.List
+mutable.Set <=> java.util.Set
+mutable.Map <=> java.util.Map
+mutable.ConcurrentMap <=> java.util.concurrent.ConcurrentMap
+```
- Iterator <=> java.util.Iterator
- Iterator <=> java.util.Enumeration
- Iterable <=> java.lang.Iterable
- Iterable <=> java.util.Collection
- mutable.Buffer <=> java.util.List
- mutable.Set <=> java.util.Set
- mutable.Map <=> java.util.Map
- mutable.ConcurrentMap <=> java.util.concurrent.ConcurrentMap
+To enable these conversions, import them from the [CollectionConverters](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/jdk/CollectionConverters$.html) object:
-To enable these conversions, simply import them from the [CollectionConverters](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/jdk/CollectionConverters$.html) object:
+{% tabs java_scala_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=java_scala_1 %}
- scala> import scala.jdk.CollectionConverters._
- import scala.jdk.CollectionConverters._
+```scala
+scala> import scala.jdk.CollectionConverters._
+import scala.jdk.CollectionConverters._
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=java_scala_1 %}
+
+```scala
+scala> import scala.jdk.CollectionConverters.*
+import scala.jdk.CollectionConverters.*
+```
+
+{% endtab %}
+{% endtabs %}
This enables conversions between Scala collections and their corresponding Java collections by way of extension methods called `asScala` and `asJava`:
- scala> import collection.mutable._
- import collection.mutable._
+{% tabs java_scala_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=java_scala_2 %}
+
+```scala
+scala> import collection.mutable._
+import collection.mutable._
+
+scala> val jul: java.util.List[Int] = ArrayBuffer(1, 2, 3).asJava
+val jul: java.util.List[Int] = [1, 2, 3]
+
+scala> val buf: Seq[Int] = jul.asScala
+val buf: scala.collection.mutable.Seq[Int] = ArrayBuffer(1, 2, 3)
- scala> val jul: java.util.List[Int] = ArrayBuffer(1, 2, 3).asJava
- jul: java.util.List[Int] = [1, 2, 3]
+scala> val m: java.util.Map[String, Int] = HashMap("abc" -> 1, "hello" -> 2).asJava
+val m: java.util.Map[String,Int] = {abc=1, hello=2}
+```
- scala> val buf: Seq[Int] = jul.asScala
- buf: scala.collection.mutable.Seq[Int] = ArrayBuffer(1, 2, 3)
+{% endtab %}
+{% tab 'Scala 3' for=java_scala_2 %}
- scala> val m: java.util.Map[String, Int] = HashMap("abc" -> 1, "hello" -> 2).asJava
- m: java.util.Map[String,Int] = {abc=1, hello=2}
+```scala
+scala> import collection.mutable.*
+import collection.mutable.*
+
+scala> val jul: java.util.List[Int] = ArrayBuffer(1, 2, 3).asJava
+val jul: java.util.List[Int] = [1, 2, 3]
+
+scala> val buf: Seq[Int] = jul.asScala
+val buf: scala.collection.mutable.Seq[Int] = ArrayBuffer(1, 2, 3)
+
+scala> val m: java.util.Map[String, Int] = HashMap("abc" -> 1, "hello" -> 2).asJava
+val m: java.util.Map[String,Int] = {abc=1, hello=2}
+```
+
+{% endtab %}
+{% endtabs %}
Internally, these conversion work by setting up a "wrapper" object that forwards all operations to the underlying collection object. So collections are never copied when converting between Java and Scala. An interesting property is that if you do a round-trip conversion from, say a Java type to its corresponding Scala type, and back to the same Java type, you end up with the identical collection object you have started with.
Certain other Scala collections can also be converted to Java, but do not have a conversion back to the original Scala type:
- Seq => java.util.List
- mutable.Seq => java.util.List
- Set => java.util.Set
- Map => java.util.Map
+```
+Seq => java.util.List
+mutable.Seq => java.util.List
+Set => java.util.Set
+Map => java.util.Map
+```
Because Java does not distinguish between mutable and immutable collections in their type, a conversion from, say, `scala.immutable.List` will yield a `java.util.List`, where all mutation operations throw an "UnsupportedOperationException". Here's an example:
- scala> val jul = List(1, 2, 3).asJava
- jul: java.util.List[Int] = [1, 2, 3]
+{% tabs java_scala_3 %}
+{% tab 'Scala 2 and 3' for=java_scala_3 %}
+
+```scala
+scala> val jul = List(1, 2, 3).asJava
+val jul: java.util.List[Int] = [1, 2, 3]
+
+scala> jul.add(7)
+java.lang.UnsupportedOperationException
+ at java.util.AbstractList.add(AbstractList.java:148)
+```
- scala> jul.add(7)
- java.lang.UnsupportedOperationException
- at java.util.AbstractList.add(AbstractList.java:148)
+{% endtab %}
+{% endtabs %}
diff --git a/_overviews/collections-2.13/creating-collections-from-scratch.md b/_overviews/collections-2.13/creating-collections-from-scratch.md
index 729b3008f9..9f10410750 100644
--- a/_overviews/collections-2.13/creating-collections-from-scratch.md
+++ b/_overviews/collections-2.13/creating-collections-from-scratch.md
@@ -14,34 +14,60 @@ permalink: /overviews/collections-2.13/:title.html
You have syntax `List(1, 2, 3)` to create a list of three integers and `Map('A' -> 1, 'C' -> 2)` to create a map with two bindings. This is actually a universal feature of Scala collections. You can take any collection name and follow it by a list of elements in parentheses. The result will be a new collection with the given elements. Here are some more examples:
- Iterable() // An empty collection
- List() // The empty list
- List(1.0, 2.0) // A list with elements 1.0, 2.0
- Vector(1.0, 2.0) // A vector with elements 1.0, 2.0
- Iterator(1, 2, 3) // An iterator returning three integers.
- Set(dog, cat, bird) // A set of three animals
- HashSet(dog, cat, bird) // A hash set of the same animals
- Map('a' -> 7, 'b' -> 0) // A map from characters to integers
+{% tabs creating_1 %}
+{% tab 'Scala 2 and 3' for=creating_1 %}
+
+```scala
+val a = Iterable() // An empty collection
+val b = List() // The empty list
+val c = List(1.0, 2.0) // A list with elements 1.0, 2.0
+val d = Vector(1.0, 2.0) // A vector with elements 1.0, 2.0
+val e = Iterator(1, 2, 3) // An iterator returning three integers.
+val f = Set(dog, cat, bird) // A set of three animals
+val g = HashSet(dog, cat, bird) // A hash set of the same animals
+val h = Map('a' -> 7, 'b' -> 0) // A map from characters to integers
+```
+
+{% endtab %}
+{% endtabs %}
"Under the covers" each of the above lines is a call to the `apply` method of some object. For instance, the third line above expands to
- List.apply(1.0, 2.0)
+{% tabs creating_2 %}
+{% tab 'Scala 2 and 3' for=creating_2 %}
+
+```scala
+val c = List.apply(1.0, 2.0)
+```
+
+{% endtab %}
+{% endtabs %}
So this is a call to the `apply` method of the companion object of the `List` class. That method takes an arbitrary number of arguments and constructs a list from them. Every collection class in the Scala library has a companion object with such an `apply` method. It does not matter whether the collection class represents a concrete implementation, like `List`, `LazyList` or `Vector`, or whether it is an abstract base class such as `Seq`, `Set` or `Iterable`. In the latter case, calling apply will produce some default implementation of the abstract base class. Examples:
- scala> List(1, 2, 3)
- res17: List[Int] = List(1, 2, 3)
- scala> Iterable(1, 2, 3)
- res18: Iterable[Int] = List(1, 2, 3)
- scala> mutable.Iterable(1, 2, 3)
- res19: scala.collection.mutable.Iterable[Int] = ArrayBuffer(1, 2, 3)
+{% tabs creating_3 %}
+{% tab 'Scala 2 and 3' for=creating_3 %}
+
+```scala
+scala> List(1, 2, 3)
+val res17: List[Int] = List(1, 2, 3)
+
+scala> Iterable(1, 2, 3)
+val res18: Iterable[Int] = List(1, 2, 3)
+
+scala> mutable.Iterable(1, 2, 3)
+val res19: scala.collection.mutable.Iterable[Int] = ArrayBuffer(1, 2, 3)
+```
+
+{% endtab %}
+{% endtabs %}
Besides `apply`, every collection companion object also defines a member `empty`, which returns an empty collection. So instead of `List()` you could write `List.empty`, instead of `Map()`, `Map.empty`, and so on.
The operations provided by collection companion objects are summarized in the following table. In short, there's
* `concat`, which concatenates an arbitrary number of collections together,
-* `fill` and `tabulate`, which generate single or multi-dimensional collections of given dimensions initialized by some expression or tabulating function,
+* `fill` and `tabulate`, which generate single or multidimensional collections of given dimensions initialized by some expression or tabulating function,
* `range`, which generates integer collections with some constant step length, and
* `iterate` and `unfold`, which generates the collection resulting from repeated application of a function to a start element or state.
diff --git a/_overviews/collections-2.13/equality.md b/_overviews/collections-2.13/equality.md
index 3ce85f4815..7fa334c8d9 100644
--- a/_overviews/collections-2.13/equality.md
+++ b/_overviews/collections-2.13/equality.md
@@ -14,21 +14,34 @@ permalink: /overviews/collections-2.13/:title.html
The collection libraries have a uniform approach to equality and hashing. The idea is, first, to divide collections into sets, maps, and sequences. Collections in different categories are always unequal. For instance, `Set(1, 2, 3)` is unequal to `List(1, 2, 3)` even though they contain the same elements. On the other hand, within the same category, collections are equal if and only if they have the same elements (for sequences: the same elements in the same order). For example, `List(1, 2, 3) == Vector(1, 2, 3)`, and `HashSet(1, 2) == TreeSet(2, 1)`.
-It does not matter for the equality check whether a collection is mutable or immutable. For a mutable collection one simply considers its current elements at the time the equality test is performed. This means that a mutable collection might be equal to different collections at different times, depending what elements are added or removed. This is a potential trap when using a mutable collection as a key in a hashmap. Example:
-
- scala> import collection.mutable.{HashMap, ArrayBuffer}
- import collection.mutable.{HashMap, ArrayBuffer}
- scala> val buf = ArrayBuffer(1, 2, 3)
- buf: scala.collection.mutable.ArrayBuffer[Int] =
- ArrayBuffer(1, 2, 3)
- scala> val map = HashMap(buf -> 3)
- map: scala.collection.mutable.HashMap[scala.collection.
- mutable.ArrayBuffer[Int],Int] = Map((ArrayBuffer(1, 2, 3),3))
- scala> map(buf)
- res13: Int = 3
- scala> buf(0) += 1
- scala> map(buf)
- java.util.NoSuchElementException: key not found:
+It does not matter for the equality check whether a collection is mutable or immutable. For a mutable collection one simply considers its current elements at the time the equality test is performed. This means that a mutable collection might be equal to different collections at different times, depending on what elements are added or removed. This is a potential trap when using a mutable collection as a key in a hashmap. Example:
+
+{% tabs equality_1 %}
+{% tab 'Scala 2 and 3' for=equality_1 %}
+
+```scala
+scala> import collection.mutable.{HashMap, ArrayBuffer}
+import collection.mutable.{HashMap, ArrayBuffer}
+
+scala> val buf = ArrayBuffer(1, 2, 3)
+val buf: scala.collection.mutable.ArrayBuffer[Int] =
+ ArrayBuffer(1, 2, 3)
+
+scala> val map = HashMap(buf -> 3)
+val map: scala.collection.mutable.HashMap[scala.collection.
+ mutable.ArrayBuffer[Int],Int] = Map((ArrayBuffer(1, 2, 3),3))
+
+scala> map(buf)
+val res13: Int = 3
+
+scala> buf(0) += 1
+
+scala> map(buf)
+ java.util.NoSuchElementException: key not found:
ArrayBuffer(2, 2, 3)
+```
+
+{% endtab %}
+{% endtabs %}
In this example, the selection in the last line will most likely fail because the hash-code of the array `buf` has changed in the second-to-last line. Therefore, the hash-code-based lookup will look at a different place than the one where `buf` was stored.
diff --git a/_overviews/collections-2.13/introduction.md b/_overviews/collections-2.13/introduction.md
index 477f8ffb10..2e4d5f8abb 100644
--- a/_overviews/collections-2.13/introduction.md
+++ b/_overviews/collections-2.13/introduction.md
@@ -12,7 +12,7 @@ permalink: /overviews/collections-2.13/:title.html
---
The collections framework is the heart of the Scala 2.13 standard
-library. It provides a common, uniform, and all-encompassing
+library, also used in Scala 3.x. It provides a common, uniform, and all-encompassing
framework for collection types. This framework enables you to work
with data in memory at a high level, with the basic building blocks of
a program being whole collections, instead of individual elements.
@@ -48,7 +48,7 @@ lines run at first try.
**Fast:** Collection operations are tuned and optimized in the
libraries. As a result, using collections is typically quite
-efficient. You might be able to do a little bit better with carefully
+efficient. You might be able to do a little better with carefully
hand-tuned data structures and operations, but you might also do a lot
worse by making some suboptimal implementation decisions along the
way.
@@ -70,12 +70,18 @@ for arrays.
**Example:** Here's one line of code that demonstrates many of the
advantages of Scala's collections.
- val (minors, adults) = people partition (_.age < 18)
+{% tabs introduction_1 %}
+{% tab 'Scala 2 and 3' for=introduction_1 %}
+```
+val (minors, adults) = people partition (_.age < 18)
+```
+{% endtab %}
+{% endtabs %}
It's immediately clear what this operation does: It partitions a
collection of `people` into `minors` and `adults` depending on
their age. Because the `partition` method is defined in the root
-collection type `TraversableLike`, this code works for any kind of
+collection type `IterableOps`, this code works for any kind of
collection, including arrays. The resulting `minors` and `adults`
collections will be of the same type as the `people` collection.
diff --git a/_overviews/collections-2.13/iterators.md b/_overviews/collections-2.13/iterators.md
index 0f88475625..a72716740d 100644
--- a/_overviews/collections-2.13/iterators.md
+++ b/_overviews/collections-2.13/iterators.md
@@ -16,46 +16,99 @@ An iterator is not a collection, but rather a way to access the elements of a co
The most straightforward way to "step through" all the elements returned by an iterator `it` uses a while-loop:
- while (it.hasNext)
- println(it.next())
+{% tabs iterators_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=iterators_1 %}
+```scala
+while (it.hasNext)
+ println(it.next())
+```
+{% endtab %}
+{% tab 'Scala 3' for=iterators_1 %}
+```scala
+while it.hasNext do
+ println(it.next())
+```
+{% endtab %}
+{% endtabs %}
+
+Iterators in Scala also provide analogues of most of the methods that you find in the `Iterable` and `Seq` classes. For instance, they provide a `foreach` method which executes a given procedure on each element returned by an iterator. Using `foreach`, the loop above could be abbreviated to:
+
+{% tabs iterators_2 %}
+{% tab 'Scala 2 and 3' for=iterators_2 %}
+
+```scala
+it.foreach(println)
+```
+
+{% endtab %}
+{% endtabs %}
-Iterators in Scala also provide analogues of most of the methods that you find in the `Traversable`, `Iterable` and `Seq` classes. For instance, they provide a `foreach` method which executes a given procedure on each element returned by an iterator. Using `foreach`, the loop above could be abbreviated to:
+As always, for-expressions can be used as an alternate syntax for expressions involving `foreach`, `map`, `withFilter`, and `flatMap`, so yet another way to print all elements returned by an iterator would be:
- it foreach println
+{% tabs iterators_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=iterators_3 %}
+```scala
+for (elem <- it) println(elem)
+```
+{% endtab %}
+{% tab 'Scala 3' for=iterators_3 %}
+```scala
+for elem <- it do println(elem)
+```
+{% endtab %}
+{% endtabs %}
+
+There's an important difference between the foreach method on iterators and the same method on iterable collections: When called on an iterator, `foreach` will leave the iterator at its end when it is done. So calling `next` again on the same iterator will fail with a `NoSuchElementException`. By contrast, when called on a collection, `foreach` leaves the number of elements in the collection unchanged (unless the passed function adds or removes elements, but this is discouraged, because it may lead to surprising results).
-As always, for-expressions can be used as an alternate syntax for expressions involving `foreach`, `map`, `withFilter`, and `flatMap`, so yet another way to print all elements returned by an iterator would be:
+The other operations that `Iterator` has in common with `Iterable` have the same property. For instance, iterators provide a `map` method, which returns a new iterator:
- for (elem <- it) println(elem)
+{% tabs iterators_4 %}
+{% tab 'Scala 2 and 3' for=iterators_4 %}
-There's an important difference between the foreach method on iterators and the same method on traversable collections: When called on an iterator, `foreach` will leave the iterator at its end when it is done. So calling `next` again on the same iterator will fail with a `NoSuchElementException`. By contrast, when called on a collection, `foreach` leaves the number of elements in the collection unchanged (unless the passed function adds or removes elements, but this is discouraged, because it may lead to surprising results).
+```scala
+scala> val it = Iterator("a", "number", "of", "words")
+val it: Iterator[java.lang.String] =
-The other operations that `Iterator` has in common with `Iterable` have the same property. For instance, iterators provide a `map` method, which returns a new iterator:
+scala> it.map(_.length)
+val res1: Iterator[Int] =
+
+scala> it.hasNext
+val res2: Boolean = true
+
+scala> res1.foreach(println)
+1
+6
+2
+5
- scala> val it = Iterator("a", "number", "of", "words")
- it: Iterator[java.lang.String] =
- scala> it.map(_.length)
- res1: Iterator[Int] =
- scala> it.hasNext
- res2: Boolean = true
- scala> res1 foreach println
- 1
- 6
- 2
- 5
- scala> it.hasNext
- res4: Boolean = false
+scala> it.hasNext
+val res4: Boolean = false
+```
+
+{% endtab %}
+{% endtabs %}
As you can see, after the call to `it.map`, the `it` iterator hasn’t advanced to its end, but traversing the iterator
resulting from the call to `res1.foreach` also traverses `it` and advances it to its end.
Another example is the `dropWhile` method, which can be used to find the first elements of an iterator that has a certain property. For instance, to find the first word in the iterator above that has at least two characters you could write:
- scala> val it = Iterator("a", "number", "of", "words")
- it: Iterator[java.lang.String] =
- scala> it dropWhile (_.length < 2)
- res4: Iterator[java.lang.String] =
- scala> res4.next()
- res5: java.lang.String = number
+{% tabs iterators_5 %}
+{% tab 'Scala 2 and 3' for=iterators_5 %}
+
+```scala
+scala> val it = Iterator("a", "number", "of", "words")
+val it: Iterator[java.lang.String] =
+
+scala> it.dropWhile(_.length < 2)
+val res4: Iterator[java.lang.String] =
+
+scala> res4.next()
+val res5: java.lang.String = number
+```
+
+{% endtab %}
+{% endtabs %}
Note again that `it` was changed by the call to `dropWhile`: it now points to the second word "number" in the list.
In fact, `it` and the result `res4` returned by `dropWhile` will return exactly the same sequence of elements.
@@ -63,15 +116,23 @@ In fact, `it` and the result `res4` returned by `dropWhile` will return exactly
One way to circumvent this behavior is to `duplicate` the underlying iterator instead of calling methods on it directly.
The _two_ iterators that result will each return exactly the same elements as the underlying iterator `it`:
- scala> val (words, ns) = Iterator("a", "number", "of", "words").duplicate
- words: Iterator[String] =
- ns: Iterator[String] =
+{% tabs iterators_6 %}
+{% tab 'Scala 2 and 3' for=iterators_6 %}
+
+```scala
+scala> val (words, ns) = Iterator("a", "number", "of", "words").duplicate
+val words: Iterator[String] =
+val ns: Iterator[String] =
- scala> val shorts = words.filter(_.length < 3).toList
- shorts: List[String] = List(a, of)
+scala> val shorts = words.filter(_.length < 3).toList
+val shorts: List[String] = List(a, of)
- scala> val count = ns.map(_.length).sum
- count: Int = 14
+scala> val count = ns.map(_.length).sum
+val count: Int = 14
+```
+
+{% endtab %}
+{% endtabs %}
The two iterators work independently: advancing one does not affect the other, so that each can be
destructively modified by invoking arbitrary methods. This creates the illusion of iterating over
@@ -87,31 +148,31 @@ All operations on iterators are summarized below.
| WHAT IT IS | WHAT IT DOES |
| ------ | ------ |
| **Abstract Methods:** | |
-| `it.next()` | Returns next element on iterator and advances past it. |
-| `it.hasNext` | Returns `true` if `it` can return another element. |
+| `it.next()` | Returns next element on iterator and advances past it. |
+| `it.hasNext` | Returns `true` if `it` can return another element. |
| **Variations:** | |
| `it.buffered` | A buffered iterator returning all elements of `it`. |
-| `it grouped size` | An iterator that yields the elements returned by `it` in fixed-sized sequence "chunks". |
-| `it sliding size` | An iterator that yields the elements returned by `it` in sequences representing a sliding fixed-sized window. |
+| `it.grouped(size)` | An iterator that yields the elements returned by `it` in fixed-sized sequence "chunks". |
+| `it.sliding(size)` | An iterator that yields the elements returned by `it` in sequences representing a sliding fixed-sized window. |
| **Duplication:** | |
| `it.duplicate` | A pair of iterators that each independently return all elements of `it`. |
| **Additions:** | |
-| `it concat jt` or `it ++ jt` | An iterator returning all elements returned by iterator `it`, followed by all elements returned by iterator `jt`. |
-| `it.padTo(len, x)` | The iterator that first returns all elements of `it` and then follows that by copies of `x` until length `len` elements are returned overall. |
+| `it.concat(jt)` or `it ++ jt` | An iterator returning all elements returned by iterator `it`, followed by all elements returned by iterator `jt`. |
+| `it.padTo(len, x)` | The iterator that first returns all elements of `it` and then follows that by copies of `x` until length `len` elements are returned overall. |
| **Maps:** | |
-| `it map f` | The iterator obtained from applying the function `f` to every element returned from `it`. |
-| `it flatMap f` | The iterator obtained from applying the iterator-valued function `f` to every element in `it` and appending the results. |
-| `it collect f` | The iterator obtained from applying the partial function `f` to every element in `it` for which it is defined and collecting the results. |
+| `it.map(f)` | The iterator obtained from applying the function `f` to every element returned from `it`. |
+| `it.flatMap(f)` | The iterator obtained from applying the iterator-valued function `f` to every element in `it` and appending the results. |
+| `it.collect(f)` | The iterator obtained from applying the partial function `f` to every element in `it` for which it is defined and collecting the results. |
| **Conversions:** | |
| `it.toArray` | Collects the elements returned by `it` in an array. |
| `it.toList` | Collects the elements returned by `it` in a list. |
| `it.toIterable` | Collects the elements returned by `it` in an iterable. |
| `it.toSeq` | Collects the elements returned by `it` in a sequence. |
| `it.toIndexedSeq` | Collects the elements returned by `it` in an indexed sequence. |
-| `it.toLazyList` | Collects the elements returned by `it` in a lazy list. |
+| `it.toLazyList` | Collects the elements returned by `it` in a lazy list. |
| `it.toSet` | Collects the elements returned by `it` in a set. |
| `it.toMap` | Collects the key/value pairs returned by `it` in a map. |
-| **Copying:** | |
+| **Copying:** | |
| `it.copyToArray(arr, s, n)`| Copies at most `n` elements returned by `it` to array `arr` starting at index `s`. The last two arguments are optional. |
| **Size Info:** | |
| `it.isEmpty` | Test whether the iterator is empty (opposite of `hasNext`). |
@@ -120,44 +181,44 @@ All operations on iterators are summarized below.
| `it.length` | Same as `it.size`. |
| `it.knownSize` |The number of elements, if this one is known without modifying the iterator’s state, otherwise `-1`. |
| **Element Retrieval Index Search:**| |
-| `it find p` | An option containing the first element returned by `it` that satisfies `p`, or `None` is no element qualifies. Note: The iterator advances to after the element, or, if none is found, to the end. |
-| `it indexOf x` | The index of the first element returned by `it` that equals `x`. Note: The iterator advances past the position of this element. |
-| `it indexWhere p` | The index of the first element returned by `it` that satisfies `p`. Note: The iterator advances past the position of this element. |
+| `it.find(p)` | An option containing the first element returned by `it` that satisfies `p`, or `None` is no element qualifies. Note: The iterator advances to after the element, or, if none is found, to the end. |
+| `it.indexOf(x)` | The index of the first element returned by `it` that equals `x`. Note: The iterator advances past the position of this element. |
+| `it.indexWhere(p)` | The index of the first element returned by `it` that satisfies `p`. Note: The iterator advances past the position of this element. |
| **Subiterators:** | |
-| `it take n` | An iterator returning of the first `n` elements of `it`. Note: it will advance to the position after the `n`'th element, or to its end, if it contains less than `n` elements. |
-| `it drop n` | The iterator that starts with the `(n+1)`'th element of `it`. Note: `it` will advance to the same position. |
-| `it.slice(m,n)` | The iterator that returns a slice of the elements returned from it, starting with the `m`'th element and ending before the `n`'th element. |
-| `it takeWhile p` | An iterator returning elements from `it` as long as condition `p` is true. |
-| `it dropWhile p` | An iterator skipping elements from `it` as long as condition `p` is `true`, and returning the remainder. |
-| `it filter p` | An iterator returning all elements from `it` that satisfy the condition `p`. |
-| `it withFilter p` | Same as `it` filter `p`. Needed so that iterators can be used in for-expressions. |
-| `it filterNot p` | An iterator returning all elements from `it` that do not satisfy the condition `p`. |
+| `it.take(n)` | An iterator returning of the first `n` elements of `it`. Note: it will advance to the position after the `n`'th element, or to its end, if it contains less than `n` elements. |
+| `it.drop(n)` | The iterator that starts with the `(n+1)`'th element of `it`. Note: `it` will advance to the same position. |
+| `it.slice(m,n)` | The iterator that returns a slice of the elements returned from it, starting with the `m`'th element and ending before the `n`'th element. |
+| `it.takeWhile(p)` | An iterator returning elements from `it` as long as condition `p` is true. |
+| `it.dropWhile(p)` | An iterator skipping elements from `it` as long as condition `p` is `true`, and returning the remainder. |
+| `it.filter(p)` | An iterator returning all elements from `it` that satisfy the condition `p`. |
+| `it.withFilter(p)` | Same as `it` filter `p`. Needed so that iterators can be used in for-expressions. |
+| `it.filterNot(p)` | An iterator returning all elements from `it` that do not satisfy the condition `p`. |
| `it.distinct` | An iterator returning the elements from `it` without duplicates. |
| **Subdivisions:** | |
-| `it partition p` | Splits `it` into a pair of two iterators: one returning all elements from `it` that satisfy the predicate `p`, the other returning all elements from `it` that do not. |
-| `it span p` | Splits `it` into a pair of two iterators: one returning all elements of the prefix of `it` that satisfy the predicate `p`, the other returning all remaining elements of `it`. |
+| `it.partition(p)` | Splits `it` into a pair of two iterators: one returning all elements from `it` that satisfy the predicate `p`, the other returning all elements from `it` that do not. |
+| `it.span(p)` | Splits `it` into a pair of two iterators: one returning all elements of the prefix of `it` that satisfy the predicate `p`, the other returning all remaining elements of `it`. |
| **Element Conditions:** | |
-| `it forall p` | A boolean indicating whether the predicate p holds for all elements returned by `it`. |
-| `it exists p` | A boolean indicating whether the predicate p holds for some element in `it`. |
-| `it count p` | The number of elements in `it` that satisfy the predicate `p`. |
+| `it.forall(p)` | A boolean indicating whether the predicate p holds for all elements returned by `it`. |
+| `it.exists(p)` | A boolean indicating whether the predicate p holds for some element in `it`. |
+| `it.count(p)` | The number of elements in `it` that satisfy the predicate `p`. |
| **Folds:** | |
| `it.foldLeft(z)(op)` | Apply binary operation `op` between successive elements returned by `it`, going left to right and starting with `z`. |
| `it.foldRight(z)(op)` | Apply binary operation `op` between successive elements returned by `it`, going right to left and starting with `z`. |
-| `it reduceLeft op` | Apply binary operation `op` between successive elements returned by non-empty iterator `it`, going left to right. |
-| `it reduceRight op` | Apply binary operation `op` between successive elements returned by non-empty iterator `it`, going right to left. |
+| `it.reduceLeft(op)` | Apply binary operation `op` between successive elements returned by non-empty iterator `it`, going left to right. |
+| `it.reduceRight(op)` | Apply binary operation `op` between successive elements returned by non-empty iterator `it`, going right to left. |
| **Specific Folds:** | |
| `it.sum` | The sum of the numeric element values returned by iterator `it`. |
| `it.product` | The product of the numeric element values returned by iterator `it`. |
| `it.min` | The minimum of the ordered element values returned by iterator `it`. |
| `it.max` | The maximum of the ordered element values returned by iterator `it`. |
| **Zippers:** | |
-| `it zip jt` | An iterator of pairs of corresponding elements returned from iterators `it` and `jt`. |
-| `it.zipAll(jt, x, y)` | An iterator of pairs of corresponding elements returned from iterators `it` and `jt`, where the shorter iterator is extended to match the longer one by appending elements `x` or `y`. |
+| `it.zip(jt)` | An iterator of pairs of corresponding elements returned from iterators `it` and `jt`. |
+| `it.zipAll(jt, x, y)` | An iterator of pairs of corresponding elements returned from iterators `it` and `jt`, where the shorter iterator is extended to match the longer one by appending elements `x` or `y`. |
| `it.zipWithIndex` | An iterator of pairs of elements returned from `it` with their indices. |
| **Update:** | |
-| `it.patch(i, jt, r)` | The iterator resulting from `it` by replacing `r` elements starting with `i` by the patch iterator `jt`. |
+| `it.patch(i, jt, r)` | The iterator resulting from `it` by replacing `r` elements starting with `i` by the patch iterator `jt`. |
| **Comparison:** | |
-| `it sameElements jt` | A test whether iterators `it` and `jt` return the same elements in the same order. Note: Using the iterators after this operation is undefined and subject to change. |
+| `it.sameElements(jt)` | A test whether iterators `it` and `jt` return the same elements in the same order. Note: Using the iterators after this operation is undefined and subject to change. |
| **Strings:** | |
| `it.addString(b, start, sep, end)`| Adds a string to `StringBuilder` `b` which shows all elements returned by `it` between separators `sep` enclosed in strings `start` and `end`. `start`, `sep`, `end` are all optional. |
| `it.mkString(start, sep, end)` | Converts the collection to a string which shows all elements returned by `it` between separators `sep` enclosed in strings `start` and `end`. `start`, `sep`, `end` are all optional. |
@@ -170,44 +231,88 @@ A lazy operation does not immediately compute all of its results. Instead, it co
So the expression `(1 to 10).iterator.map(println)` would not print anything to the screen. The `map` method in this case doesn't apply its argument function to the values in the range, it returns a new `Iterator` that will do this as each one is requested. Adding `.toList` to the end of that expression will actually print the elements.
-A consequence of this is that a method like `map` or `filter` won't necessarily apply its argument function to all of the input elements. The expression `(1 to 10).iterator.map(println).take(5).toList` would only print the values `1` to `5`, for instance, since those are only ones that will be requested from the `Iterator` returned by `map`.
+A consequence of this is that a method like `map` or `filter` won't necessarily apply its argument function to all the input elements. The expression `(1 to 10).iterator.map(println).take(5).toList` would only print the values `1` to `5`, for instance, since those are only ones that will be requested from the `Iterator` returned by `map`.
This is one of the reasons why it's important to only use pure functions as arguments to `map`, `filter`, `fold` and similar methods. Remember, a pure function has no side-effects, so one would not normally use `println` in a `map`. `println` is used to demonstrate laziness as it's not normally visible with pure functions.
Laziness is still valuable, despite often not being visible, as it can prevent unneeded computations from happening, and can allow for working with infinite sequences, like so:
- def zipWithIndex[A](i: Iterator[A]): Iterator[(Int, A)] =
- Iterator.from(0).zip(i)
+{% tabs iterators_7 %}
+{% tab 'Scala 2 and 3' for=iterators_7 %}
+
+```scala
+def zipWithIndex[A](i: Iterator[A]): Iterator[(Int, A)] =
+ Iterator.from(0).zip(i)
+```
+
+{% endtab %}
+{% endtabs %}
### Buffered iterators
Sometimes you want an iterator that can "look ahead", so that you can inspect the next element to be returned without advancing past that element. Consider for instance, the task to skip leading empty strings from an iterator that returns a sequence of strings. You might be tempted to write the following
-
- def skipEmptyWordsNOT(it: Iterator[String]) =
- while (it.next().isEmpty) {}
+{% tabs iterators_8 class=tabs-scala-version %}
+{% tab 'Scala 2' for=iterators_8 %}
+```scala mdoc
+def skipEmptyWordsNOT(it: Iterator[String]) =
+ while (it.next().isEmpty) {}
+```
+{% endtab %}
+{% tab 'Scala 3' for=iterators_8 %}
+```scala
+def skipEmptyWordsNOT(it: Iterator[String]) =
+ while it.next().isEmpty do ()
+```
+{% endtab %}
+{% endtabs %}
But looking at this code more closely, it's clear that this is wrong: The code will indeed skip leading empty strings, but it will also advance `it` past the first non-empty string!
The solution to this problem is to use a buffered iterator. Class [BufferedIterator](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/BufferedIterator.html) is a subclass of [Iterator](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterator.html), which provides one extra method, `head`. Calling `head` on a buffered iterator will return its first element but will not advance the iterator. Using a buffered iterator, skipping empty words can be written as follows.
- def skipEmptyWords(it: BufferedIterator[String]) =
- while (it.head.isEmpty) { it.next() }
+{% tabs iterators_9 class=tabs-scala-version %}
+{% tab 'Scala 2' for=iterators_9 %}
+```scala
+def skipEmptyWords(it: BufferedIterator[String]) =
+ while (it.head.isEmpty) { it.next() }
+```
+{% endtab %}
+{% tab 'Scala 3' for=iterators_9 %}
+```scala
+def skipEmptyWords(it: BufferedIterator[String]) =
+ while it.head.isEmpty do it.next()
+```
+{% endtab %}
+{% endtabs %}
Every iterator can be converted to a buffered iterator by calling its `buffered` method. Here's an example:
- scala> val it = Iterator(1, 2, 3, 4)
- it: Iterator[Int] =
- scala> val bit = it.buffered
- bit: scala.collection.BufferedIterator[Int] =
- scala> bit.head
- res10: Int = 1
- scala> bit.next()
- res11: Int = 1
- scala> bit.next()
- res12: Int = 2
- scala> bit.headOption
- res13: Option[Int] = Some(3)
+{% tabs iterators_10 %}
+{% tab 'Scala 2 and 3' for=iterators_10 %}
+
+```scala
+scala> val it = Iterator(1, 2, 3, 4)
+val it: Iterator[Int] =
+
+scala> val bit = it.buffered
+val bit: scala.collection.BufferedIterator[Int] =
+
+scala> bit.head
+val res10: Int = 1
+
+scala> bit.next()
+val res11: Int = 1
+
+scala> bit.next()
+val res12: Int = 2
+
+scala> bit.headOption
+val res13: Option[Int] = Some(3)
+```
+
+{% endtab %}
+{% endtabs %}
Note that calling `head` on the buffered iterator `bit` does not advance it. Therefore, the subsequent call `bit.next()` returns the same value as `bit.head`.
@@ -217,21 +322,50 @@ The buffered iterator only buffers the next element when `head` is invoked. Othe
such as those produced by `duplicate` and `partition`, may buffer arbitrary subsequences of the
underlying iterator. But iterators can be efficiently joined by adding them together with `++`:
- scala> def collapse(it: Iterator[Int]) = if (!it.hasNext) Iterator.empty else {
- | var head = it.next
- | val rest = if (head == 0) it.dropWhile(_ == 0) else it
- | Iterator.single(head) ++ rest
- | }
- collapse: (it: Iterator[Int])Iterator[Int]
-
- scala> def collapse(it: Iterator[Int]) = {
- | val (zeros, rest) = it.span(_ == 0)
- | zeros.take(1) ++ rest
- | }
- collapse: (it: Iterator[Int])Iterator[Int]
-
- scala> collapse(Iterator(0, 0, 0, 1, 2, 3, 4)).toList
- res14: List[Int] = List(0, 1, 2, 3, 4)
+{% tabs iterators_11 class=tabs-scala-version %}
+{% tab 'Scala 2' for=iterators_11 %}
+
+```scala
+scala> def collapse(it: Iterator[Int]) = if (!it.hasNext) Iterator.empty else {
+ | var head = it.next
+ | val rest = if (head == 0) it.dropWhile(_ == 0) else it
+ | Iterator.single(head) ++ rest
+ |}
+def collapse(it: Iterator[Int]): Iterator[Int]
+
+scala> def collapse(it: Iterator[Int]) = {
+ | val (zeros, rest) = it.span(_ == 0)
+ | zeros.take(1) ++ rest
+ |}
+def collapse(it: Iterator[Int]): Iterator[Int]
+
+scala> collapse(Iterator(0, 0, 0, 1, 2, 3, 4)).toList
+val res14: List[Int] = List(0, 1, 2, 3, 4)
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=iterators_11 %}
+
+```scala
+scala> def collapse(it: Iterator[Int]) = if !it.hasNext then Iterator.empty else
+ | var head = it.next
+ | val rest = if head == 0 then it.dropWhile(_ == 0) else it
+ | Iterator.single(head) ++ rest
+ |
+def collapse(it: Iterator[Int]): Iterator[Int]
+
+scala> def collapse(it: Iterator[Int]) =
+ | val (zeros, rest) = it.span(_ == 0)
+ | zeros.take(1) ++ rest
+ |
+def collapse(it: Iterator[Int]): Iterator[Int]
+
+scala> collapse(Iterator(0, 0, 0, 1, 2, 3, 4)).toList
+val res14: List[Int] = List(0, 1, 2, 3, 4)
+```
+
+{% endtab %}
+{% endtabs %}
In the second version of `collapse`, the unconsumed zeros are buffered internally.
In the first version, any leading zeros are dropped and the desired result constructed
diff --git a/_overviews/collections-2.13/maps.md b/_overviews/collections-2.13/maps.md
index 3a27586614..34d9696f19 100644
--- a/_overviews/collections-2.13/maps.md
+++ b/_overviews/collections-2.13/maps.md
@@ -16,7 +16,7 @@ A [Map](https://www.scala-lang.org/api/current/scala/collection/Map.html) is an
The fundamental operations on maps are similar to those on sets. They are summarized in the following table and fall into the following categories:
-* **Lookup** operations `apply`, `get`, `getOrElse`, `contains`, and `isDefinedAt`. These turn maps into partial functions from keys to values. The fundamental lookup method for a map is: `def get(key): Option[Value]`. The operation "`m get key`" tests whether the map contains an association for the given `key`. If so, it returns the associated value in a `Some`. If no key is defined in the map, `get` returns `None`. Maps also define an `apply` method that returns the value associated with a given key directly, without wrapping it in an `Option`. If the key is not defined in the map, an exception is raised.
+* **Lookup** operations `apply`, `get`, `getOrElse`, `contains`, and `isDefinedAt`. These turn maps into partial functions from keys to values. The fundamental lookup method for a map is: `def get(key): Option[Value]`. The operation `m.get(key)` tests whether the map contains an association for the given `key`. If so, it returns the associated value in a `Some`. If no key is defined in the map, `get` returns `None`. Maps also define an `apply` method that returns the value associated with a given key directly, without wrapping it in an `Option`. If the key is not defined in the map, an exception is raised.
* **Additions and updates** `+`, `++`, `updated`, which let you add new bindings to a map or change existing bindings.
* **Removals** `-`, `--`, which remove bindings from a map.
* **Subcollection producers** `keys`, `keySet`, `keysIterator`, `values`, `valuesIterator`, which return a map's keys and values separately in various forms.
@@ -24,90 +24,140 @@ The fundamental operations on maps are similar to those on sets. They are summar
### Operations in Class Map ###
-| WHAT IT IS | WHAT IT DOES |
-| ------ | ------ |
-| **Lookups:** | |
-| `ms get k` |The value associated with key `k` in map `ms` as an option, `None` if not found.|
-| `ms(k)` |(or, written out, `ms apply k`) The value associated with key `k` in map `ms`, or exception if not found.|
-| `ms getOrElse (k, d)` |The value associated with key `k` in map `ms`, or the default value `d` if not found.|
-| `ms contains k` |Tests whether `ms` contains a mapping for key `k`.|
-| `ms isDefinedAt k` |Same as `contains`. |
-| **Subcollections:** | |
+| WHAT IT IS | WHAT IT DOES |
+| ------ | ------ |
+| **Lookups:** | |
+| `ms.get(k)` |The value associated with key `k` in map `ms` as an option, `None` if not found.|
+| `ms(k)` |(or, written out, `ms.apply(k)`) The value associated with key `k` in map `ms`, or exception if not found.|
+| `ms.getOrElse(k, d)` |The value associated with key `k` in map `ms`, or the default value `d` if not found.|
+| `ms.contains(k)` |Tests whether `ms` contains a mapping for key `k`.|
+| `ms.isDefinedAt(k)` |Same as `contains`. |
+| **Subcollections:** | |
| `ms.keys` |An iterable containing each key in `ms`. |
| `ms.keySet` |A set containing each key in `ms`. |
| `ms.keysIterator` |An iterator yielding each key in `ms`. |
| `ms.values` |An iterable containing each value associated with a key in `ms`.|
| `ms.valuesIterator` |An iterator yielding each value associated with a key in `ms`.|
-| **Transformation:** | |
-| `ms.view filterKeys p` |A map view containing only those mappings in `ms` where the key satisfies predicate `p`.|
-| `ms.view mapValues f` |A map view resulting from applying function `f` to each value associated with a key in `ms`.|
+| **Transformation:** | |
+| `ms.view.filterKeys(p)` |A map view containing only those mappings in `ms` where the key satisfies predicate `p`.|
+| `ms.view.mapValues(f)` |A map view resulting from applying function `f` to each value associated with a key in `ms`.|
Immutable maps support in addition operations to add and remove mappings by returning new `Map`s, as summarized in the following table.
### Operations in Class immutable.Map ###
-| WHAT IT IS | WHAT IT DOES |
-| ------ | ------ |
-| **Additions and Updates:**| |
+| WHAT IT IS | WHAT IT DOES |
+| ------ | ------ |
+| **Additions and Updates:**| |
| `ms.updated(k, v)` or `ms + (k -> v)` |The map containing all mappings of `ms` as well as the mapping `k -> v` from key `k` to value `v`.|
-| **Removals:** | |
-| `ms remove k` or `ms - k` |The map containing all mappings of `ms` except for any mapping of key `k`.|
-| `ms removeAll ks` or `ms -- ks` |The map containing all mappings of `ms` except for any mapping with a key in `ks`.|
+| **Removals:** | |
+| `ms.removed(k)` or `ms - k` |The map containing all mappings of `ms` except for any mapping of key `k`.|
+| `ms.removedAll(ks)` or `ms -- ks` |The map containing all mappings of `ms` except for any mapping with a key in `ks`.|
Mutable maps support in addition the operations summarized in the following table.
### Operations in Class mutable.Map ###
-| WHAT IT IS | WHAT IT DOES |
-| ------ | ------ |
-| **Additions and Updates:**| |
-| `ms(k) = v` |(Or, written out, `ms.update(x, v)`). Adds mapping from key `k` to value `v` to map ms as a side effect, overwriting any previous mapping of `k`.|
-| `ms.addOne(k -> v)` or `ms += (k -> v)` |Adds mapping from key `k` to value `v` to map `ms` as a side effect and returns `ms` itself.|
-| `ms addAll xvs` or `ms ++= kvs` |Adds all mappings in `kvs` to `ms` as a side effect and returns `ms` itself.|
-| `ms.put(k, v)` |Adds mapping from key `k` to value `v` to `ms` and returns any value previously associated with `k` as an option.|
-| `ms getOrElseUpdate (k, d)`|If key `k` is defined in map `ms`, return its associated value. Otherwise, update `ms` with the mapping `k -> d` and return `d`.|
-| **Removals:**| |
-| `ms subtractOne k` or `ms -= k` |Removes mapping with key `k` from ms as a side effect and returns `ms` itself.|
-| `ms subtractAll ks` or `ms --= ks` |Removes all keys in `ks` from `ms` as a side effect and returns `ms` itself.|
-| `ms remove k` |Removes any mapping with key `k` from `ms` and returns any value previously associated with `k` as an option.|
-| `ms filterInPlace p` |Keeps only those mappings in `ms` that have a key satisfying predicate `p`.|
-| `ms.clear()` |Removes all mappings from `ms`. |
-| **Transformation:** | |
-| `ms mapValuesInPlace f` |Transforms all associated values in map `ms` with function `f`.|
-| **Cloning:** | |
-| `ms.clone` |Returns a new mutable map with the same mappings as `ms`.|
-
-The addition and removal operations for maps mirror those for sets. A mutable map `m` is usually updated "in place", using the two variants `m(key) = value` or `m += (key -> value)`. There is also the variant `m.put(key, value)`, which returns an `Option` value that contains the value previously associated with `key`, or `None` if the `key` did not exist in the map before.
+| WHAT IT IS | WHAT IT DOES |
+| ------ | ------ |
+| **Additions and Updates:** | |
+| `ms(k) = v` |(Or, written out, `ms.update(k, v)`). Adds mapping from key `k` to value `v` to map ms as a side effect, overwriting any previous mapping of `k`.|
+| `ms.addOne(k -> v)` or `ms += (k -> v)` |Adds mapping from key `k` to value `v` to map `ms` as a side effect and returns `ms` itself.|
+| `ms.addAll(kvs)` or `ms ++= kvs` |Adds all mappings in `kvs` to `ms` as a side effect and returns `ms` itself.|
+| `ms.put(k, v)` |Adds mapping from key `k` to value `v` to `ms` and returns any value previously associated with `k` as an option.|
+| `ms.getOrElseUpdate(k, d)` |If key `k` is defined in map `ms`, return its associated value. Otherwise, update `ms` with the mapping `k -> d` and return `d`.|
+| **Removals:** | |
+| `ms.subtractOne(k)` or `ms -= k` |Removes mapping with key `k` from ms as a side effect and returns `ms` itself.|
+| `ms.subtractAll(ks)` or `ms --= ks` |Removes all keys in `ks` from `ms` as a side effect and returns `ms` itself.|
+| `ms.remove(k)` |Removes any mapping with key `k` from `ms` and returns any value previously associated with `k` as an option.|
+| `ms.filterInPlace(p)` |Keeps only those mappings in `ms` that have a key satisfying predicate `p`.|
+| `ms.clear()` |Removes all mappings from `ms`. |
+| **Transformation:** | |
+| `ms.mapValuesInPlace(f)` |Transforms all associated values in map `ms` with function `f`.|
+| **Cloning:** | |
+| `ms.clone` |Returns a new mutable map with the same mappings as `ms`.|
+
+The addition and removal operations for maps mirror those for sets. A mutable map `m` is usually updated in place, using the two variants `m(key) = value` or `m += (key -> value)`. There is also the variant `m.put(key, value)`, which returns an `Option` value that contains the value previously associated with `key`, or `None` if the `key` did not exist in the map before.
The `getOrElseUpdate` is useful for accessing maps that act as caches. Say you have an expensive computation triggered by invoking a function `f`:
- scala> def f(x: String) = {
- println("taking my time."); sleep(100)
- x.reverse }
- f: (x: String)String
+{% tabs expensive-computation-reverse class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=expensive-computation-reverse %}
+```scala
+scala> def f(x: String): String = {
+ println("taking my time."); Thread.sleep(100)
+ x.reverse
+ }
+f: (x: String)String
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=expensive-computation-reverse %}
+```scala
+scala> def f(x: String): String =
+ println("taking my time."); Thread.sleep(100)
+ x.reverse
+
+def f(x: String): String
+```
+{% endtab %}
+
+{% endtabs %}
Assume further that `f` has no side-effects, so invoking it again with the same argument will always yield the same result. In that case you could save time by storing previously computed bindings of argument and results of `f` in a map and only computing the result of `f` if a result of an argument was not found there. One could say the map is a _cache_ for the computations of the function `f`.
- scala> val cache = collection.mutable.Map[String, String]()
- cache: scala.collection.mutable.Map[String,String] = Map()
+{% tabs cache-creation %}
+{% tab 'Scala 2 and 3' for=cache-creation %}
+```scala
+scala> val cache = collection.mutable.Map[String, String]()
+cache: scala.collection.mutable.Map[String,String] = Map()
+```
+{% endtab %}
+{% endtabs %}
You can now create a more efficient caching version of the `f` function:
- scala> def cachedF(s: String) = cache.getOrElseUpdate(s, f(s))
- cachedF: (s: String)String
- scala> cachedF("abc")
- taking my time.
- res3: String = cba
- scala> cachedF("abc")
- res4: String = cba
-
-Note that the second argument to `getOrElseUpdate` is "by-name", so the computation of `f("abc")` above is only performed if `getOrElseUpdate` requires the value of its second argument, which is precisely if its first argument is not found in the `cache` map. You could also have implemented `cachedF` directly, using just basic map operations, but it would take more code to do so:
-
- def cachedF(arg: String) = cache get arg match {
- case Some(result) => result
- case None =>
- val result = f(x)
- cache(arg) = result
- result
- }
+{% tabs cache-usage %}
+{% tab 'Scala 2 and 3' for=cache-usage %}
+```scala
+scala> def cachedF(s: String): String = cache.getOrElseUpdate(s, f(s))
+cachedF: (s: String)String
+scala> cachedF("abc")
+taking my time.
+res3: String = cba
+scala> cachedF("abc")
+res4: String = cba
+```
+{% endtab %}
+{% endtabs %}
+
+Note that the second argument to `getOrElseUpdate` is by-name, so the computation of `f("abc")` above is only performed if `getOrElseUpdate` requires the value of its second argument, which is precisely if its first argument is not found in the `cache` map. You could also have implemented `cachedF` directly, using just basic map operations, but it would take more code to do so:
+
+{% tabs cacheF class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=cacheF %}
+```scala
+def cachedF(arg: String): String = cache.get(arg) match {
+ case Some(result) => result
+ case None =>
+ val result = f(x)
+ cache(arg) = result
+ result
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=cacheF %}
+```scala
+def cachedF(arg: String): String = cache.get(arg) match
+ case Some(result) => result
+ case None =>
+ val result = f(x)
+ cache(arg) = result
+ result
+```
+{% endtab %}
+
+{% endtabs %}
diff --git a/_overviews/collections-2.13/overview.md b/_overviews/collections-2.13/overview.md
index 4d739156ac..5ef0c9b0f3 100644
--- a/_overviews/collections-2.13/overview.md
+++ b/_overviews/collections-2.13/overview.md
@@ -13,10 +13,10 @@ permalink: /overviews/collections-2.13/:title.html
---
Scala collections systematically distinguish between mutable and
-immutable collections. A _mutable_ collection can be updated or
+immutable collections. A _mutable_ collection can be updated, reduced or
extended in place. This means you can change, add, or remove elements
of a collection as a side effect. _Immutable_ collections, by
-contrast, never change. You have still operations that simulate
+contrast, never change. You still have operations that simulate
additions, removals, or updates, but those operations will in each
case return a new collection and leave the old collection unchanged.
@@ -36,14 +36,14 @@ always yield a collection with the same elements.
A collection in package `scala.collection.mutable` is known to have
some operations that change the collection in place. So dealing with
-mutable collection means you need to understand which code changes
+a mutable collection means you need to understand which code changes
which collection when.
A collection in package `scala.collection` can be either mutable or
immutable. For instance, [collection.IndexedSeq\[T\]](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/IndexedSeq.html)
is a superclass of both [collection.immutable.IndexedSeq\[T\]](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/IndexedSeq.html)
and
-[collection.mutable.IndexedSeq\[T\]](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/IndexedSeq.html)
+[collection.mutable.IndexedSeq\[T\]](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/IndexedSeq.html).
Generally, the root collections in
package `scala.collection` support transformation operations
affecting the whole collection, the immutable
@@ -73,7 +73,13 @@ A useful convention if you want to use both mutable and immutable
versions of collections is to import just the package
`collection.mutable`.
- import scala.collection.mutable
+{% tabs overview_1 %}
+{% tab 'Scala 2 and 3' for=overview_1 %}
+```scala mdoc
+import scala.collection.mutable
+```
+{% endtab %}
+{% endtabs %}
Then a word like `Set` without a prefix still refers to an immutable collection,
whereas `mutable.Set` refers to the mutable counterpart.
@@ -86,10 +92,16 @@ aliases in the `scala` package, so you can use them by their simple
names without needing an import. An example is the `List` type, which
can be accessed alternatively as
- scala.collection.immutable.List // that's where it is defined
- scala.List // via the alias in the scala package
- List // because scala._
- // is always automatically imported
+{% tabs overview_2 %}
+{% tab 'Scala 2 and 3' for=overview_2 %}
+```scala mdoc
+scala.collection.immutable.List // that's where it is defined
+scala.List // via the alias in the scala package
+List // because scala._
+ // is always automatically imported
+```
+{% endtab %}
+{% endtabs %}
Other types aliased are
[Iterable](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterable.html), [Seq](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Seq.html), [IndexedSeq](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/IndexedSeq.html), [Iterator](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterator.html), [LazyList](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/LazyList.html), [Vector](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Vector.html), [StringBuilder](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/StringBuilder.html), and [Range](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Range.html).
@@ -116,27 +128,45 @@ Legend:
The most important collection classes are shown in the figures above. There is quite a bit of commonality shared by all these classes. For instance, every kind of collection can be created by the same uniform syntax, writing the collection class name followed by its elements:
- Iterable("x", "y", "z")
- Map("x" -> 24, "y" -> 25, "z" -> 26)
- Set(Color.red, Color.green, Color.blue)
- SortedSet("hello", "world")
- Buffer(x, y, z)
- IndexedSeq(1.0, 2.0)
- LinearSeq(a, b, c)
+{% tabs overview_3 %}
+{% tab 'Scala 2 and 3' for=overview_3 %}
+```scala
+Iterable("x", "y", "z")
+Map("x" -> 24, "y" -> 25, "z" -> 26)
+Set(Color.red, Color.green, Color.blue)
+SortedSet("hello", "world")
+Buffer(x, y, z)
+IndexedSeq(1.0, 2.0)
+LinearSeq(a, b, c)
+```
+{% endtab %}
+{% endtabs %}
The same principle also applies for specific collection implementations, such as:
- List(1, 2, 3)
- HashMap("x" -> 24, "y" -> 25, "z" -> 26)
+{% tabs overview_4 %}
+{% tab 'Scala 2 and 3' for=overview_4 %}
+```scala
+List(1, 2, 3)
+HashMap("x" -> 24, "y" -> 25, "z" -> 26)
+```
+{% endtab %}
+{% endtabs %}
All these collections get displayed with `toString` in the same way they are written above.
All collections support the API provided by `Iterable`, but specialize types wherever this makes sense. For instance the `map` method in class `Iterable` returns another `Iterable` as its result. But this result type is overridden in subclasses. For instance, calling `map` on a `List` yields again a `List`, calling it on a `Set` yields again a `Set` and so on.
- scala> List(1, 2, 3) map (_ + 1)
- res0: List[Int] = List(2, 3, 4)
- scala> Set(1, 2, 3) map (_ * 2)
- res0: Set[Int] = Set(2, 4, 6)
+{% tabs overview_5 %}
+{% tab 'Scala 2 and 3' for=overview_5 %}
+```
+scala> List(1, 2, 3) map (_ + 1)
+res0: List[Int] = List(2, 3, 4)
+scala> Set(1, 2, 3) map (_ * 2)
+res0: Set[Int] = Set(2, 4, 6)
+```
+{% endtab %}
+{% endtabs %}
This behavior which is implemented everywhere in the collections libraries is called the _uniform return type principle_.
diff --git a/_overviews/collections-2.13/performance-characteristics.md b/_overviews/collections-2.13/performance-characteristics.md
index b40deb1e45..ed1885017a 100644
--- a/_overviews/collections-2.13/performance-characteristics.md
+++ b/_overviews/collections-2.13/performance-characteristics.md
@@ -74,7 +74,7 @@ The first table treats sequence types--both immutable and mutable--with the foll
| **apply** | Indexing. |
| **update** | Functional update (with `updated`) for immutable sequences, side-effecting update (with `update` for mutable sequences). |
| **prepend**| Adding an element to the front of the sequence. For immutable sequences, this produces a new sequence. For mutable sequences it modifies the existing sequence. |
-| **append** | Adding an element and the end of the sequence. For immutable sequences, this produces a new sequence. For mutable sequences it modifies the existing sequence. |
+| **append** | Adding an element to the end of the sequence. For immutable sequences, this produces a new sequence. For mutable sequences it modifies the existing sequence. |
| **insert** | Inserting an element at an arbitrary position in the sequence. This is only supported directly for mutable sequences. |
The second table treats mutable and immutable sets and maps with the following operations:
diff --git a/_overviews/collections-2.13/seqs.md b/_overviews/collections-2.13/seqs.md
index 1cd8ebfc7b..cabd0b8a0a 100644
--- a/_overviews/collections-2.13/seqs.md
+++ b/_overviews/collections-2.13/seqs.md
@@ -16,7 +16,7 @@ The [Seq](https://www.scala-lang.org/api/current/scala/collection/Seq.html) trai
The operations on sequences, summarized in the table below, fall into the following categories:
-* **Indexing and length** operations `apply`, `isDefinedAt`, `length`, `indices`, and `lengthCompare`. For a `Seq`, the `apply` operation means indexing; hence a sequence of type `Seq[T]` is a partial function that takes an `Int` argument (an index) and which yields a sequence element of type `T`. In other words `Seq[T]` extends `PartialFunction[Int, T]`. The elements of a sequence are indexed from zero up to the `length` of the sequence minus one. The `length` method on sequences is an alias of the `size` method of general collections. The `lengthCompare` method allows you to compare the lengths of a sequences with an Int even if the sequences has infinite length.
+* **Indexing and length** operations `apply`, `isDefinedAt`, `length`, `indices`, and `lengthCompare`. For a `Seq`, the `apply` operation means indexing; hence a sequence of type `Seq[T]` is a partial function that takes an `Int` argument (an index) and which yields a sequence element of type `T`. In other words `Seq[T]` extends `PartialFunction[Int, T]`. The elements of a sequence are indexed from zero up to the `length` of the sequence minus one. The `length` method on sequences is an alias of the `size` method of general collections. The `lengthCompare` method allows you to compare the lengths of a sequences with an Int or with an `Iterable` even if the sequences has infinite length.
* **Index search operations** `indexOf`, `lastIndexOf`, `indexOfSlice`, `lastIndexOfSlice`, `indexWhere`, `lastIndexWhere`, `segmentLength`, which return the index of an element equal to a given value or matching some predicate.
* **Addition operations** `prepended`, `prependedAll`, `appended`, `appendedAll`, `padTo`, which return new sequences obtained by adding elements at the front or the end of a sequence.
* **Update operations** `updated`, `patch`, which return a new sequence obtained by replacing some elements of the original sequence.
@@ -32,17 +32,17 @@ If a sequence is mutable, it offers in addition a side-effecting `update` method
| WHAT IT IS | WHAT IT DOES |
| ------ | ------ |
| **Indexing and Length:** | |
-| `xs(i)` |(or, written out, `xs apply i`). The element of `xs` at index `i`.|
-| `xs isDefinedAt i` |Tests whether `i` is contained in `xs.indices`.|
+| `xs(i)` |(or, written out, `xs.apply(i)`). The element of `xs` at index `i`.|
+| `xs.isDefinedAt(i)` |Tests whether `i` is contained in `xs.indices`.|
| `xs.length` |The length of the sequence (same as `size`).|
-| `xs lengthCompare n` |Returns `-1` if `xs` is shorter than `n`, `+1` if it is longer, and `0` if it is of length `n`. Works even if the sequence is infinite, for example `LazyList.from(1) lengthCompare 42` returns a positive value.|
+| `xs.lengthCompare(n)` |Returns `-1` if `xs` is shorter than `n`, `+1` if it is longer, and `0` if it is of length `n`. Works even if the sequence is infinite, for example `LazyList.from(1).lengthCompare(42)` returns a positive value.|
| `xs.indices` |The index range of `xs`, extending from `0` to `xs.length - 1`.|
| **Index Search:** | |
-| `xs indexOf x` |The index of the first element in `xs` equal to `x` (several variants exist).|
-| `xs lastIndexOf x` |The index of the last element in `xs` equal to `x` (several variants exist).|
-| `xs indexOfSlice ys` |The first index of `xs` such that successive elements starting from that index form the sequence `ys`.|
-| `xs lastIndexOfSlice ys` |The last index of `xs` such that successive elements starting from that index form the sequence `ys`.|
-| `xs indexWhere p` |The index of the first element in xs that satisfies `p` (several variants exist).|
+| `xs.indexOf(x)` |The index of the first element in `xs` equal to `x` (several variants exist).|
+| `xs.lastIndexOf(x)` |The index of the last element in `xs` equal to `x` (several variants exist).|
+| `xs.indexOfSlice(ys)` |The first index of `xs` such that successive elements starting from that index form the sequence `ys`.|
+| `xs.lastIndexOfSlice(ys)` |The last index of `xs` such that successive elements starting from that index form the sequence `ys`.|
+| `xs.indexWhere(p)` |The index of the first element in xs that satisfies `p` (several variants exist).|
| `xs.segmentLength(p, i)`|The length of the longest uninterrupted segment of elements in `xs`, starting with `xs(i)`, that all satisfy the predicate `p`.|
| **Additions:** | |
| `xs.prepended(x)` or `x +: xs` |A new sequence that consists of `x` prepended to `xs`.|
@@ -56,26 +56,26 @@ If a sequence is mutable, it offers in addition a side-effecting `update` method
| `xs(i) = x` |(or, written out, `xs.update(i, x)`, only available for `mutable.Seq`s). Changes the element of `xs` at index `i` to `x`.|
| **Sorting:** | |
| `xs.sorted` |A new sequence obtained by sorting the elements of `xs` using the standard ordering of the element type of `xs`.|
-| `xs sortWith lt` |A new sequence obtained by sorting the elements of `xs` using `lt` as comparison operation.|
-| `xs sortBy f` |A new sequence obtained by sorting the elements of `xs`. Comparison between two elements proceeds by mapping the function `f` over both and comparing the results.|
+| `xs.sortWith(lt)` |A new sequence obtained by sorting the elements of `xs` using `lt` as comparison operation.|
+| `xs.sortBy(f)` |A new sequence obtained by sorting the elements of `xs`. Comparison between two elements proceeds by mapping the function `f` over both and comparing the results.|
| **Reversals:** | |
| `xs.reverse` |A sequence with the elements of `xs` in reverse order.|
| `xs.reverseIterator` |An iterator yielding all the elements of `xs` in reverse order.|
| **Comparisons:** | |
-| `xs sameElements ys` |A test whether `xs` and `ys` contain the same elements in the same order|
-| `xs startsWith ys` |Tests whether `xs` starts with sequence `ys` (several variants exist).|
-| `xs endsWith ys` |Tests whether `xs` ends with sequence `ys` (several variants exist).|
-| `xs contains x` |Tests whether `xs` has an element equal to `x`.|
-| `xs search x` |Tests whether a sorted sequence `xs` has an element equal to `x`, possibly in a more efficient way than `xs contains x`.|
-| `xs containsSlice ys` |Tests whether `xs` has a contiguous subsequence equal to `ys`.|
-| `(xs corresponds ys)(p)` |Tests whether corresponding elements of `xs` and `ys` satisfy the binary predicate `p`.|
+| `xs.sameElements(ys)` |A test whether `xs` and `ys` contain the same elements in the same order|
+| `xs.startsWith(ys)` |Tests whether `xs` starts with sequence `ys` (several variants exist).|
+| `xs.endsWith(ys)` |Tests whether `xs` ends with sequence `ys` (several variants exist).|
+| `xs.contains(x)` |Tests whether `xs` has an element equal to `x`.|
+| `xs.search(x)` |Tests whether a sorted sequence `xs` has an element equal to `x`, possibly in a more efficient way than `xs.contains(x)`.|
+| `xs.containsSlice(ys)` |Tests whether `xs` has a contiguous subsequence equal to `ys`.|
+| `xs.corresponds(ys)(p)` |Tests whether corresponding elements of `xs` and `ys` satisfy the binary predicate `p`.|
| **Multiset Operations:** | |
-| `xs intersect ys` |The multi-set intersection of sequences `xs` and `ys` that preserves the order of elements in `xs`.|
-| `xs diff ys` |The multi-set difference of sequences `xs` and `ys` that preserves the order of elements in `xs`.|
+| `xs.intersect(ys)` |The multi-set intersection of sequences `xs` and `ys` that preserves the order of elements in `xs`.|
+| `xs.diff(ys)` |The multi-set difference of sequences `xs` and `ys` that preserves the order of elements in `xs`.|
| `xs.distinct` |A subsequence of `xs` that contains no duplicated element.|
-| `xs distinctBy f` |A subsequence of `xs` that contains no duplicated element after applying the transforming function `f`. For instance, `List("foo", "bar", "quux").distinctBy(_.length) == List("foo", "quux")`|
+| `xs.distinctBy(f)` |A subsequence of `xs` that contains no duplicated element after applying the transforming function `f`. For instance, `List("foo", "bar", "quux").distinctBy(_.length) == List("foo", "quux")`|
-Trait [Seq](https://www.scala-lang.org/api/current/scala/collection/Seq.html) has two subtraits [LinearSeq](https://www.scala-lang.org/api/current/scala/collection/LinearSeq.html), and [IndexedSeq](https://www.scala-lang.org/api/current/scala/collection/IndexedSeq.html). These do not add any new operations to the immutable branch, but each offers different performance characteristics: A linear sequence has efficient `head` and `tail` operations, whereas an indexed sequence has efficient `apply`, `length`, and (if mutable) `update` operations. Frequently used linear sequences are `scala.collection.immutable.List` and `scala.collection.immutable.LazyList`. Frequently used indexed sequences are `scala.Array` and `scala.collection.mutable.ArrayBuffer`. The `Vector` class provides an interesting compromise between indexed and linear access. It has both effectively constant time indexing overhead and constant time linear access overhead. Because of this, vectors are a good foundation for mixed access patterns where both indexed and linear accesses are used. You'll learn more on vectors [later](concrete-immutable-collection-classes.html).
+Trait [Seq](https://www.scala-lang.org/api/current/scala/collection/Seq.html) has two subtraits [LinearSeq](https://www.scala-lang.org/api/current/scala/collection/LinearSeq.html), and [IndexedSeq](https://www.scala-lang.org/api/current/scala/collection/IndexedSeq.html). These do not add any new operations to the immutable branch, but each offers different performance characteristics: A linear sequence has efficient `head` and `tail` operations, whereas an indexed sequence has efficient `apply`, `length`, and (if mutable) `update` operations. Frequently used linear sequences are `scala.collection.immutable.List` and `scala.collection.immutable.LazyList`. Frequently used indexed sequences are `scala.Array` and `scala.collection.mutable.ArrayBuffer`. The `Vector` class provides an interesting compromise between indexed and linear access. It has both effectively constant time indexing overhead and constant time linear access overhead. Because of this, vectors are a good foundation for mixed access patterns where both indexed and linear accesses are used. You'll learn more on vectors [later]({% link _overviews/collections-2.13/concrete-immutable-collection-classes.md %}).
On the mutable branch, `IndexedSeq` adds operations for transforming its elements in place (by contrast with
transformation operations such as `map` and `sort`, available on the root `Seq`, which return a new collection
@@ -102,20 +102,20 @@ Two often used implementations of buffers are `ListBuffer` and `ArrayBuffer`. A
| WHAT IT IS | WHAT IT DOES|
| ------ | ------ |
| **Additions:** | |
-| `buf append x` or `buf += x` |Appends element `x` to buffer, and returns `buf` itself as result.|
-| `buf appendAll xs` or`buf ++= xs` |Appends all elements in `xs` to buffer.|
-| `buf prepend x` or `x +=: buf` |Prepends element `x` to buffer.|
-| `buf prependAll xs` or `xs ++=: buf` |Prepends all elements in `xs` to buffer.|
+| `buf.append(x)` or `buf += x` |Appends element `x` to buffer, and returns `buf` itself as result.|
+| `buf.appendAll(xs)` or `buf ++= xs` |Appends all elements in `xs` to buffer.|
+| `buf.prepend(x)` or `x +=: buf` |Prepends element `x` to buffer.|
+| `buf.prependAll(xs)` or `xs ++=: buf` |Prepends all elements in `xs` to buffer.|
| `buf.insert(i, x)` |Inserts element `x` at index `i` in buffer.|
| `buf.insertAll(i, xs)` |Inserts all elements in `xs` at index `i` in buffer.|
| `buf.padToInPlace(n, x)` |Appends element `x` to buffer until it has `n` elements in total.|
| **Removals:** | |
-| `buf subtractOne x` or `buf -= x` |Removes element `x` from buffer.|
-| `buf subtractAll xs` or `buf --= xs` |Removes elements in `xs` from buffer.|
-| `buf remove i` |Removes element at index `i` from buffer.|
+| `buf.subtractOne(x)` or `buf -= x` |Removes element `x` from buffer.|
+| `buf.subtractAll(xs)` or `buf --= xs` |Removes elements in `xs` from buffer.|
+| `buf.remove(i)` |Removes element at index `i` from buffer.|
| `buf.remove(i, n)` |Removes `n` elements starting at index `i` from buffer.|
-| `buf trimStart n` |Removes first `n` elements from buffer.|
-| `buf trimEnd n` |Removes last `n` elements from buffer.|
+| `buf.trimStart(n)` |Removes first `n` elements from buffer.|
+| `buf.trimEnd(n)` |Removes last `n` elements from buffer.|
| `buf.clear()` |Removes all elements from buffer.|
| **Replacement:** | |
| `buf.patchInPlace(i, xs, n)` |Replaces (at most) `n` elements of buffer by elements in `xs`, starting from index `i` in buffer.|
diff --git a/_overviews/collections-2.13/sets.md b/_overviews/collections-2.13/sets.md
index 96984d34f3..a57814ffd1 100644
--- a/_overviews/collections-2.13/sets.md
+++ b/_overviews/collections-2.13/sets.md
@@ -18,14 +18,18 @@ permalink: /overviews/collections-2.13/:title.html
For example:
-
- scala> val fruit = Set("apple", "orange", "peach", "banana")
- fruit: scala.collection.immutable.Set[java.lang.String] = Set(apple, orange, peach, banana)
- scala> fruit("peach")
- res0: Boolean = true
- scala> fruit("potato")
- res1: Boolean = false
-
+{% tabs sets_1 %}
+{% tab 'Scala 2 and 3' for=sets_1 %}
+```scala
+scala> val fruit = Set("apple", "orange", "peach", "banana")
+fruit: scala.collection.immutable.Set[java.lang.String] = Set(apple, orange, peach, banana)
+scala> fruit("peach")
+res0: Boolean = true
+scala> fruit("potato")
+res1: Boolean = false
+```
+{% endtab %}
+{% endtabs %}
* **Additions** `incl` and `concat` (or `+` and `++`, respectively), which add one or more elements to a set, yielding a new set.
* **Removals** `excl` and `removedAll` (or `-` and `--`, respectively), which remove one or more elements from a set, yielding a new set.
@@ -85,22 +89,33 @@ The operation `s += elem` adds `elem` to the set `s` as a side effect, and retur
The choice of the method names `+=` and `-=` means that very similar code can work with either mutable or immutable sets. Consider first the following REPL dialogue which uses an immutable set `s`:
- scala> var s = Set(1, 2, 3)
- s: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
- scala> s += 4
- scala> s -= 2
- scala> s
- res2: scala.collection.immutable.Set[Int] = Set(1, 3, 4)
+{% tabs sets_2 %}
+{% tab 'Scala 2 and 3' for=sets_2 %}
+```scala
+scala> var s = Set(1, 2, 3)
+s: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
+scala> s += 4
+scala> s -= 2
+scala> s
+res2: scala.collection.immutable.Set[Int] = Set(1, 3, 4)
+```
+{% endtab %}
+{% endtabs %}
We used `+=` and `-=` on a `var` of type `immutable.Set`. A statement such as `s += 4` is an abbreviation for `s = s + 4`. So this invokes the addition method `+` on the set `s` and then assigns the result back to the `s` variable. Consider now an analogous interaction with a mutable set.
-
- scala> val s = collection.mutable.Set(1, 2, 3)
- s: scala.collection.mutable.Set[Int] = Set(1, 2, 3)
- scala> s += 4
- res3: s.type = Set(1, 4, 2, 3)
- scala> s -= 2
- res4: s.type = Set(1, 4, 3)
+{% tabs sets_3 %}
+{% tab 'Scala 2 and 3' for=sets_3 %}
+```scala
+scala> val s = collection.mutable.Set(1, 2, 3)
+s: scala.collection.mutable.Set[Int] = Set(1, 2, 3)
+scala> s += 4
+res3: s.type = Set(1, 4, 2, 3)
+scala> s -= 2
+res4: s.type = Set(1, 4, 3)
+```
+{% endtab %}
+{% endtabs %}
The end effect is very similar to the previous interaction; we start with a `Set(1, 2, 3)` and end up with a `Set(1, 3, 4)`. However, even though the statements look the same as before, they do something different. `s += 4` now invokes the `+=` method on the mutable set value `s`, changing the set in place. Likewise, `s -= 2` now invokes the `-=` method on the same set.
@@ -108,7 +123,7 @@ Comparing the two interactions shows an important principle. You often can repla
Mutable sets also provide add and remove as variants of `+=` and `-=`. The difference is that `add` and `remove` return a Boolean result indicating whether the operation had an effect on the set.
-The current default implementation of a mutable set uses a hashtable to store the set's elements. The default implementation of an immutable set uses a representation that adapts to the number of elements of the set. An empty set is represented by just a singleton object. Sets of sizes up to four are represented by a single object that stores all elements as fields. Beyond that size, immutable sets are implemented as [Compressed Hash-Array Mapped Prefix-tree](concrete-immutable-collection-classes.html).
+The current default implementation of a mutable set uses a hashtable to store the set's elements. The default implementation of an immutable set uses a representation that adapts to the number of elements of the set. An empty set is represented by just a singleton object. Sets of sizes up to four are represented by a single object that stores all elements as fields. Beyond that size, immutable sets are implemented as [Compressed Hash-Array Mapped Prefix-tree]({% link _overviews/collections-2.13/concrete-immutable-collection-classes.md %}).
A consequence of these representation choices is that, for sets of small sizes (say up to 4), immutable sets are usually more compact and also more efficient than mutable sets. So, if you expect the size of a set to be small, try making it immutable.
@@ -120,34 +135,63 @@ A [SortedSet](https://www.scala-lang.org/api/current/scala/collection/SortedSet.
To create an empty [TreeSet](https://www.scala-lang.org/api/current/scala/collection/immutable/TreeSet.html), you could first specify the desired ordering:
- scala> val myOrdering = Ordering.fromLessThan[String](_ > _)
- myOrdering: scala.math.Ordering[String] = ...
+{% tabs sorted-sets_1 %}
+{% tab 'Scala 2 and 3' for=sorted-sets_1 %}
+```scala
+scala> val myOrdering = Ordering.fromLessThan[String](_ > _)
+myOrdering: scala.math.Ordering[String] = ...
+```
+{% endtab %}
+{% endtabs %}
Then, to create an empty tree set with that ordering, use:
- scala> TreeSet.empty(myOrdering)
- res1: scala.collection.immutable.TreeSet[String] = TreeSet()
-
-Or you can leave out the ordering argument but give an element type or the empty set. In that case, the default ordering on the element type will be used.
-
- scala> TreeSet.empty[String]
- res2: scala.collection.immutable.TreeSet[String] = TreeSet()
+{% tabs sorted-sets_2 %}
+{% tab 'Scala 2 and 3' for=sorted-sets_2 %}
+```scala
+scala> TreeSet.empty(myOrdering)
+res1: scala.collection.immutable.TreeSet[String] = TreeSet()
+```
+{% endtab %}
+{% endtabs %}
+
+Or you can leave out the ordering argument but give an element type for the empty set. In that case, the default ordering on the element type will be used.
+
+{% tabs sorted-sets_3 %}
+{% tab 'Scala 2 and 3' for=sorted-sets_3 %}
+```scala
+scala> TreeSet.empty[String]
+res2: scala.collection.immutable.TreeSet[String] = TreeSet()
+```
+{% endtab %}
+{% endtabs %}
If you create new sets from a tree-set (for instance by concatenation or filtering) they will keep the same ordering as the original set. For instance,
- scala> res2 + "one" + "two" + "three" + "four"
- res3: scala.collection.immutable.TreeSet[String] = TreeSet(four, one, three, two)
+{% tabs sorted-sets_4 %}
+{% tab 'Scala 2 and 3' for=sorted-sets_4 %}
+```scala
+scala> res2 + "one" + "two" + "three" + "four"
+res3: scala.collection.immutable.TreeSet[String] = TreeSet(four, one, three, two)
+```
+{% endtab %}
+{% endtabs %}
Sorted sets also support ranges of elements. For instance, the `range` method returns all elements from a starting element up to, but excluding, an end element. Or, the `from` method returns all elements greater or equal than a starting element in the set's ordering. The result of calls to both methods is again a sorted set. Examples:
- scala> res3.range("one", "two")
- res4: scala.collection.immutable.TreeSet[String] = TreeSet(one, three)
- scala> res3 rangeFrom "three"
- res5: scala.collection.immutable.TreeSet[String] = TreeSet(three, two)
-
+{% tabs sorted-sets_5 %}
+{% tab 'Scala 2 and 3' for=sorted-sets_5 %}
+```scala
+scala> res3.range("one", "two")
+res4: scala.collection.immutable.TreeSet[String] = TreeSet(one, three)
+scala> res3 rangeFrom "three"
+res5: scala.collection.immutable.TreeSet[String] = TreeSet(three, two)
+```
+{% endtab %}
+{% endtabs %}
### Bitsets ###
-Bitsets are sets of non-negative integer elements that are implemented in one or more words of packed bits. The internal representation of a [BitSet](https://www.scala-lang.org/api/current/scala/collection/BitSet.html) uses an array of `Long`s. The first `Long` covers elements from 0 to 63, the second from 64 to 127, and so on (Immutable bitsets of elements in the range of 0 to 127 optimize the array away and store the bits directly in a one or two `Long` fields.) For every `Long`, each of its 64 bits is set to 1 if the corresponding element is contained in the set, and is unset otherwise. It follows that the size of a bitset depends on the largest integer that's stored in it. If `N` is that largest integer, then the size of the set is `N/64` `Long` words, or `N/8` bytes, plus a small number of extra bytes for status information.
+Bitsets are sets of non-negative integer elements that are implemented in one or more words of packed bits. The internal representation of a [BitSet](https://www.scala-lang.org/api/current/scala/collection/BitSet.html) uses an array of `Long`s. The first `Long` covers elements from 0 to 63, the second from 64 to 127, and so on (Immutable bitsets of elements in the range of 0 to 127 optimize the array away and store the bits directly in a one or two `Long` fields). For every `Long`, each of its 64 bits is set to 1 if the corresponding element is contained in the set, and is unset otherwise. It follows that the size of a bitset depends on the largest integer that's stored in it. If `N` is that largest integer, then the size of the set is `N/64` `Long` words, or `N/8` bytes, plus a small number of extra bytes for status information.
Bitsets are hence more compact than other sets if they contain many small elements. Another advantage of bitsets is that operations such as membership test with `contains`, or element addition and removal with `+=` and `-=` are all extremely efficient.
diff --git a/_overviews/collections-2.13/strings.md b/_overviews/collections-2.13/strings.md
index 485410df49..aebe244304 100644
--- a/_overviews/collections-2.13/strings.md
+++ b/_overviews/collections-2.13/strings.md
@@ -14,17 +14,30 @@ permalink: /overviews/collections-2.13/:title.html
Like arrays, strings are not directly sequences, but they can be converted to them, and they also support all sequence operations on strings. Here are some examples of operations you can invoke on strings.
- scala> val str = "hello"
- str: java.lang.String = hello
- scala> str.reverse
- res6: String = olleh
- scala> str.map(_.toUpper)
- res7: String = HELLO
- scala> str drop 3
- res8: String = lo
- scala> str.slice(1, 4)
- res9: String = ell
- scala> val s: Seq[Char] = str
- s: Seq[Char] = hello
+{% tabs strings_1 %}
+{% tab 'Scala 2 and 3' for=strings_1 %}
+
+```scala
+scala> val str = "hello"
+val str: java.lang.String = hello
+
+scala> str.reverse
+val res6: String = olleh
+
+scala> str.map(_.toUpper)
+val res7: String = HELLO
+
+scala> str.drop(3)
+val res8: String = lo
+
+scala> str.slice(1, 4)
+val res9: String = ell
+
+scala> val s: Seq[Char] = str
+val s: Seq[Char] = hello
+```
+
+{% endtab %}
+{% endtabs %}
These operations are supported by two implicit conversions. The first, low-priority conversion maps a `String` to a `WrappedString`, which is a subclass of `immutable.IndexedSeq`, This conversion got applied in the last line above where a string got converted into a Seq. The other, high-priority conversion maps a string to a `StringOps` object, which adds all methods on immutable sequences to strings. This conversion was implicitly inserted in the method calls of `reverse`, `map`, `drop`, and `slice` in the example above.
diff --git a/_overviews/collections-2.13/trait-iterable.md b/_overviews/collections-2.13/trait-iterable.md
index edc2ef2b1f..21b28e2282 100644
--- a/_overviews/collections-2.13/trait-iterable.md
+++ b/_overviews/collections-2.13/trait-iterable.md
@@ -14,7 +14,13 @@ permalink: /overviews/collections-2.13/:title.html
At the top of the collection hierarchy is trait `Iterable`. All methods in this trait are defined in terms of an abstract method, `iterator`, which yields the collection's elements one by one.
- def iterator: Iterator[A]
+{% tabs trait-iterable_1 %}
+{% tab 'Scala 2 and 3' for=trait-iterable_1 %}
+```scala
+def iterator: Iterator[A]
+```
+{% endtab %}
+{% endtabs %}
Collection classes that implement `Iterable` just need to define this method; all other methods can be inherited from `Iterable`.
@@ -31,119 +37,124 @@ Collection classes that implement `Iterable` just need to define this method; al
* **Element tests** `exists`, `forall`, `count` which test collection elements with a given predicate.
* **Folds** `foldLeft`, `foldRight`, `reduceLeft`, `reduceRight` which apply a binary operation to successive elements.
* **Specific folds** `sum`, `product`, `min`, `max`, which work on collections of specific types (numeric or comparable).
-* **String** operations `mkString`, `addString`, `className`, which give alternative ways of converting a collection to a string.
-* **View** operation: A view is a collection that's evaluated lazily. You'll learn more about views in [later](views.html).
+* **String** operations `mkString` and `addString` which give alternative ways of converting a collection to a string.
+* **View** operation: A view is a collection that's evaluated lazily. You'll learn more about views in [later]({% link _overviews/collections-2.13/views.md %}).
Two more methods exist in `Iterable` that return iterators: `grouped` and `sliding`. These iterators, however, do not return single elements but whole subsequences of elements of the original collection. The maximal size of these subsequences is given as an argument to these methods. The `grouped` method returns its elements in "chunked" increments, where `sliding` yields a sliding "window" over the elements. The difference between the two should become clear by looking at the following REPL interaction:
- scala> val xs = List(1, 2, 3, 4, 5)
- xs: List[Int] = List(1, 2, 3, 4, 5)
- scala> val git = xs grouped 3
- git: Iterator[List[Int]] = non-empty iterator
- scala> git.next()
- res3: List[Int] = List(1, 2, 3)
- scala> git.next()
- res4: List[Int] = List(4, 5)
- scala> val sit = xs sliding 3
- sit: Iterator[List[Int]] = non-empty iterator
- scala> sit.next()
- res5: List[Int] = List(1, 2, 3)
- scala> sit.next()
- res6: List[Int] = List(2, 3, 4)
- scala> sit.next()
- res7: List[Int] = List(3, 4, 5)
+{% tabs trait-iterable_2 %}
+{% tab 'Scala 2 and 3' for=trait-iterable_2 %}
+```
+scala> val xs = List(1, 2, 3, 4, 5)
+xs: List[Int] = List(1, 2, 3, 4, 5)
+scala> val git = xs grouped 3
+git: Iterator[List[Int]] = non-empty iterator
+scala> git.next()
+res3: List[Int] = List(1, 2, 3)
+scala> git.next()
+res4: List[Int] = List(4, 5)
+scala> val sit = xs sliding 3
+sit: Iterator[List[Int]] = non-empty iterator
+scala> sit.next()
+res5: List[Int] = List(1, 2, 3)
+scala> sit.next()
+res6: List[Int] = List(2, 3, 4)
+scala> sit.next()
+res7: List[Int] = List(3, 4, 5)
+```
+{% endtab %}
+{% endtabs %}
### Operations in Class Iterable ###
-| WHAT IT IS | WHAT IT DOES |
-| ------ | ------ |
-| **Abstract Method:** | |
-| `xs.iterator` |An `iterator` that yields every element in `xs`.|
-| **Other Iterators:** | |
-| `xs foreach f` |Executes function `f` for every element of `xs`.|
-| `xs grouped size` |An iterator that yields fixed-sized "chunks" of this collection.|
-| `xs sliding size` |An iterator that yields a sliding fixed-sized window of elements in this collection.|
-| **Addition:** | |
-| `xs concat ys` (or `xs ++ ys`) |A collection consisting of the elements of both `xs` and `ys`. `ys` is a [IterableOnce](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/IterableOnce.html) collection, i.e., either an [Iterable](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterable.html) or an [Iterator](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterator.html).|
-| **Maps:** | |
-| `xs map f` |The collection obtained from applying the function f to every element in `xs`.|
-| `xs flatMap f` |The collection obtained from applying the collection-valued function `f` to every element in `xs` and concatenating the results.|
-| `xs collect f` |The collection obtained from applying the partial function `f` to every element in `xs` for which it is defined and collecting the results.|
-| **Conversions:** | |
-| `xs.to(SortedSet)` | Generic conversion operation that takes a collection factory as parameter. |
-| `xs.toList` |Converts the collection to a list. |
-| `xs.toVector` |Converts the collection to a vector. |
-| `xs.toMap` |Converts the collection of key/value pairs to a map. If the collection does not have pairs as elements, calling this operation results in a static type error.|
-| `xs.toSet` |Converts the collection to a set. |
-| `xs.toSeq` |Converts the collection to a sequence. |
-| `xs.toIndexedSeq` |Converts the collection to an indexed sequence. |
-| `xs.toBuffer` |Converts the collection to a buffer. |
-| `xs.toArray` |Converts the collection to an array. |
-| **Copying:** | |
-| `xs copyToArray(arr, s, n)`|Copies at most `n` elements of the collection to array `arr` starting at index `s`. The last two arguments are optional.|
-| **Size info:** | |
-| `xs.isEmpty` |Tests whether the collection is empty. |
-| `xs.nonEmpty` |Tests whether the collection contains elements. |
-| `xs.size` |The number of elements in the collection. |
-| `xs.knownSize` |The number of elements, if this one takes constant time to compute, otherwise `-1`. |
-| `xs.sizeCompare(ys)` |Returns a negative value if `xs` is shorter than the `ys` collection, a positive value if it is longer, and `0` if they have the same size. Works even if the collection is infinite, for example `LazyList.from(1) sizeCompare List(1, 2)` returns a positive value. |
-| `xs.sizeCompare(n)` |Returns a negative value if `xs` is shorter than `n`, a positive value if it is longer, and `0` if it is of size `n`. Works even if the collection is infinite, for example `LazyList.from(1) sizeCompare 42` returns a positive value. |
-| `xs.sizeIs < 42`, `xs.sizeIs != 42`, etc. |Provides a more convenient syntax for `xs.sizeCompare(42) < 0`, `xs.sizeCompare(42) != 0`, etc., respectively.|
-| **Element Retrieval:** | |
-| `xs.head` |The first element of the collection (or, some element, if no order is defined).|
-| `xs.headOption` |The first element of `xs` in an option value, or None if `xs` is empty.|
-| `xs.last` |The last element of the collection (or, some element, if no order is defined).|
-| `xs.lastOption` |The last element of `xs` in an option value, or None if `xs` is empty.|
-| `xs find p` |An option containing the first element in `xs` that satisfies `p`, or `None` if no element qualifies.|
-| **Subcollections:** | |
-| `xs.tail` |The rest of the collection except `xs.head`. |
-| `xs.init` |The rest of the collection except `xs.last`. |
-| `xs.slice(from, to)` |A collection consisting of elements in some index range of `xs` (from `from` up to, and excluding `to`).|
-| `xs take n` |A collection consisting of the first `n` elements of `xs` (or, some arbitrary `n` elements, if no order is defined).|
-| `xs drop n` |The rest of the collection except `xs take n`.|
-| `xs takeWhile p` |The longest prefix of elements in the collection that all satisfy `p`.|
-| `xs dropWhile p` |The collection without the longest prefix of elements that all satisfy `p`.|
-| `xs takeRight n` |A collection consisting of the last `n` elements of `xs` (or, some arbitrary `n` elements, if no order is defined).|
-| `xs dropRight n` |The rest of the collection except `xs takeRight n`.|
-| `xs filter p` |The collection consisting of those elements of xs that satisfy the predicate `p`.|
-| `xs withFilter p` |A non-strict filter of this collection. Subsequent calls to `map`, `flatMap`, `foreach`, and `withFilter` will only apply to those elements of `xs` for which the condition `p` is true.|
-| `xs filterNot p` |The collection consisting of those elements of `xs` that do not satisfy the predicate `p`.|
-| **Subdivisions:** | |
-| `xs splitAt n` |Split `xs` at a position, giving the pair of collections `(xs take n, xs drop n)`.|
-| `xs span p` |Split `xs` according to a predicate, giving the pair of collections `(xs takeWhile p, xs.dropWhile p)`.|
-| `xs partition p` |Split `xs` into a pair of collections; one with elements that satisfy the predicate `p`, the other with elements that do not, giving the pair of collections `(xs filter p, xs.filterNot p)`|
-| `xs groupBy f` |Partition `xs` into a map of collections according to a discriminator function `f`.|
-| `xs.groupMap(f)(g)`|Partition `xs` into a map of collections according to a discriminator function `f`, and applies the transformation function `g` to each element in a group.|
-| `xs.groupMapReduce(f)(g)(h)`|Partition `xs` according to a discriminator function `f`, and then combine the results of applying the function `g` to each element in a group using the `h` function.|
-| **Element Conditions:** | |
-| `xs forall p` |A boolean indicating whether the predicate `p` holds for all elements of `xs`.|
-| `xs exists p` |A boolean indicating whether the predicate `p` holds for some element in `xs`.|
-| `xs count p` |The number of elements in `xs` that satisfy the predicate `p`.|
-| **Folds:** | |
-| `xs.foldLeft(z)(op)` |Apply binary operation `op` between successive elements of `xs`, going left to right and starting with `z`.|
-| `xs.foldRight(z)(op)` |Apply binary operation `op` between successive elements of `xs`, going right to left and ending with `z`.|
-| `xs reduceLeft op` |Apply binary operation `op` between successive elements of non-empty collection `xs`, going left to right.|
-| `xs reduceRight op` |Apply binary operation `op` between successive elements of non-empty collection `xs`, going right to left.|
-| **Specific Folds:** | |
-| `xs.sum` |The sum of the numeric element values of collection `xs`.|
-| `xs.product` |The product of the numeric element values of collection `xs`.|
-| `xs.min` |The minimum of the ordered element values of collection `xs`.|
-| `xs.max` |The maximum of the ordered element values of collection `xs`.|
-| `xs.minOption` |Like `min` but returns `None` if `xs` is empty.|
-| `xs.maxOption` |Like `max` but returns `None` if `xs` is empty.|
-| **Strings:** | |
-| `xs.addString(b, start, sep, end)`|Adds a string to `StringBuilder` `b` that shows all elements of `xs` between separators `sep` enclosed in strings `start` and `end`. `start`, `sep`, `end` are all optional.|
-| `xs.mkString(start, sep, end)`|Converts the collection to a string that shows all elements of `xs` between separators `sep` enclosed in strings `start` and `end`. `start`, `sep`, `end` are all optional.|
-| `xs.stringPrefix` |The collection name at the beginning of the string returned from `xs.toString`.|
-| **Zippers:** | |
-| `xs zip ys` |A collection of pairs of corresponding elements from `xs` and `ys`.|
-| `xs.zipAll(ys, x, y)` |A collection of pairs of corresponding elements from `xs` and `ys`, where the shorter sequence is extended to match the longer one by appending elements `x` or `y`.|
-| `xs.zipWithIndex` |An collection of pairs of elements from `xs` with their indices.|
-| **Views:** | |
-| `xs.view` |Produces a view over `xs`.|
+| WHAT IT IS | WHAT IT DOES |
+|-------------------------------------------| ------ |
+| **Abstract Method:** | |
+| `xs.iterator` |An `iterator` that yields every element in `xs`.|
+| **Other Iterators:** | |
+| `xs.foreach(f)` |Executes function `f` for every element of `xs`.|
+| `xs.grouped(size)` |An iterator that yields fixed-sized "chunks" of this collection.|
+| `xs.sliding(size)` |An iterator that yields a sliding fixed-sized window of elements in this collection.|
+| **Addition:** | |
+| `xs.concat(ys)` (or `xs ++ ys`) |A collection consisting of the elements of both `xs` and `ys`. `ys` is a [IterableOnce](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/IterableOnce.html) collection, i.e., either an [Iterable](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterable.html) or an [Iterator](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterator.html).|
+| **Maps:** | |
+| `xs.map(f)` |The collection obtained from applying the function f to every element in `xs`.|
+| `xs.flatMap(f)` |The collection obtained from applying the collection-valued function `f` to every element in `xs` and concatenating the results.|
+| `xs.collect(f)` |The collection obtained from applying the partial function `f` to every element in `xs` for which it is defined and collecting the results.|
+| **Conversions:** | |
+| `xs.to(SortedSet)` | Generic conversion operation that takes a collection factory as parameter. |
+| `xs.toList` |Converts the collection to a list. |
+| `xs.toVector` |Converts the collection to a vector. |
+| `xs.toMap` |Converts the collection of key/value pairs to a map. If the collection does not have pairs as elements, calling this operation results in a static type error.|
+| `xs.toSet` |Converts the collection to a set. |
+| `xs.toSeq` |Converts the collection to a sequence. |
+| `xs.toIndexedSeq` |Converts the collection to an indexed sequence. |
+| `xs.toBuffer` |Converts the collection to a buffer. |
+| `xs.toArray` |Converts the collection to an array. |
+| **Copying:** | |
+| `xs copyToArray(arr, s, n)` |Copies at most `n` elements of the collection to array `arr` starting at index `s`. The last two arguments are optional.|
+| **Size info:** | |
+| `xs.isEmpty` |Tests whether the collection is empty. |
+| `xs.nonEmpty` |Tests whether the collection contains elements. |
+| `xs.size` |The number of elements in the collection. |
+| `xs.knownSize` |The number of elements, if this one takes constant time to compute, otherwise `-1`. |
+| `xs.sizeCompare(ys)` |Returns a negative value if `xs` is shorter than the `ys` collection, a positive value if it is longer, and `0` if they have the same size. Works even if the collection is infinite, for example `LazyList.from(1) sizeCompare List(1, 2)` returns a positive value. |
+| `xs.sizeCompare(n)` |Returns a negative value if `xs` is shorter than `n`, a positive value if it is longer, and `0` if it is of size `n`. Works even if the collection is infinite, for example `LazyList.from(1) sizeCompare 42` returns a positive value. |
+| `xs.sizeIs < 42`, `xs.sizeIs != 42`, etc. |Provides a more convenient syntax for `xs.sizeCompare(42) < 0`, `xs.sizeCompare(42) != 0`, etc., respectively.|
+| **Element Retrieval:** | |
+| `xs.head` |The first element of the collection (or, some element, if no order is defined).|
+| `xs.headOption` |The first element of `xs` in an option value, or None if `xs` is empty.|
+| `xs.last` |The last element of the collection (or, some element, if no order is defined).|
+| `xs.lastOption` |The last element of `xs` in an option value, or None if `xs` is empty.|
+| `xs.find(p)` |An option containing the first element in `xs` that satisfies `p`, or `None` if no element qualifies.|
+| **Subcollections:** | |
+| `xs.tail` |The rest of the collection except `xs.head`. |
+| `xs.init` |The rest of the collection except `xs.last`. |
+| `xs.slice(from, to)` |A collection consisting of elements in some index range of `xs` (from `from` up to, and excluding `to`).|
+| `xs.take(n)` |A collection consisting of the first `n` elements of `xs` (or, some arbitrary `n` elements, if no order is defined).|
+| `xs.drop(n)` |The rest of the collection except `xs.take(n)`.|
+| `xs.takeWhile(p)` |The longest prefix of elements in the collection that all satisfy `p`.|
+| `xs.dropWhile(p)` |The collection without the longest prefix of elements that all satisfy `p`.|
+| `xs.takeRight(n)` |A collection consisting of the last `n` elements of `xs` (or, some arbitrary `n` elements, if no order is defined).|
+| `xs.dropRight(n)` |The rest of the collection except `xs.takeRight(n)`.|
+| `xs.filter(p)` |The collection consisting of those elements of xs that satisfy the predicate `p`.|
+| `xs.withFilter(p)` |A non-strict filter of this collection. Subsequent calls to `map`, `flatMap`, `foreach`, and `withFilter` will only apply to those elements of `xs` for which the condition `p` is true.|
+| `xs.filterNot(p)` |The collection consisting of those elements of `xs` that do not satisfy the predicate `p`.|
+| **Subdivisions:** | |
+| `xs.splitAt(n)` |Split `xs` at a position, giving the pair of collections `(xs take n, xs drop n)`.|
+| `xs.span(p)` |Split `xs` according to a predicate, giving the pair of collections `(xs takeWhile p, xs.dropWhile p)`.|
+| `xs.partition(p)` |Split `xs` into a pair of collections; one with elements that satisfy the predicate `p`, the other with elements that do not, giving the pair of collections `(xs filter p, xs.filterNot p)`|
+| `xs.groupBy(f)` |Partition `xs` into a map of collections according to a discriminator function `f`.|
+| `xs.groupMap(f)(g)` |Partition `xs` into a map of collections according to a discriminator function `f`, and applies the transformation function `g` to each element in a group.|
+| `xs.groupMapReduce(f)(g)(h)` |Partition `xs` according to a discriminator function `f`, and then combine the results of applying the function `g` to each element in a group using the `h` function.|
+| **Element Conditions:** | |
+| `xs.forall(p)` |A boolean indicating whether the predicate `p` holds for all elements of `xs`.|
+| `xs.exists(p)` |A boolean indicating whether the predicate `p` holds for some element in `xs`.|
+| `xs.count(p)` |The number of elements in `xs` that satisfy the predicate `p`.|
+| **Folds:** | |
+| `xs.foldLeft(z)(op)` |Apply binary operation `op` between successive elements of `xs`, going left to right and starting with `z`.|
+| `xs.foldRight(z)(op)` |Apply binary operation `op` between successive elements of `xs`, going right to left and starting with `z`.|
+| `xs.reduceLeft(op)` |Apply binary operation `op` between successive elements of non-empty collection `xs`, going left to right.|
+| `xs.reduceRight(op)` |Apply binary operation `op` between successive elements of non-empty collection `xs`, going right to left.|
+| **Specific Folds:** | |
+| `xs.sum` |The sum of the numeric element values of collection `xs`.|
+| `xs.product` |The product of the numeric element values of collection `xs`.|
+| `xs.min` |The minimum of the ordered element values of collection `xs`.|
+| `xs.max` |The maximum of the ordered element values of collection `xs`.|
+| `xs.minOption` |Like `min` but returns `None` if `xs` is empty.|
+| `xs.maxOption` |Like `max` but returns `None` if `xs` is empty.|
+| **Strings:** | |
+| `xs.addString(b, start, sep, end)` |Adds a string to `StringBuilder` `b` that shows all elements of `xs` between separators `sep` enclosed in strings `start` and `end`. `start`, `sep`, `end` are all optional.|
+| `xs.mkString(start, sep, end)` |Converts the collection to a string that shows all elements of `xs` between separators `sep` enclosed in strings `start` and `end`. `start`, `sep`, `end` are all optional.|
+| **Zippers:** | |
+| `xs.zip(ys)` |A collection of pairs of corresponding elements from `xs` and `ys`.|
+| `xs.zipAll(ys, x, y)` |A collection of pairs of corresponding elements from `xs` and `ys`, where the shorter sequence is extended to match the longer one by appending elements `x` or `y`.|
+| `xs.zipWithIndex` |An collection of pairs of elements from `xs` with their indices.|
+| **Views:** | |
+| `xs.view` |Produces a view over `xs`.|
In the inheritance hierarchy below `Iterable` you find three traits: [Seq](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Seq.html), [Set](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Set.html), and [Map](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Map.html). `Seq` and `Map` implement the [PartialFunction](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/PartialFunction.html) trait with its `apply` and `isDefinedAt` methods, each implemented differently. `Set` gets its `apply` method from [SetOps](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/SetOps.html).
-For sequences, `apply` is positional indexing, where elements are always numbered from `0`. That is, `Seq(1, 2, 3)(1)` gives `2`. For sets, `apply` is a membership test. For instance, `Set('a', 'b', 'c')('b')` gives `true` whereas `Set()('a')` gives `false`. Finally for maps, `apply` is a selection. For instance, `Map('a' -> 1, 'b' -> 10, 'c' -> 100)('b')` gives `10`.
+For sequences, `apply` is positional indexing, where elements are always numbered from `0`. That is, `Seq(1, 2, 3)(1)` gives `2`. For sets, `apply` is a membership test. For instance, `Set('a', 'b', 'c')('b')` gives `true` whereas `Set()('a')` gives `false`. Finally, for maps, `apply` is a selection. For instance, `Map('a' -> 1, 'b' -> 10, 'c' -> 100)('b')` gives `10`.
In the following, we will explain each of the three kinds of collections in more detail.
diff --git a/_overviews/collections-2.13/views.md b/_overviews/collections-2.13/views.md
index 0c094bb38e..6b0052c5e5 100644
--- a/_overviews/collections-2.13/views.md
+++ b/_overviews/collections-2.13/views.md
@@ -18,11 +18,23 @@ There are two principal ways to implement transformers. One is _strict_, that is
As an example of a non-strict transformer consider the following implementation of a lazy map operation:
- def lazyMap[T, U](coll: Iterable[T], f: T => U) = new Iterable[U] {
- def iterator = coll.iterator map f
- }
-
-Note that `lazyMap` constructs a new `Iterable` without stepping through all elements of the given collection `coll`. The given function `f` is instead applied to the elements of the new collection's `iterator` as they are demanded.
+{% tabs views_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=views_1 %}
+```scala mdoc
+def lazyMap[T, U](iter: Iterable[T], f: T => U) = new Iterable[U] {
+ def iterator = iter.iterator.map(f)
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=views_1 %}
+```scala
+def lazyMap[T, U](iter: Iterable[T], f: T => U) = new Iterable[U]:
+ def iterator = iter.iterator.map(f)
+```
+{% endtab %}
+{% endtabs %}
+
+Note that `lazyMap` constructs a new `Iterable` without stepping through all elements of the given collection `iter`. The given function `f` is instead applied to the elements of the new collection's `iterator` as they are demanded.
Scala collections are by default strict in all their transformers, except for `LazyList`, which implements all its transformer methods lazily. However, there is a systematic way to turn every collection into a lazy one and _vice versa_, which is based on collection views. A _view_ is a special kind of collection that represents some base collection, but implements all transformers lazily.
@@ -30,42 +42,103 @@ To go from a collection to its view, you can use the `view` method on the collec
Let's see an example. Say you have a vector of Ints over which you want to map two functions in succession:
- scala> val v = Vector(1 to 10: _*)
- v: scala.collection.immutable.Vector[Int] =
- Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
- scala> v map (_ + 1) map (_ * 2)
- res5: scala.collection.immutable.Vector[Int] =
- Vector(4, 6, 8, 10, 12, 14, 16, 18, 20, 22)
+{% tabs views_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=views_2 %}
+
+```scala
+scala> val v = Vector(1 to 10: _*)
+val v: scala.collection.immutable.Vector[Int] =
+ Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+
+scala> v.map(_ + 1).map(_ * 2)
+val res5: scala.collection.immutable.Vector[Int] =
+ Vector(4, 6, 8, 10, 12, 14, 16, 18, 20, 22)
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=views_2 %}
+
+```scala
+scala> val v = Vector((1 to 10)*)
+val v: scala.collection.immutable.Vector[Int] =
+ Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+
+scala> v.map(_ + 1).map(_ * 2)
+val res5: scala.collection.immutable.Vector[Int] =
+ Vector(4, 6, 8, 10, 12, 14, 16, 18, 20, 22)
+```
+
+{% endtab %}
+{% endtabs %}
In the last statement, the expression `v map (_ + 1)` constructs a new vector which is then transformed into a third vector by the second call to `map (_ * 2)`. In many situations, constructing the intermediate result from the first call to map is a bit wasteful. In the example above, it would be faster to do a single map with the composition of the two functions `(_ + 1)` and `(_ * 2)`. If you have the two functions available in the same place you can do this by hand. But quite often, successive transformations of a data structure are done in different program modules. Fusing those transformations would then undermine modularity. A more general way to avoid the intermediate results is by turning the vector first into a view, then applying all transformations to the view, and finally forcing the view to a vector:
- scala> (v.view map (_ + 1) map (_ * 2)).to(Vector)
- res12: scala.collection.immutable.Vector[Int] =
- Vector(4, 6, 8, 10, 12, 14, 16, 18, 20, 22)
+{% tabs views_3 %}
+{% tab 'Scala 2 and 3' for=views_3 %}
+
+```scala
+scala> val w = v.view.map(_ + 1).map(_ * 2).to(Vector)
+val w: scala.collection.immutable.Vector[Int] =
+ Vector(4, 6, 8, 10, 12, 14, 16, 18, 20, 22)
+```
+
+{% endtab %}
+{% endtabs %}
Let's do this sequence of operations again, one by one:
- scala> val vv = v.view
- vv: scala.collection.IndexedSeqView[Int] = IndexedSeqView()
+{% tabs views_4 %}
+{% tab 'Scala 2 and 3' for=views_4 %}
+
+```scala
+scala> val vv = v.view
+val vv: scala.collection.IndexedSeqView[Int] = IndexedSeqView()
+```
+
+{% endtab %}
+{% endtabs %}
The application `v.view` gives you an `IndexedSeqView[Int]`, i.e. a lazily evaluated `IndexedSeq[Int]`. Like with `LazyList`,
the `toString` operation of views does not force the view elements, that’s why the content of `vv` is shown as `IndexedSeqView()`.
Applying the first `map` to the view gives:
- scala> vv map (_ + 1)
- res13: scala.collection.IndexedSeqView[Int] = IndexedSeqView()
+{% tabs views_5 %}
+{% tab 'Scala 2 and 3' for=views_5 %}
+
+```scala
+scala> vv.map(_ + 1)
+val res13: scala.collection.IndexedSeqView[Int] = IndexedSeqView()
+```
+{% endtab %}
+{% endtabs %}
The result of the `map` is another `IndexedSeqView[Int]` value. This is in essence a wrapper that *records* the fact that a `map` with function `(_ + 1)` needs to be applied on the vector `v`. It does not apply that map until the view is forced, however. Let's now apply the second `map` to the last result.
- scala> res13 map (_ * 2)
- res14: scala.collection.IndexedSeqView[Int] = IndexedSeqView()
+{% tabs views_6 %}
+{% tab 'Scala 2 and 3' for=views_6 %}
+
+```scala
+scala> res13.map(_ * 2)
+val res14: scala.collection.IndexedSeqView[Int] = IndexedSeqView()
+```
+
+{% endtab %}
+{% endtabs %}
Finally, forcing the last result gives:
- scala> res14.to(Vector)
- res15: scala.collection.immutable.Vector[Int] =
- Vector(4, 6, 8, 10, 12, 14, 16, 18, 20, 22)
+{% tabs views_7 %}
+{% tab 'Scala 2 and 3' for=views_7 %}
+
+```scala
+scala> res14.to(Vector)
+val res15: scala.collection.immutable.Vector[Int] =
+ Vector(4, 6, 8, 10, 12, 14, 16, 18, 20, 22)
+```
+
+{% endtab %}
+{% endtabs %}
Both stored functions get applied as part of the execution of the `to` operation and a new vector is constructed. That way, no intermediate data structure is needed.
@@ -84,16 +157,36 @@ These operations are documented as “always forcing the collection elements”.
The main reason for using views is performance. You have seen that by switching a collection to a view the construction of intermediate results can be avoided. These savings can be quite important. As another example, consider the problem of finding the first palindrome in a list of words. A palindrome is a word which reads backwards the same as forwards. Here are the necessary definitions:
- def isPalindrome(x: String) = x == x.reverse
- def findPalindrome(s: Seq[String]) = s find isPalindrome
+{% tabs views_8 %}
+{% tab 'Scala 2 and 3' for=views_8 %}
+
+```scala
+def isPalindrome(x: String) = x == x.reverse
+def findPalindrome(s: Seq[String]) = s.find(isPalindrome)
+```
+
+{% endtab %}
+{% endtabs %}
-Now, assume you have a very long sequence words and you want to find a palindrome in the first million words of that sequence. Can you re-use the definition of `findPalindrome`? Of course, you could write:
+Now, assume you have a very long sequence words, and you want to find a palindrome in the first million words of that sequence. Can you re-use the definition of `findPalindrome`? Of course, you could write:
- findPalindrome(words take 1000000)
+{% tabs views_9 %}
+{% tab 'Scala 2 and 3' for=views_9 %}
+```scala
+val palindromes = findPalindrome(words.take(1000000))
+```
+{% endtab %}
+{% endtabs %}
This nicely separates the two aspects of taking the first million words of a sequence and finding a palindrome in it. But the downside is that it always constructs an intermediary sequence consisting of one million words, even if the first word of that sequence is already a palindrome. So potentially, 999'999 words are copied into the intermediary result without being inspected at all afterwards. Many programmers would give up here and write their own specialized version of finding palindromes in some given prefix of an argument sequence. But with views, you don't have to. Simply write:
- findPalindrome(words.view take 1000000)
+{% tabs views_10 %}
+{% tab 'Scala 2 and 3' for=views_10 %}
+```scala
+val palindromes = findPalindrome(words.view.take(1000000))
+```
+{% endtab %}
+{% endtabs %}
This has the same nice separation of concerns, but instead of a sequence of a million elements it will only construct a single lightweight view object. This way, you do not need to choose between performance and modularity.
@@ -101,16 +194,50 @@ After having seen all these nifty uses of views you might wonder why have strict
Here's an example which bit a few users of versions of Scala before 2.8. In these versions the `Range` type was lazy, so it behaved in effect like a view. People were trying to create a number of actors like this:
- val actors = for (i <- 1 to 10) yield actor { ... }
+{% tabs views_11 class=tabs-scala-version %}
+{% tab 'Scala 2' for=views_11 %}
+```scala
+val actors = for (i <- 1 to 10) yield actor { ... }
+```
+{% endtab %}
+{% tab 'Scala 3' for=views_11 %}
+```scala
+val actors = for i <- 1 to 10 yield actor { ... }
+```
+{% endtab %}
+{% endtabs %}
They were surprised that none of the actors was executing afterwards, even though the actor method should create and start an actor from the code that's enclosed in the braces following it. To explain why nothing happened, remember that the for expression above is equivalent to an application of map:
- val actors = (1 to 10) map (i => actor { ... })
+{% tabs views_12 %}
+{% tab 'Scala 2 and 3' for=views_12 %}
+
+```scala
+val actors = (1 to 10).map(i => actor { ... })
+```
+
+{% endtab %}
+{% endtabs %}
Since previously the range produced by `(1 to 10)` behaved like a view, the result of the map was again a view. That is, no element was computed, and, consequently, no actor was created! Actors would have been created by forcing the range of the whole expression, but it's far from obvious that this is what was required to make the actors do their work.
To avoid surprises like this, the current Scala collections library has more regular rules. All collections except lazy lists and views are strict. The only way to go from a strict to a lazy collection is via the `view` method. The only way to go back is via `to`. So the `actors` definition above would now behave as expected in that it would create and start 10 actors. To get back the surprising previous behavior, you'd have to add an explicit `view` method call:
- val actors = for (i <- (1 to 10).view) yield actor { ... }
+{% tabs views_13 class=tabs-scala-version %}
+{% tab 'Scala 2' for=views_13 %}
+
+```scala
+val actors = for (i <- (1 to 10).view) yield actor { ... }
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=views_13 %}
+
+```scala
+val actors = for i <- (1 to 10).view yield actor { ... }
+```
+
+{% endtab %}
+{% endtabs %}
In summary, views are a powerful tool to reconcile concerns of efficiency with concerns of modularity. But in order not to be entangled in aspects of delayed evaluation, you should restrict views to purely functional code where collection transformations do not have side effects. What's best avoided is a mixture of views and operations that create new collections while also having side effects.
diff --git a/_overviews/collections/arrays.md b/_overviews/collections/arrays.md
index 019ac91248..637806b014 100644
--- a/_overviews/collections/arrays.md
+++ b/_overviews/collections/arrays.md
@@ -24,7 +24,7 @@ permalink: /overviews/collections/:title.html
Given that Scala arrays are represented just like Java arrays, how can these additional features be supported in Scala? In fact, the answer to this question differs between Scala 2.8 and earlier versions. Previously, the Scala compiler somewhat "magically" wrapped and unwrapped arrays to and from `Seq` objects when required in a process called boxing and unboxing. The details of this were quite complicated, in particular when one created a new array of generic type `Array[T]`. There were some puzzling corner cases and the performance of array operations was not all that predictable.
-The Scala 2.8 design is much simpler. Almost all compiler magic is gone. Instead the Scala 2.8 array implementation makes systematic use of implicit conversions. In Scala 2.8 an array does not pretend to _be_ a sequence. It can't really be that because the data type representation of a native array is not a subtype of `Seq`. Instead there is an implicit "wrapping" conversion between arrays and instances of class `scala.collection.mutable.WrappedArray`, which is a subclass of `Seq`. Here you see it in action:
+The Scala 2.8 design is much simpler. Almost all compiler magic is gone. Instead, the Scala 2.8 array implementation makes systematic use of implicit conversions. In Scala 2.8 an array does not pretend to _be_ a sequence. It can't really be that because the data type representation of a native array is not a subtype of `Seq`. Instead, there is an implicit "wrapping" conversion between arrays and instances of class `scala.collection.mutable.WrappedArray`, which is a subclass of `Seq`. Here you see it in action:
scala> val seq: Seq[Int] = a1
seq: Seq[Int] = WrappedArray(1, 2, 3)
@@ -60,9 +60,9 @@ The `ArrayOps` object gets inserted automatically by the implicit conversion. So
scala> intArrayOps(a1).reverse
res5: Array[Int] = Array(3, 2, 1)
-where `intArrayOps` is the implicit conversion that was inserted previously. This raises the question how the compiler picked `intArrayOps` over the other implicit conversion to `WrappedArray` in the line above. After all, both conversions map an array to a type that supports a reverse method, which is what the input specified. The answer to that question is that the two implicit conversions are prioritized. The `ArrayOps` conversion has a higher priority than the `WrappedArray` conversion. The first is defined in the `Predef` object whereas the second is defined in a class `scala.LowPriorityImplicits`, which is inherited by `Predef`. Implicits in subclasses and subobjects take precedence over implicits in base classes. So if both conversions are applicable, the one in `Predef` is chosen. A very similar scheme works for strings.
+where `intArrayOps` is the implicit conversion that was inserted previously. This raises the question of how the compiler picked `intArrayOps` over the other implicit conversion to `WrappedArray` in the line above. After all, both conversions map an array to a type that supports a reverse method, which is what the input specified. The answer to that question is that the two implicit conversions are prioritized. The `ArrayOps` conversion has a higher priority than the `WrappedArray` conversion. The first is defined in the `Predef` object whereas the second is defined in a class `scala.LowPriorityImplicits`, which is inherited by `Predef`. Implicits in subclasses and subobjects take precedence over implicits in base classes. So if both conversions are applicable, the one in `Predef` is chosen. A very similar scheme works for strings.
-So now you know how arrays can be compatible with sequences and how they can support all sequence operations. What about genericity? In Java you cannot write a `T[]` where `T` is a type parameter. How then is Scala's `Array[T]` represented? In fact a generic array like `Array[T]` could be at run-time any of Java's eight primitive array types `byte[]`, `short[]`, `char[]`, `int[]`, `long[]`, `float[]`, `double[]`, `boolean[]`, or it could be an array of objects. The only common run-time type encompassing all of these types is `AnyRef` (or, equivalently `java.lang.Object`), so that's the type to which the Scala compiler maps `Array[T]`. At run-time, when an element of an array of type `Array[T]` is accessed or updated there is a sequence of type tests that determine the actual array type, followed by the correct array operation on the Java array. These type tests slow down array operations somewhat. You can expect accesses to generic arrays to be three to four times slower than accesses to primitive or object arrays. This means that if you need maximal performance, you should prefer concrete over generic arrays. Representing the generic array type is not enough, however, there must also be a way to create generic arrays. This is an even harder problem, which requires a little bit of help from you. To illustrate the problem, consider the following attempt to write a generic method that creates an array.
+So now you know how arrays can be compatible with sequences and how they can support all sequence operations. What about genericity? In Java, you cannot write a `T[]` where `T` is a type parameter. How then is Scala's `Array[T]` represented? In fact a generic array like `Array[T]` could be at run-time any of Java's eight primitive array types `byte[]`, `short[]`, `char[]`, `int[]`, `long[]`, `float[]`, `double[]`, `boolean[]`, or it could be an array of objects. The only common run-time type encompassing all of these types is `AnyRef` (or, equivalently `java.lang.Object`), so that's the type to which the Scala compiler maps `Array[T]`. At run-time, when an element of an array of type `Array[T]` is accessed or updated there is a sequence of type tests that determine the actual array type, followed by the correct array operation on the Java array. These type tests slow down array operations somewhat. You can expect accesses to generic arrays to be three to four times slower than accesses to primitive or object arrays. This means that if you need maximal performance, you should prefer concrete to generic arrays. Representing the generic array type is not enough, however, there must also be a way to create generic arrays. This is an even harder problem, which requires a little of help from you. To illustrate the issue, consider the following attempt to write a generic method that creates an array.
// this is wrong!
def evenElems[T](xs: Vector[T]): Array[T] = {
@@ -72,7 +72,7 @@ So now you know how arrays can be compatible with sequences and how they can sup
arr
}
-The `evenElems` method returns a new array that consist of all elements of the argument vector `xs` which are at even positions in the vector. The first line of the body of `evenElems` creates the result array, which has the same element type as the argument. So depending on the actual type parameter for `T`, this could be an `Array[Int]`, or an `Array[Boolean]`, or an array of some of the other primitive types in Java, or an array of some reference type. But these types have all different runtime representations, so how is the Scala runtime going to pick the correct one? In fact, it can't do that based on the information it is given, because the actual type that corresponds to the type parameter `T` is erased at runtime. That's why you will get the following error message if you compile the code above:
+The `evenElems` method returns a new array that consist of all elements of the argument vector `xs` which are at even positions in the vector. The first line of the body of `evenElems` creates the result array, which has the same element type as the argument. So depending on the actual type parameter for `T`, this could be an `Array[Int]`, or an `Array[Boolean]`, or an array of some other primitive types in Java, or an array of some reference type. But these types have all different runtime representations, so how is the Scala runtime going to pick the correct one? In fact, it can't do that based on the information it is given, because the actual type that corresponds to the type parameter `T` is erased at runtime. That's why you will get the following error message if you compile the code above:
error: cannot find class manifest for element type T
val arr = new Array[T]((arr.length + 1) / 2)
diff --git a/_overviews/collections/concrete-immutable-collection-classes.md b/_overviews/collections/concrete-immutable-collection-classes.md
index 95a76570d1..6324128e48 100644
--- a/_overviews/collections/concrete-immutable-collection-classes.md
+++ b/_overviews/collections/concrete-immutable-collection-classes.md
@@ -19,7 +19,7 @@ A [List](https://www.scala-lang.org/api/{{ site.scala-212-version }}/scala/colle
Lists have always been the workhorse for Scala programming, so not much needs to be said about them here. The major change in 2.8 is that the `List` class together with its subclass `::` and its subobject `Nil` is now defined in package `scala.collection.immutable`, where it logically belongs. There are still aliases for `List`, `Nil`, and `::` in the `scala` package, so from a user perspective, lists can be accessed as before.
-Another change is that lists now integrate more closely into the collections framework, and are less of a special case than before. For instance all of the numerous methods that originally lived in the `List` companion object have been deprecated. They are replaced by the [uniform creation methods]({{ site.baseurl }}/overviews/collections/creating-collections-from-scratch.html) inherited by every collection.
+Another change is that lists now integrate more closely into the collections framework, and are less of a special case than before. For instance all the numerous methods that originally lived in the `List` companion object have been deprecated. They are replaced by the [uniform creation methods]({{ site.baseurl }}/overviews/collections/creating-collections-from-scratch.html) inherited by every collection.
## Streams
diff --git a/_overviews/collections/concrete-mutable-collection-classes.md b/_overviews/collections/concrete-mutable-collection-classes.md
index bc7bf02567..108b531c9a 100644
--- a/_overviews/collections/concrete-mutable-collection-classes.md
+++ b/_overviews/collections/concrete-mutable-collection-classes.md
@@ -54,7 +54,7 @@ Just like an array buffer is useful for building arrays, and a list buffer is us
## Linked Lists
-Linked lists are mutable sequences that consist of nodes which are linked with next pointers. They are supported by class [LinkedList](https://www.scala-lang.org/api/{{ site.scala-212-version }}/scala/collection/mutable/LinkedList.html). In most languages `null` would be picked as the empty linked list. That does not work for Scala collections, because even empty sequences must support all sequence methods. In particular `LinkedList.empty.isEmpty` should return `true` and not throw a `NullPointerException`. Empty linked lists are encoded instead in a special way: Their `next` field points back to the node itself. Like their immutable cousins, linked lists are best traversed sequentially. In addition linked lists make it easy to insert an element or linked list into another linked list.
+Linked lists are mutable sequences that consist of nodes which are linked with next pointers. They are supported by class [LinkedList](https://www.scala-lang.org/api/{{ site.scala-212-version }}/scala/collection/mutable/LinkedList.html). In most languages `null` would be picked as the empty linked list. That does not work for Scala collections, because even empty sequences must support all sequence methods. In particular `LinkedList.empty.isEmpty` should return `true` and not throw a `NullPointerException`. Empty linked lists are encoded instead in a special way: Their `next` field points back to the node itself. Like their immutable cousins, linked lists are best traversed sequentially. In addition, linked lists make it easy to insert an element or linked list into another linked list.
## Double Linked Lists
@@ -85,7 +85,7 @@ Scala provides mutable queues in addition to immutable ones. You use a `mQueue`
Array sequences are mutable sequences of fixed size which store their elements internally in an `Array[Object]`. They are implemented in Scala by class [ArraySeq](https://www.scala-lang.org/api/{{ site.scala-212-version }}/scala/collection/mutable/ArraySeq.html).
-You would typically use an `ArraySeq` if you want an array for its performance characteristics, but you also want to create generic instances of the sequence where you do not know the type of the elements and you do not have a `ClassTag` to provide it at run-time. These issues are explained in the section on [arrays]({{ site.baseurl }}/overviews/collections/arrays.html).
+You would typically use an `ArraySeq` if you want an array for its performance characteristics, but you also want to create generic instances of the sequence where you do not know the type of the elements, and you do not have a `ClassTag` to provide it at run-time. These issues are explained in the section on [arrays]({{ site.baseurl }}/overviews/collections/arrays.html).
## Stacks
diff --git a/_overviews/collections/creating-collections-from-scratch.md b/_overviews/collections/creating-collections-from-scratch.md
index a7c1a7ff5b..2468bf9e27 100644
--- a/_overviews/collections/creating-collections-from-scratch.md
+++ b/_overviews/collections/creating-collections-from-scratch.md
@@ -40,7 +40,7 @@ Besides `apply`, every collection companion object also defines a member `empty`
Descendants of `Seq` classes provide also other factory operations in their companion objects. These are summarized in the following table. In short, there's
* `concat`, which concatenates an arbitrary number of traversables together,
-* `fill` and `tabulate`, which generate single or multi-dimensional sequences of given dimensions initialized by some expression or tabulating function,
+* `fill` and `tabulate`, which generate single or multidimensional sequences of given dimensions initialized by some expression or tabulating function,
* `range`, which generates integer sequences with some constant step length, and
* `iterate`, which generates the sequence resulting from repeated application of a function to a start element.
diff --git a/_overviews/collections/equality.md b/_overviews/collections/equality.md
index c949d7aac5..bb9abc6f06 100644
--- a/_overviews/collections/equality.md
+++ b/_overviews/collections/equality.md
@@ -13,7 +13,7 @@ permalink: /overviews/collections/:title.html
The collection libraries have a uniform approach to equality and hashing. The idea is, first, to divide collections into sets, maps, and sequences. Collections in different categories are always unequal. For instance, `Set(1, 2, 3)` is unequal to `List(1, 2, 3)` even though they contain the same elements. On the other hand, within the same category, collections are equal if and only if they have the same elements (for sequences: the same elements in the same order). For example, `List(1, 2, 3) == Vector(1, 2, 3)`, and `HashSet(1, 2) == TreeSet(2, 1)`.
-It does not matter for the equality check whether a collection is mutable or immutable. For a mutable collection one simply considers its current elements at the time the equality test is performed. This means that a mutable collection might be equal to different collections at different times, depending what elements are added or removed. This is a potential trap when using a mutable collection as a key in a hashmap. Example:
+It does not matter for the equality check whether a collection is mutable or immutable. For a mutable collection one simply considers its current elements at the time the equality test is performed. This means that a mutable collection might be equal to different collections at different times, depending on what elements are added or removed. This is a potential trap when using a mutable collection as a key in a hashmap. Example:
scala> import collection.mutable.{HashMap, ArrayBuffer}
import collection.mutable.{HashMap, ArrayBuffer}
diff --git a/_overviews/collections/introduction.md b/_overviews/collections/introduction.md
index d61806d127..5fc2e3f301 100644
--- a/_overviews/collections/introduction.md
+++ b/_overviews/collections/introduction.md
@@ -55,7 +55,7 @@ lines run at first try.
**Fast:** Collection operations are tuned and optimized in the
libraries. As a result, using collections is typically quite
-efficient. You might be able to do a little bit better with carefully
+efficient. You might be able to do a little better with carefully
hand-tuned data structures and operations, but you might also do a lot
worse by making some suboptimal implementation decisions along the
way. What's more, collections have been recently adapted to parallel
diff --git a/_overviews/collections/iterators.md b/_overviews/collections/iterators.md
index f08e65d5a3..78dfcc69f0 100644
--- a/_overviews/collections/iterators.md
+++ b/_overviews/collections/iterators.md
@@ -26,7 +26,7 @@ As always, for-expressions can be used as an alternate syntax for expressions in
for (elem <- it) println(elem)
-There's an important difference between the foreach method on iterators and the same method on traversable collections: When called on an iterator, `foreach` will leave the iterator at its end when it is done. So calling `next` again on the same iterator will fail with a `NoSuchElementException`. By contrast, when called on a collection, `foreach` leaves the number of elements in the collection unchanged (unless the passed function adds to removes elements, but this is discouraged, because it may lead to surprising results).
+There's an important difference between the foreach method on iterators and the same method on traversable collections: When called on an iterator, `foreach` will leave the iterator at its end when it is done. So calling `next` again on the same iterator will fail with a `NoSuchElementException`. By contrast, when called on a collection, `foreach` leaves the number of elements in the collection unchanged (unless the passed function adds or removes elements, but this is discouraged, because it may lead to surprising results).
The other operations that Iterator has in common with `Traversable` have the same property. For instance, iterators provide a `map` method, which returns a new iterator:
@@ -166,7 +166,7 @@ A lazy operation does not immediately compute all of its results. Instead, it co
So the expression `(1 to 10).iterator.map(println)` would not print anything to the screen. The `map` method in this case doesn't apply its argument function to the values in the range, it returns a new `Iterator` that will do this as each one is requested. Adding `.toList` to the end of that expression will actually print the elements.
-A consequence of this is that a method like `map` or `filter` won't necessarily apply its argument function to all of the input elements. The expression `(1 to 10).iterator.map(println).take(5).toList` would only print the values `1` to `5`, for instance, since those are only ones that will be requested from the `Iterator` returned by `map`.
+A consequence of this is that a method like `map` or `filter` won't necessarily apply its argument function to all the input elements. The expression `(1 to 10).iterator.map(println).take(5).toList` would only print the values `1` to `5`, for instance, since those are only ones that will be requested from the `Iterator` returned by `map`.
This is one of the reasons why it's important to only use pure functions as arguments to `map`, `filter`, `fold` and similar methods. Remember, a pure function has no side-effects, so one would not normally use `println` in a `map`. `println` is used to demonstrate laziness as it's not normally visible with pure functions.
diff --git a/_overviews/collections/migrating-from-scala-27.md b/_overviews/collections/migrating-from-scala-27.md
index d621c78899..5e1efc7822 100644
--- a/_overviews/collections/migrating-from-scala-27.md
+++ b/_overviews/collections/migrating-from-scala-27.md
@@ -12,7 +12,7 @@ permalink: /overviews/collections/:title.html
Porting your existing Scala applications to use the new collections should be almost automatic. There are only a couple of possible issues to take care of.
-Generally, the old functionality of Scala 2.7 collections has been left in place. Some features have been deprecated, which means they will removed in some future release. You will get a _deprecation warning_ when you compile code that makes use of these features in Scala 2.8. In a few places deprecation was unfeasible, because the operation in question was retained in 2.8, but changed in meaning or performance characteristics. These cases will be flagged with _migration warnings_ when compiled under 2.8. To get full deprecation and migration warnings with suggestions how to change your code, pass the `-deprecation` and `-Xmigration` flags to `scalac` (note that `-Xmigration` is an extended option, so it starts with an `X`). You can also pass the same options to the `scala` REPL to get the warnings in an interactive session. Example:
+Generally, the old functionality of Scala 2.7 collections has been left in place. Some features have been deprecated, which means they will be removed in some future release. You will get a _deprecation warning_ when you compile code that makes use of these features in Scala 2.8. In a few places deprecation was unfeasible, because the operation in question was retained in 2.8, but changed in meaning or performance characteristics. These cases will be flagged with _migration warnings_ when compiled under 2.8. To get full deprecation and migration warnings with suggestions how to change your code, pass the `-deprecation` and `-Xmigration` flags to `scalac` (note that `-Xmigration` is an extended option, so it starts with an `X`). You can also pass the same options to the `scala` REPL to get the warnings in an interactive session. Example:
>scala -deprecation -Xmigration
Welcome to Scala version 2.8.0.final
@@ -38,7 +38,7 @@ Generally, the old functionality of Scala 2.7 collections has been left in place
There are two parts of the old libraries which have been replaced wholesale, and for which deprecation warnings were not feasible.
-1. The previous `scala.collection.jcl` package is gone. This package tried to mimick some of the Java collection library design in Scala, but in doing so broke many symmetries. Most people who wanted Java collections bypassed `jcl` and used `java.util` directly. Scala 2.8 offers automatic conversion mechanisms between both collection libraries in the [JavaConversions]({{ site.baseurl }}/overviews/collections/conversions-between-java-and-scala-collections.html) object which replaces the `jcl` package.
+1. The previous `scala.collection.jcl` package is gone. This package tried to mimic aspects of the Java collection library design in Scala, but in doing so broke many symmetries. Most people who wanted Java collections bypassed `jcl` and used `java.util` directly. Scala 2.8 offers automatic conversion mechanisms between both collection libraries in the [JavaConversions]({{ site.baseurl }}/overviews/collections/conversions-between-java-and-scala-collections.html) object which replaces the `jcl` package.
2. Projections have been generalized and cleaned up and are now available as views. It seems that projections were used rarely, so not much code should be affected by this change.
So, if your code uses either `jcl` or projections there might be some minor rewriting to do.
diff --git a/_overviews/collections/trait-iterable.md b/_overviews/collections/trait-iterable.md
index abc8051703..ac72783f41 100644
--- a/_overviews/collections/trait-iterable.md
+++ b/_overviews/collections/trait-iterable.md
@@ -62,6 +62,6 @@ Trait `Iterable` also adds some other methods to `Traversable` that can be imple
In the inheritance hierarchy below Iterable you find three traits: [Seq](https://www.scala-lang.org/api/{{ site.scala-212-version }}/scala/collection/Seq.html), [Set](https://www.scala-lang.org/api/{{ site.scala-212-version }}/scala/collection/Set.html), and [Map](https://www.scala-lang.org/api/{{ site.scala-212-version }}/scala/collection/Map.html). `Seq` and `Map` implement the [PartialFunction](https://www.scala-lang.org/api/{{ site.scala-212-version }}/scala/PartialFunction.html) trait with its `apply` and `isDefinedAt` methods, each implemented differently. `Set` gets its `apply` method from [GenSetLike](https://www.scala-lang.org/api/{{ site.scala-212-version }}/scala/collection/GenSetLike.html).
-For sequences, `apply` is positional indexing, where elements are always numbered from `0`. That is, `Seq(1, 2, 3)(1)` gives `2`. For sets, `apply` is a membership test. For instance, `Set('a', 'b', 'c')('b')` gives `true` whereas `Set()('a')` gives `false`. Finally for maps, `apply` is a selection. For instance, `Map('a' -> 1, 'b' -> 10, 'c' -> 100)('b')` gives `10`.
+For sequences, `apply` is positional indexing, where elements are always numbered from `0`. That is, `Seq(1, 2, 3)(1)` gives `2`. For sets, `apply` is a membership test. For instance, `Set('a', 'b', 'c')('b')` gives `true` whereas `Set()('a')` gives `false`. Finally, for maps, `apply` is a selection. For instance, `Map('a' -> 1, 'b' -> 10, 'c' -> 100)('b')` gives `10`.
In the following, we will explain each of the three kinds of collections in more detail.
diff --git a/_overviews/collections/trait-traversable.md b/_overviews/collections/trait-traversable.md
index 11aaa6b349..d2173cb789 100644
--- a/_overviews/collections/trait-traversable.md
+++ b/_overviews/collections/trait-traversable.md
@@ -25,7 +25,7 @@ The `foreach` method is meant to traverse all elements of the collection, and ap
* **Conversions** `toArray`, `toList`, `toIterable`, `toSeq`, `toIndexedSeq`, `toStream`, `toSet`, `toMap`, which turn a `Traversable` collection into something more specific. All these conversions return their receiver argument unchanged if the run-time type of the collection already matches the demanded collection type. For instance, applying `toList` to a list will yield the list itself.
* **Copying operations** `copyToBuffer` and `copyToArray`. As their names imply, these copy collection elements to a buffer or array, respectively.
* **Size info** operations `isEmpty`, `nonEmpty`, `size`, and `hasDefiniteSize`: Traversable collections can be finite or infinite. An example of an infinite traversable collection is the stream of natural numbers `Stream.from(0)`. The method `hasDefiniteSize` indicates whether a collection is possibly infinite. If `hasDefiniteSize` returns true, the collection is certainly finite. If it returns false, the collection has not been fully elaborated yet, so it might be infinite or finite.
-* **Element retrieval** operations `head`, `last`, `headOption`, `lastOption`, and `find`. These select the first or last element of a collection, or else the first element matching a condition. Note, however, that not all collections have a well-defined meaning of what "first" and "last" means. For instance, a hash set might store elements according to their hash keys, which might change from run to run. In that case, the "first" element of a hash set could also be different for every run of a program. A collection is _ordered_ if it always yields its elements in the same order. Most collections are ordered, but some (_e.g._ hash sets) are not-- dropping the ordering gives a little bit of extra efficiency. Ordering is often essential to give reproducible tests and to help in debugging. That's why Scala collections give ordered alternatives for all collection types. For instance, the ordered alternative for `HashSet` is `LinkedHashSet`.
+* **Element retrieval** operations `head`, `last`, `headOption`, `lastOption`, and `find`. These select the first or last element of a collection, or else the first element matching a condition. Note, however, that not all collections have a well-defined meaning of what "first" and "last" means. For instance, a hash set might store elements according to their hash keys, which might change from run to run. In that case, the "first" element of a hash set could also be different for every run of a program. A collection is _ordered_ if it always yields its elements in the same order. Most collections are ordered, but some (_e.g._ hash sets) are not-- dropping the ordering gives a little extra efficiency. Ordering is often essential to give reproducible tests and to help in debugging. That's why Scala collections give ordered alternatives for all collection types. For instance, the ordered alternative for `HashSet` is `LinkedHashSet`.
* **Sub-collection retrieval operations** `tail`, `init`, `slice`, `take`, `drop`, `takeWhile`, `dropWhile`, `filter`, `filterNot`, `withFilter`. These all return some sub-collection identified by an index range or some predicate.
* **Subdivision operations** `splitAt`, `span`, `partition`, `groupBy`, which split the elements of this collection into several sub-collections.
* **Element tests** `exists`, `forall`, `count` which test collection elements with a given predicate.
diff --git a/_overviews/collections/views.md b/_overviews/collections/views.md
index dd3c128657..1798d77cf4 100644
--- a/_overviews/collections/views.md
+++ b/_overviews/collections/views.md
@@ -73,7 +73,7 @@ There are two reasons why you might want to consider using views. The first is p
def isPalindrome(x: String) = x == x.reverse
def findPalindrome(s: Seq[String]) = s find isPalindrome
-Now, assume you have a very long sequence words and you want to find a palindrome in the first million words of that sequence. Can you re-use the definition of `findPalindrome`? Of course, you could write:
+Now, assume you have a very long sequence of words, and you want to find a palindrome in the first million words of that sequence. Can you re-use the definition of `findPalindrome`? Of course, you could write:
findPalindrome(words take 1000000)
diff --git a/_overviews/compiler-options/errors.md b/_overviews/compiler-options/errors.md
new file mode 100644
index 0000000000..8128ef96ae
--- /dev/null
+++ b/_overviews/compiler-options/errors.md
@@ -0,0 +1,110 @@
+---
+layout: singlepage-overview
+title: Error Formatting
+---
+
+# Introduction
+
+An advanced mechanism for formatting type errors and inspecting missing
+implicits has been introduced in Scala 2.13.6.
+It is based on the compiler plugin [splain](https://github.com/tek/splain).
+
+This tool abstracts several classes of compiler errors with simple data types
+that can be processed by a few built-in routines as well as
+[user-provided analyzer plugins](/overviews/plugins/index.html).
+
+The most significant feature is the illustration of chains of implicit instances
+that allows a user to determine the root cause of an implicit error:
+
+
+
+# Basic Configuration
+
+* `-Vimplicits` enables printing of implicit chains
+* `-Vtype-diffs` enables colored diffs for found/required errors
+
+## Additional Configuration
+
+`-Vimplicits-verbose-tree` shows the implicits between the error site and the
+root cause, see [#implicit-resolution-chains].
+
+`-Vimplicits-max-refined` reduces the verbosity of refined types, see
+[#truncating-refined-types].
+
+# Features
+
+The error formatting engine provides the following enhancements:
+
+## Infix Types
+
+Instead of `shapeless.::[A, HNil]`, prints `A :: HNil`.
+
+## Found/Required Types
+
+Rather than printing up to four types, only the dealiased types are shown as a colored diff:
+
+
+
+## Implicit Resolution Chains
+
+When an implicit is not found, only the outermost error at the invocation point is printed by the regular error
+reporter.
+Previously, the flag `-Xlog-implicits` caused the compiler to print all information about processed implicits, but the
+output was highly verbose and contained all invalid implicits for parameters that have been resolved successfully.
+The flag has been renamed to `-Vimplicits` and prints a compact list of all involved implicit instances.
+`-Xlog-implicits` will continue to work as a deprecated alias.
+
+
+
+Here, `!I` stands for *could not find implicit value*, the name of the implicit
+parameter is in yellow, and its type in green.
+
+If the parameter `-Vimplicits-verbose-tree` is given, all intermediate implicits will be
+printed, potentially spanning tens of lines.
+An example of this is the circe error at the top of the page.
+
+For comparison, this is the regular compiler output for this case:
+
+```
+[error] /path/Example.scala:20:5: could not find implicit value for parameter a: io.circe.Decoder[A]
+[error] A.fun
+[error] ^
+```
+
+## Infix Type and Type Argument Line Breaking
+
+Types longer than 79 characters will be split into multiple lines:
+
+```
+implicit error;
+!I e: String
+f invalid because
+!I impPar4: List[
+ (
+ VeryLongTypeName ::::
+ VeryLongTypeName ::::
+ VeryLongTypeName ::::
+ VeryLongTypeName
+ )
+ ::::
+ (Short :::: Short) ::::
+ (
+ VeryLongTypeName ::::
+ VeryLongTypeName ::::
+ VeryLongTypeName ::::
+ VeryLongTypeName
+ )
+ ::::
+ VeryLongTypeName ::::
+ VeryLongTypeName ::::
+ VeryLongTypeName ::::
+ VeryLongTypeName
+]
+```
+
+## Truncating Refined Types
+
+Refined types, like `T { type A = X; type B = Y }`, can get rather long and clutter up error messages.
+The option `-Vimplicits-max-refined` controls how many characters the refinement may take up before it gets displayed as
+`T {...}`.
+The default is to display the unabridged type.
diff --git a/_overviews/compiler-options/index.md b/_overviews/compiler-options/index.md
index 34c1817b29..c4fd52f010 100644
--- a/_overviews/compiler-options/index.md
+++ b/_overviews/compiler-options/index.md
@@ -25,17 +25,13 @@ title: Scala Compiler Options
## Introduction
-Scala compiler `scalac` offers various **compiler options**, also referred to as **compiler flags**, to change how to compile your program.
+The Scala compiler `scalac` offers various **compiler options**, or **flags**, that change the compiler's default behavior. Some options just generate more compiler output in the form of diagnostics or warnings, while others change the result of compilation.
-Nowadays, most people are not running `scalac` from the command line.
-Instead, they use sbt, an IDE, and other tools as their interface to the compiler.
-Therefore they may not even have `scalac` installed, and won't think to do `man scalac`.
+The Scala command `scala`, which runs scripts or compiled code, accepts the same options as the `scalac` compiler, plus a few more that determine how to run a program.
-This page comes to the rescue for the people to find…
-
-* What compiler options `scalac` offers
-* How to use compiler options
+Options may be specified on the command line to `scalac` or in the configuration of a build tool or IDE.
+The Scala distribution includes a `man` page. If Scala is installed as a system command, that documentation may be available from `man scalac`.
## How to use compiler options
@@ -44,34 +40,47 @@ This page comes to the rescue for the people to find…
```bash
scalac [ ]
```
+Boolean flags are specified in the usual way:
+
+`scalac -Werror -Xlint Hello.scala`
+
+Options that require arguments use "colon" syntax:
+
+`scalac -Vprint:parser,typer`
-E.g. `scalac -encoding utf8 -Xfatal-warnings Hello.scala`
+Options that take just a single argument accept traditional syntax:
-Default paths can be listed by running a command line tool:
+`scalac -d /tmp`
+
+Conventionally, options have a prefix `-V` if they show "verbose" output;
+`-W` to manage warnings; `-X` for extended options that modify tool behavior;
+`-Y` for private options with limited support, where `Y` may suggest forking behavior.
+Several options have historical aliases, such as `-Xfatal-warnings` for `-Werror`.
+
+In Scala 2, default paths can be listed by running a tool in the distribution:
```
scala scala.tools.util.PathResolver [ ]
```
-
-
+That can help debug errors in options such as `--classpath`.
### Use compiler options with sbt
-
+Here is a typical configuration of the `scalacOptions` setting in `sbt`:
```scala
-scalacOptions ++= Seq(
- "-encoding", "utf8", // Option and arguments on same line
- "-Xfatal-warnings", // New lines for each options
- "-deprecation",
- "-unchecked",
+scalacOptions ++= Seq( // use ++= to add to existing options
+ "-encoding", "utf8", // if an option takes an arg, supply it on the same line
+ "-feature", // then put the next option on a new line for easy editing
"-language:implicitConversions",
- "-language:higherKinds",
"-language:existentials",
- "-language:postfixOps"
-)
+ "-unchecked",
+ "-Werror",
+ "-Xlint", // exploit "trailing comma" syntax so you can add an option without editing this line
+) // for "trailing comma", the closing paren must be on the next line
```
+The convention is always to append to the setting with `++=` and to supply one option per line.
-
+Normally the last option will have a trailing comma so that `git diff` is a bit cleaner when options are added.
{% for category in site.data.compiler-options %}
{{ category.category }}
@@ -116,73 +125,95 @@ scalacOptions ++= Seq(
{% endfor %}
+### Targeting a version of the JVM
+
+Applications or libraries targeting the JVM may wish to specify a target version.
+
+The `-release` option specifies the target version, such as "8" or "18".
+
+Like the option for `javac`, it allows building against an earlier version of the JDK. It will compile against the API for that version and also output class files for that version.
+
+The deprecated option `-target` does not compile against the desired API, but only specifies a target class file format.
## Additional resources
### Compilation Phases
diff --git a/_overviews/compiler-options/optimizer.md b/_overviews/compiler-options/optimizer.md
new file mode 100644
index 0000000000..5f35867bb5
--- /dev/null
+++ b/_overviews/compiler-options/optimizer.md
@@ -0,0 +1,223 @@
+---
+layout: singlepage-overview
+title: Optimizer
+---
+
+**[Lukas Rytz](https://github.com/lrytz) (2018)**
+
+**[Andrew Marki](https://github.com/som-snytt) (2022)**
+
+# The Scala 2.12 / 2.13 Inliner and Optimizer
+
+## In Brief
+
+- The Scala compiler has a compile-time optimizer that is available in versions 2.12 and 2.13, but not yet in Scala 3.
+- Don't enable the optimizer during development: it breaks incremental compilation, and it makes the compiler slower. Only enable it for testing, on CI, and to build releases.
+- Enable method-local optimizations with `-opt:local`. This option is safe for binary compatibility, but typically doesn't improve performance on its own.
+- Enable inlining in addition to method-local optimizations with `-opt:inline:[PATTERN]`.
+ - Don't inline from your dependencies when publishing a library, it breaks binary compatibility. Use `-opt:inline:my.package.**` to only inline from packages within your library.
+ - When compiling an application with global inlining (`-opt:inline:**`), ensure that the run-time classpath is **exactly the same** as the compile-time classpath.
+- The `@inline` annotation only has an effect if the inliner is enabled. It tells the inliner to always try to inline the annotated method or callsite.
+- Without the `@inline` annotation, the inliner generally inlines higher-order methods and forwarder methods. The main goal is to eliminate megamorphic callsites due to functions passed as argument, and to eliminate value boxing. Other optimizations are delegated to the JVM.
+
+Read more to learn more.
+
+## Intro
+
+The Scala compiler has included an inliner since version 2.0. Closure elimination and dead code elimination were added in 2.1. That was the first Scala optimizer, written and maintained by [Iulian Dragos](https://github.com/dragos). He continued to improve these features over time and consolidated them under the `-optimise` flag (later Americanized to `-optimize`), which remained available through Scala 2.11.
+
+The optimizer was re-written for Scala 2.12 to become more reliable and powerful – and to side-step the spelling issue by calling the new flag `-opt`. This post describes how to use the optimizer in Scala 2.12 and 2.13: what it does, how it works, and what are its limitations.
+
+The options were simplified for 2.13.9. This page uses the simplified forms.
+
+## Motivation
+
+Why does the Scala compiler even have a JVM bytecode optimizer? The JVM is a highly optimized runtime with a just-in-time (JIT) compiler that benefits from over two decades of tuning. It's because there are certain well-known code patterns that the JVM fails to optimize properly. These patterns are common in functional languages such as Scala. (Increasingly, Java code with lambdas is catching up and showing the same performance issues at run-time.)
+
+The two most important such patterns are "megamorphic dispatch" (also called "the inlining problem") and value boxing. If you'd like to learn more about these problems in the context of Scala, you could watch the part of [my Scala Days 2015 talk (starting at 26:13)](https://youtu.be/Ic4vQJcYwsU?t=1573).
+
+The goal of the Scala optimizer is to produce bytecode that the JVM can execute fast. It is also a goal to avoid performing any optimizations that the JVM can already do well.
+
+This means that the Scala optimizer may become obsolete in the future, if the JIT compiler is improved to handle these patterns better. In fact, with the arrival of GraalVM, that future might be nearer than you think! But for now, we dive into some details about the Scala optimizer.
+
+## Constraints and assumptions
+
+The Scala optimizer has to make its improvements within fairly narrow constraints:
+
+- The optimizer only changes method bodies, but never signatures of classes or methods. The generated bytecode has the same (binary) interface, whether or not the optimizer is enabled.
+- We don't assume the whole program (all user code plus all of its dependencies, that together make up an application) is known when running the optimizer. There may be classes on the run-time classpath that we don't see at compile-time: we may be compiling a library, or only a component of an application. This means that:
+ - Every non-final method can potentially be overridden, even if at compile-time there are no classes that define such an override
+ - Consequently, we can only inline methods that can be resolved at compile-time: final methods, methods in `object`s, and methods where the receiver's type is precisely known (for example, in `(new A).f`, the receiver is known to be exactly `A`, not a subtype of `A`).
+- The optimizer does not break applications that use reflection. This follows from the two points above: changes to classes could be observed by reflection, and additional classes could be loaded and instantiated dynamically.
+
+However, even when staying within these constraints, some changes performed by the optimizer can be observed at run-time:
+
+- Inlined methods disappear from call stacks.
+
+ - This can lead to unexpected behaviors when using a debugger.
+ - Related: line numbers (stored in bytecode) are discarded when a method is inlined into a different classfile, which also impacts debugging experience. (This [could be improved](https://github.com/scala/scala-dev/issues/3) and is expected to [progress](https://github.com/scala/scala3/pull/11492).)
+
+- Inlining a method can delay class loading of the class where the method is defined.
+
+- The optimizer assumes that modules (singletons like `object O`) are never `null`.
+ - This assumption can be false if the module is loaded in its superclass. The following example throws a `NullPointerException` when compiled normally, but prints `0` when compiled with the optimizer enabled:
+
+ ```scala
+ class A {
+ println(Test.f)
+ }
+ object Test extends A {
+ @inline def f = 0
+ def main(args: Array[String]): Unit = ()
+ }
+ ```
+
+ - This assumption can be disabled with `-opt:-assume-modules-non-null`, which results in additional null checks in optimized code.
+
+- The optimizer removes unnecessary loads of certain built-in modules, for example `scala.Predef` and `scala.runtime.ScalaRunTime`. This means that initialization (construction) of these modules can be skipped or delayed.
+
+ - For example, in `def f = 1 -> ""`, the method `Predef.->` is inlined and the access to `Predef` is eliminated. The resulting code is `def f = new Tuple2(1, "")`.
+ - This assumption can be disabled with `-opt:-allow-skip-core-module-init`
+
+- The optimizer eliminates unused `C.getClass` calls, which may delay class loading. This can be disabled with `-opt:-allow-skip-class-loading`.
+
+## Binary compatibility
+
+Scala minor releases are binary compatible with each other, for example, 2.12.6 and 2.12.7. The same is true for many libraries in the Scala ecosystem. These binary compatibility promises are the main reason for the Scala optimizer not to be enabled everywhere.
+
+The reason is that inlining a method from one class into another changes the (binary) interface that is accessed:
+
+```scala
+class C {
+ private[this] var x = 0
+ @inline final def inc(): Int = { x += 1; x }
+}
+```
+
+When inlining a callsite `c.inc()`, the resulting code no longer calls `inc`, but instead accesses the field `x` directly. Since that field is private (also in bytecode), inlining `inc` is only allowed within the class `C` itself. Trying to access `x` from any other class would cause an `IllegalAccessError` at run-time.
+
+However, there are many cases where implementation details in Scala source code become public in bytecode:
+
+```scala
+class C {
+ private def x = 0
+ @inline final def m: Int = x
+}
+object C {
+ def t(c: C) = c.x
+}
+```
+
+Scala allows accessing the private method `x` in the companion object `C`. In bytecode, however, the classfile for the companion `C$` is not allowed to access a private method of `C`. For that reason, the Scala compiler "mangles" the name of `x` to `C$$x` and makes the method public.
+
+This means that `m` can be inlined into classes other than `C`, since the resulting code invokes `C.C$$x` instead of `C.m`. Unfortunately this breaks Scala's binary compatibility promise: the fact that the public method `m` calls a private method `x` is considered to be an implementation detail that can change in a minor release of the library defining `C`.
+
+Even more trivially, assume that method `m` was buggy and is changed to `def m = if (fullMoon) 1 else x` in a minor release. Normally, it would be enough for a user to put the new version on the classpath. However, if the old version of `c.m` was inlined at compile-time, having the new version of C on the run-time classpath would not fix the bug.
+
+In order to safely use the Scala optimizer, users need to make sure that the compile-time and run-time classpaths are identical. This has a far-reaching consequence for library developers: **libraries that are published to be consumed by other projects should not inline code from the classpath**. The inliner can be configured to inline code from the library itself using `-opt:inline:my.package.**`.
+
+The reason for this restriction is that dependency management tools like sbt will often pick newer versions of transitive dependencies. For example, if library `A` depends on `core-1.1.1`, `B` depends on `core-1.1.2` and the application depends on both `A` and `B`, the build tool will put `core-1.1.2` on the classpath. If code from `core-1.1.1` was inlined into `A` at compile-time, it might break at run-time due to a binary incompatibility.
+
+## Using and interacting with the optimizer
+
+The compiler flag for enabling the optimizer is `-opt`. Running `scalac -opt:help` shows how to use the flag.
+
+By default (without any compiler flags, or with `-opt:default`), the Scala compiler eliminates unreachable code, but does not run any other optimizations.
+
+`-opt:local` enables all method-local optimizations, for example:
+
+- Elimination of code that loads unused values
+- Rewriting of null and `isInstanceOf` checks whose result is known at compile-time
+- Elimination of value boxes like `java.lang.Integer` or `scala.runtime.DoubleRef` that are created within a method and don't escape it
+
+Individual optimizations can be disabled. For example, `-opt:local,-nullness-tracking` disables nullness optimizations.
+
+Method-local optimizations alone typically don't have any positive effect on performance, because source code usually doesn't have unnecessary boxing or null checks. However, local optimizations can often be applied after inlining, so it's really the combination of inlining and local optimizations that can improve program performance.
+
+`-opt:inline` enables inlining in addition to method-local optimizations. However, to avoid unexpected binary compatibility issues, we also need to tell the compiler which code it is allowed to inline. This is done by specifying a pattern after the option to select packages, classes, and methods for inlining. Examples:
+
+- `-opt:inline:my.library.**` enables inlining from any class defined in package `my.library`, or in any of its sub-packages. Inlining within a library is safe for binary compatibility, so the resulting binary can be published. It will still work correctly even if one of its dependencies is updated to a newer minor version in the run-time classpath.
+- `-opt:inline:`, where the pattern is the literal string ``, enables inlining from the set of source files being compiled in the current compiler invocation. This option can also be used for compiling libraries. If the source files of a library are split up across multiple sbt projects, inlining is only done within each project. Note that in an incremental compilation, inlining would only happen within the sources being re-compiled – but in any case, it is recommended to only enable the optimizer in CI and release builds (and to run `clean` before building).
+- `-opt:inline:**` allows inlining from every class, including the JDK. This option enables full optimization when compiling an application. To avoid binary incompatibilities, it is mandatory to ensure that the run-time classpath is identical to the compile-time classpath, including the Java standard library.
+
+Running `scalac -opt:help` explains how to use the compiler flag.
+
+### Inliner heuristics and `@inline`
+
+When the inliner is enabled, it automatically selects callsites for inlining according to a heuristic.
+
+As mentioned in the introduction, the main goal of the Scala optimizer is to eliminate megamorphic dispatch and value boxing. In order to keep this post from growing too long, a followup post will include the analysis of concrete examples that motivate which callsites are selected by the inliner heuristic.
+
+Nevertheless, it is useful to have an intuition of how the heuristic works, so here is an overview:
+
+- Methods or callsites annotated [`@noinline`](https://www.scala-lang.org/api/current/scala/noinline.html) are not inlined.
+- The inliner doesn't inline *into* forwarder methods.
+- Methods or callsites annotated [`@inline`](https://www.scala-lang.org/api/current/scala/inline.html) are inlined.
+- Higher-order methods with a function literal as argument are inlined.
+- Higher-order methods where a parameter function of the callsite method is forwarded to the callee are inlined.
+- Methods with an `IntRef` / `DoubleRef` / ... parameter are inlined. When nested methods update variables of the outer method, those variables are boxed into `XRef` objects. These boxes can often be eliminated after inlining the nested method.
+- Forwarders, factory methods and trivial methods are inlined. Examples include simple closure bodies like `_ + 1` and synthetic methods (potentially with boxing / unboxing adaptations) such as bridges.
+
+To prevent methods from exceeding the JVM's method size limit, the inliner has size limits. Inlining into a method stops when the number of instructions exceeds a certain threshold.
+
+As you can see in the list above, the `@inline` and `@noinline` annotations are the only way for programmers to influence inlining decisions. In general, our recommendation is to avoid using these annotations. If you observe issues with the inliner heuristic that can be fixed by annotating methods, we are very keen to hear about them, for example in the form of a [bug report](https://github.com/scala/bug/issues).
+
+A related anecdote: in the Scala compiler and standard library (which are built with the optimizer enabled), there are roughly 330 `@inline`-annotated methods. Removing all of these annotations and re-building the project has no effect on the compiler's performance. So the annotations are well-intended and benign, but in reality unnecessary.
+
+For expert users, `@inline` annotations can be used to hand-tune performance critical code without reducing abstraction. If you have a project that falls into this category, please [let us know](https://contributors.scala-lang.org), we're interested to learn more!
+
+Finally, note that the `@inline` annotation only has an effect when the inliner is enabled, which is not the case by default. The reason is to avoid introducing accidental binary incompatibilities, as [explained above](#binary-compatibility).
+
+### Inliner warnings
+
+The inliner can issue warnings when callsites cannot be inlined. By default, these warnings are not issued individually, but only as a summary at the end of compilation (similar to deprecation warnings).
+
+```
+$> scalac Test.scala '-opt:inline:**'
+warning: there was one inliner warning; re-run enabling -Wopt for details, or try -help
+one warning found
+
+$> scalac Test.scala '-opt:inline:**' -Wopt
+Test.scala:3: warning: C::f()I is annotated @inline but could not be inlined:
+The method is not final and may be overridden.
+ def t = f
+ ^
+one warning found
+```
+
+By default, the inliner issues warnings for invocations of methods annotated `@inline` that cannot be inlined. Here is the source code that was compiled in the commands above:
+
+```scala
+class C {
+ @inline def f = 1
+ def t = f // cannot inline: C.f is not final
+}
+object T extends C {
+ override def t = f // can inline: T.f is final
+}
+```
+
+The `-Wopt` flag has more configurations. With `-Wopt:_`, a warning is issued for every callsite that is selected by the heuristic but cannot be inlined. See also `-Wopt:help`.
+
+### Inliner log
+
+If you're curious (or maybe even skeptical) about what the inliner is doing to your code, you can use the `-Vinline` verbose flag to produce a trace of the inliner's work:
+
+```scala
+package my.project
+class C {
+ def f(a: Array[Int]) = a.map(_ + 1)
+}
+```
+
+```
+$> scalac Test.scala '-opt:inline:**' -Vinline my/project/C.f
+Inlining into my/project/C.f
+ inlined scala/Predef$.intArrayOps (the callee is annotated `@inline`). Before: 15 ins, after: 30 ins.
+ inlined scala/collection/ArrayOps$.map$extension (the callee is a higher-order method, the argument for parameter (evidence$6: Function1) is a function literal). Before: 30 ins, after: 94 ins.
+ inlined scala/runtime/ScalaRunTime$.array_length (the callee is annotated `@inline`). Before: 94 ins, after: 110 ins.
+ [...]
+ rewrote invocations of closure allocated in my/project/C.f with body $anonfun$f$1: INVOKEINTERFACE scala/Function1.apply (Ljava/lang/Object;)Ljava/lang/Object; (itf)
+ inlined my/project/C.$anonfun$f$1 (the callee is a synthetic forwarder method). Before: 654 ins, after: 666 ins.
+ inlined scala/runtime/BoxesRunTime.boxToInteger (the callee is a forwarder method with boxing adaptation). Before: 666 ins, after: 674 ins.
+```
diff --git a/_overviews/contribute/add-guides.md b/_overviews/contribute/add-guides.md
new file mode 100644
index 0000000000..4840739cda
--- /dev/null
+++ b/_overviews/contribute/add-guides.md
@@ -0,0 +1,373 @@
+---
+title: Add New Guides/Tutorials
+num: 7
+---
+
+## Why Contribute New Learning Material?
+
+As [Heather Miller writes][why-contribute], contributing to [docs.scala-lang.org][home] is
+critical to making Scala accessible to newcomers, experienced programmers, and anyone who is curious.
+It is also a fantastic way to contribute for anyone who is comfortable using Scala, but maybe does not want to get
+involved with complex tools like the compiler.
+
+## Architecture
+
+This documentation website is backed by an open-source [GitHub repository](https://github.com/scala/docs.scala-lang),
+and is always contribution-ready.
+
+### Content
+
+Currently, the _types_ of documentation supported in this repository are:
+
+- **Guides/Overviews/Books**: Definitive guides/overviews of specific language features. Often long, detailed documents,
+ often produced by members of the Scala team. An example is the [Collections][collections-overview] overview.
+- **References**: The canonical reference for language features, written by members of the Scala team.
+ These provide the exact specification to understand more subtle aspects of the language. An example is the
+ [Scala 3 reference][scala-3-reference].
+- **Tutorials**: Bite-size, example-rich, and concise articles meant to get a developer up to speed quickly.
+- **Cheatsheets**: Quick reference of Scala syntax and behaviors.
+
+### Implementation
+
+The website is statically generated from [Markdown](https://en.wikipedia.org/wiki/Markdown) source using
+[Jekyll](https://github.com/mojombo/jekyll), and hosted on [GitHub Pages](https://pages.github.com/).
+This workflow was chosen to help contributors to focus on writing helpful content, rather than on configuration and
+boilerplate. It also aids publishing a static site in a central location.
+
+The Markdown syntax being used supports [Maruku](https://github.com/bhollis/maruku) extensions, and has automatic
+syntax highlighting, without the need for any tags.
+
+Additionally, [mdoc](https://github.com/scalameta/mdoc) is used during pull requests to validate Scala code blocks.
+To use this feature you must use the backtick notation as documented by mdoc,
+[see here](#code-blocks) for an example.
+
+**Note:** only validation of code is done by mdoc, and no extra output is generated.
+
+## Submitting Docs
+
+To contribute a new document, you should first
+[fork](https://help.github.com/articles/fork-a-repo/) the
+[repo](https://github.com/scala/docs.scala-lang), then write your article in
+[Markdown](https://daringfireball.net/projects/markdown/syntax) (example below), and finally submit a pull request.
+Likely after some edits and discussion, your document will be made live
+on [docs.scala-lang.org][home].
+
+ ---
+ layout: singlepage-overview
+ title: My Awesome Title
+ ---
+
+ ## An h2 Header in Markdown
+
+ And a paragraph, with a [link](https://www.scala-lang.org).
+
+Tables of contents will be automatically generated in a sidebar for your document, and syntax highlighting
+is provided.
+
+### Criteria for Docs to be Accepted
+
+The goal of this documentation repository is to be highly curated, rather than the approach by other community-driven
+documentation platforms, like wikis. Therefore, to be included on [docs.scala-lang.org][home], a document must:
+
+- **"fit in"** to the repository (_i.e.,_ it should not be a complete duplicate of another article),
+- **be polished**, i.e. it must be thorough, complete, correct, and organized; written as an article to be understood
+ by many users.
+- **be maintained**, if the document might require revisions from time to time, be prepared to keep it up to date, or
+nominate someone to take ownership.
+
+If you have something you're thinking about contributing, or that you're thinking about writing in order to contribute
+-- we'd love to consider it! Please don't hesitate to use GitHub issues and pull requests and the
+`#scala-contributors` room [on Discord](https://discord.com/invite/scala) for any questions, concerns,
+clarifications, etc.
+
+## Code blocks
+
+It's common for various kinds of documents to require code examples.
+You can contribute code in a Markdown document by either
+- in-line by putting backticks around it,
+- surrounding by triple backticks,
+- or indenting it by 4 spaces, e.g.:
+
+~~~
+inline example: `val x = 23`
+
+block example:
+
+```scala
+println("hello")
+```
+
+indented example:
+
+ case class Foo(x: Int)
+~~~
+
+### Scala 2 vs Scala 3
+
+Our goal is to have a unified documentation that covers both Scala 2 and Scala 3. In many cases, the
+code examples are the same in both Scala 2 and Scala 3, but sometimes there are some syntactic
+differences. In some less common cases, a page may explain a concept that is new in Scala 3 and has
+no equivalent in Scala 2, or a concept that has been removed in Scala 3. In all the cases, the
+documentation should clearly "label" the code examples so that the readers know in which versions
+of Scala they are valid.
+
+The following sections explain how to properly "label" the code examples.
+
+#### Labelling the code snippets of a page documenting a concept available in both Scala 2 and Scala 3
+
+When the content of a page not specific to Scala 2 or Scala 3, like for example our
+[Hello World][hello-world] chapter of the Scala Book, the code snippets should show both the
+Scala 2 and Scala 3 syntax. We achieve this by labelling the code snippets in tabs according
+to the following rules:
+
+- if the idiomatic syntax is different in Scala 2 and Scala 3, we create two tabs,
+ “Scala 2” and “Scala 3”, showing the corresponding syntax
+- if the code snippet is idiomatic in both Scala 2 and Scala 3, we create a single tab,
+ “Scala 2 and 3”
+- if the code snippet is valid only in Scala 2 or Scala 3, we create a single tab,
+ “Scala 2 Only” or “Scala 3 Only”
+
+Here is an example of how you
+can generate such tabs in Markdown with the `tabs` directive and class `tabs-scala-version`:
+
+
+~~~liquid
+{% tabs hello-world-demo class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+object hello extends App {
+ println("Hello, World!")
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+@main def hello() = println("Hello, World!")
+```
+{% endtab %}
+
+{% endtabs %}
+~~~
+
+
+It is crucial that you use the `tabs-scala-version` class to benefit from some cool user interactions:
+- all other Scala version tabs on the same page will also switch to current tab, whenever one is changed.
+- the tab picked will be remembered across the site, and when the user returns to the page after some time.
+
+For code snippets that are valid in both Scala 2 and Scala 3, please use a single tab labelled
+`'Scala 2 and 3'` (please note that the `tabs-scala-version` class is also dropped):
+
+
+~~~liquid
+{% tabs scala-2-and-3-demo %}
+{% tab 'Scala 2 and 3' %}
+```scala
+List(1, 2, 3).map(x => x + 1).sum
+```
+{% endtab %}
+{% endtabs %}
+~~~
+
+
+For examples that only apply to either one of Scala 2 or 3, use the tabs `'Scala 2 Only'` and `'Scala 3 Only'`.
+
+If you have a particularly long tab, for readability you can indicate which tab group it belongs to with
+a parameter `for=tab-group` as in this example:
+
+~~~liquid
+{% tabs my-tab-group class=tabs-scala-version %}
+...
+{% tab 'Scala 3' for=my-tab-group %}
+...
+~~~
+
+
+#### Labelling an entire page documenting a concept that is specific to a Scala version
+
+When the content of a page explains a concept that is new in Scala 3 and has no
+equivalent in Scala 2 (e.g. [TASTy]({% link scala3/guides/tasty-overview.md %})),
+or a concept that has been removed in Scala 3, we label the entire page instead
+of labelling each code example.
+
+We achieve this by setting a couple of a attributes in the [YAML front
+matter](https://jekyllrb.com/docs/front-matter/) of the Markdown file. For
+instance, for a page that is specific to Scala 3:
+
+~~~ yaml
+scala3: true
+versionSpecific: true
+~~~
+
+Or, for a page that is specific to Scala 2:
+
+~~~ yaml
+scala2: true
+versionSpecific: true
+~~~
+
+Please note that when the entire page is labelled, its code examples do not
+need to have tabs.
+
+### Typechecked Examples
+
+The site build process uses [mdoc](https://scalameta.org/mdoc/) to typecheck
+code snippets in markdown. This is a great way to ensure the code snippets that
+you're including typecheck and are valid. Here are a few quick tips to get
+started:
+
+First, add `mdoc` after `scala` when you are creating a
+code block. The `mdoc` modifier here will make sure that `mdoc` runs the code
+snippet and ensures that it's valid.
+
+
+
+
+ ```scala mdoc
+val a = 1
+```
+
+If you have a snippet that you expect to fail, you can also account for this by
+using `mdoc:fail` for a compile error `mdoc:crash` for a runtime-error.
+
+
+
+Keep in mind that a single file is all compiled as a single unit, so you can't
+redefine a variable that was defined above in another code snippet. _However_
+there are a couple ways to get around this. Firstly, you can use the `mdoc:nest`
+modifier with will wrap the snippet in a `scala.Predef.locally{...}`. This will
+essentially "hide" the snippet from the others. Another way around this is to
+use the `mdoc:reset` modifier, which _resets_ and forgets about everything up
+above. Here is an example using the various modifiers.
+
+
```scala mdoc:nest
+caseclassFoo(a: Int) // conflicts with Foo above, but it's nested so it's fine
+```
+
+
```scala mdoc
+val a = s"The time is ${now()}"// still have access to the now method from above
+```
+
+
```scala mdoc:reset
+caseclassFoo(a: String) // forget the previous Foo's and start fresh
+```
+
+
```scala mdoc
+val myFoo = Foo("hi") // now we only have access to the last Foo
+```
+
+## Document Templates
+
+### Guides/Overviews
+
+A guide or an overview that can be logically placed on **one** markdown page should be placed in the directory
+`_overviews/RELEVANT-CATEGORY/`. It should have the header:
+
+ ---
+ layout: singlepage-overview
+ title: YOUR TITLE
+ ---
+
+The rest of the document will be written in [Markdown](https://en.wikipedia.org/wiki/Markdown) syntax.
+
+You may substitute `RELEVANT-CATEGORY` for any directory that is related, or create a new one if one is not suitable.
+
+If your guide/overview consists of **multiple** pages, like the [Collections][collections-overview] overview,
+an ordering must be specified, by numbering documents in their logical order with the `num` tag in the header,
+and a name must be assigned to the collection of pages using the `partof` tag.
+For example, the following header might be used for a document in the collections overview:
+
+ ---
+ layout: multipage-overview
+ title: YOUR TITLE
+
+ partof: collections
+ num: 10
+ ---
+
+**At least one** document in the collection must contain a tag in the header, `outof`, that indicates the total number
+of documents in the large overview. Putting it on the last page in the overview is often best:
+
+ ---
+ layout: multipage-overview
+ title: YOUR TITLE
+
+ partof: collections
+ num: 15
+ outof: 15
+ ---
+
+Index pages, such as [docs.scala-lang.org/overviews/index.html][overviews-index] are
+generated by reading data from a configuration file, such as `_data/overviews.yml`, so your overview should be
+placed into a category there.
+
+### Tutorials
+
+Tutorials are different to guides, they should be written in a much more concise, task-oriented style,
+usually on a single page.
+
+Similar to guides, tutorials also use the same markdown header.
+
+Once the tutorial is written, to aid user navigation their link must be added to
+the metadata of `/tutorials.md`. e.g. it could look like
+
+ ---
+ layout: root-index-layout
+ title: Tutorials
+
+ tutorials:
+ ...
+ - title: My New Tutorial
+ url: "/tutorials/my-new-tutorial.html"
+ description: "Learn How To Do This Specific Task"
+ icon: code
+ ---
+
+You must also add the tutorial to the drop-down list in the navigation bar. To do this, add an extra entry to
+`_data/doc-nav-header.yml`. i.e.
+
+ ---
+ - title: Getting Started
+ url: "/getting-started/install-scala.html"
+ - title: Learn
+ ...
+ - title: Tutorials
+ url: "#"
+ submenu:
+ ...
+ - title: My New Tutorial
+ url: "/tutorials/my-new-tutorial.html"
+ ...
+ ---
+
+### Cheatsheets
+
+Cheatsheets have a special layout, and the content is expected to be a Markdown table. To contribute a cheatsheet,
+you should use the following format:
+
+ ---
+ layout: cheatsheet
+ title: YOUR TITLE
+ by: YOUR NAME
+ about: SOME TEXT ABOUT THE CHEAT SHEET.
+ ---
+ | Title A | Title B |
+ |---------|---------|
+ | content | more |
+
+[collections-overview]: {% link _overviews/collections-2.13/introduction.md %}
+[why-contribute]: {% link contribute.md %}
+[home]: {% link index.md %}
+[overviews-index]: {% link _overviews/index.md %}
+[scala-3-reference]: {{ site.scala3ref }}
+[hello-world]: {% link _overviews/scala3-book/taste-hello-world.md %}
diff --git a/_overviews/contribute/bug-reporting-guide.md b/_overviews/contribute/bug-reporting-guide.md
new file mode 100644
index 0000000000..20dd04546c
--- /dev/null
+++ b/_overviews/contribute/bug-reporting-guide.md
@@ -0,0 +1,90 @@
+---
+title: Bug Reporting Guide
+num: 8
+---
+
+The Scala compiler and standard library bug tracker is located at [https://github.com/scala/bug](https://github.com/scala/bug), and for Scala 3, it is located at [github.com/scala/scala3](https://github.com/scala/scala3/issues). Before you submit a bug make sure that it is certainly a bug by following instructions
+in [Is it a Bug?](#is-it-a-bug).
+
+## Is it a Bug?
+
+The first step in identifying a bug is to identify which component of the Scala distribution is affected. First, ensure that your issue falls within any of the following categories:
+
+ - **Library** bugs typically manifest themselves as run-time exceptions, or as *unexpected*/*unintuitive* behavior of Scala Standard Library methods.
+ - **Compiler** errors are manifested as compile time exceptions, unexpected behavior of your code at run time, or invalid behavior of the type system.
+ - **Reflection** are bugs that appear in the `scala.reflect` package. For the *reflection* bugs, the same rules apply as for the *library* bugs.
+ - **Scaladoc** bugs are manifested as a logical problems in the information it presents (that is, the displayed information is incorrect, such as an incorrect subclassing relationship), or incorrect behavior of the user interface. If you'd like to suggest a change in the content of the documentation, please submit a pull request (possible to do in the browser using GitHub, which is easier and faster than filing a bug). Please file a bug about the content of documentation only if you cannot provide a suggestion for its fix.
+
+If your issue is related to any of the following external projects, make sure to use its appropriate issue tracker:
+
+ - [Akka](https://doc.akka.io/docs/akka/current/project/issue-tracking.html)
+ - [Play!](https://github.com/playframework/Play20/issues)
+ - [Slick](https://github.com/slick/slick/issues)
+ - [sbt](https://github.com/sbt/sbt/issues)
+
+The following are generally considered to be bugs:
+
+- **Scala Compiler Crash** If the Scala compiler is crashing with an internal error (compile time exception) you have certainly found a bug, and can move on to the next section of this document on reporting confirmed bugs.
+- **Regressions** If some code snippet worked in a previous Scala release, but now no longer compiles or results in an exception, it is probably a regression.
+- **Verify Errors** happen when the compiled Scala program is loaded to the Java Virtual Machine. If you're getting a *Verify Error*, you've usually found a bug. Make sure first that your project is not using stale `.class` files before reporting a new issue.
+
+If you have a code snippet that is resulting in bytecode which you believe is behaving incorrectly, you may or may not have found a bug. Before reporting your issue, please attempt the following:
+
+* Make sure you minimize your problem. To correctly minimize the problem follow the following instructions:
+
+ 1. Gradually remove parts from the original failing code snippet until you believe you have the simplest representation of your problem.
+
+ 2. Ensure that you have decoupled your code snippet from any library that could be introducing the incorrect behavior. One way to achieve this is to try to recompile the offending code snippet in isolation, outside the context of any complex build environment. If your code depends on some strictly Java library and source code is available for it, make sure that the latter is also minimized.
+
+ 3. Make sure you are compiling your project from a clean slate. Your problem could be related to separate compilation, which is difficult to detect without a clean build with new `.class` files.
+
+ 4. If you have encountered a bug while building your code in the IDE, then please reproduce it on the command line. The same rule applies for build tools like **sbt** or **Mill**.
+
+ 5. If you want to file an improvement in the issue tracker please discuss it first on one of the mailing lists. They offer much bigger audience than issue tracker. The latter is not suitable for long discussions.
+
+* Keep in mind that the behavior you are witnessing could be intended. Good formal resources for verifying whether the language behavior is intended is either in the [Scala Improvement Proposal Documents][sips] or in the [Scala Language Specification](https://www.scala-lang.org/files/archive/spec/2.13/). If in doubt, you may always ask on the [Community Category](https://contributors.scala-lang.org/c/community) or [Stack Overflow](https://stackoverflow.com/questions/tagged/scala).
+
+In general, if you find yourself stuck on any of these steps, asking on [Scala Contributors](https://contributors.scala-lang.org/) can be helpful:
+
+ - For unexpected behavior use the [Community Category](https://contributors.scala-lang.org/c/community).
+ - For compiler bugs use the [Compiler Category](https://contributors.scala-lang.org/c/compiler).
+
+* Examples of exceptions reported by the compiler which usually are not bugs:
+ 1. `StackOverflowError` is typically not a bug unless the stacktrace involves the internal packages of the compiler (like `scala.tools.nsc...`, or `dotty.tools.dotc...`). Try to increase the Java stack size (`-Xss`), in most of the cases it helps.
+ 2. `AbstractMethodError` can occur when you did not recompile all the necessary Scala files (build tools, like `sbt`, can prevent that from happening) or you are mixing external libraries compiled for different Scala versions (for example one uses `2.10.x` and the other `2.11.x`).
+
+## Please Check Before Reporting a Bug
+
+Before reporting your bug, make sure to check the issue tracker for other similar bugs. The exception name or a compiler phase are the best keywords to search for. If you are experiencing unexpected behavior search for method/class names where it happens. Your issue might already be reported, and a workaround might already be available for you take advantage of. If your issue *is* reported, be sure to add your test case as a comment if it is different from any of the existing ones.
+
+**Note:** reporting a bug that already exists creates an additional overhead for you, the Scala Team, and all people that search the issue database. To avoid this inconvenience make sure that you thoroughly search for an existing issue.
+
+If you cannot find your issue in the issue tracker, create a new bug. The details about creating a bug report are in the following section.
+
+## Creating a Bug Report
+
+Please make sure to fill in as many fields as possible. Make sure you've indicated the following:
+
+ 1. **Exact Scala version** that you are using. For example, `2.13.16` or `3.3.4`. If the bug happens in multiple versions indicate all of them.
+ 2. **The component** that is affected by the bug. For example, the Standard Library, Scaladoc, etc.
+ 3. **Labels** related to your issue. For example, if you think your issue is related to the typechecker, and if you have successfully minimized your issue, label your bug as "typechecker" and "minimized". Issue tracker will suggest names for existing labels as you type them so try not to create duplicates.
+ 4. **Running environment**. Are you running on Linux? Windows? What JVM version are you using?
+
+In order for us to quickly triage the bug that you've found, it's important that the code snippet which produces the observed issue is as minimized as possible. For advice on minimizing your code snippet, please see the appropriate subsection of the above ([Is it a Bug?](#is-it-a-bug)).
+
+### Description
+
+In the description of your issue, be as detailed as you can. Bug reports which have the following information included are typically understood, triaged, and fixed very quickly:
+1. Include a test case (minimized if possible) enabling us to reproduce the problematic behavior. Include your test
+case (and output) in properly formatted code blocks:
+~~~
+```scala
+List(1, 2, 3).map(x => x + 1)
+```
+~~~
+2. The expected output.
+3. The actual output, including the stacktrace.
+4. Related discussion on the mailing lists, if applicable.
+5. If you have already looked into the issue provide interesting insights or proposals for fixing the issue.
+
+[sips]: {% link _sips/index.md %}
diff --git a/_overviews/contribute/codereviews.md b/_overviews/contribute/codereviews.md
new file mode 100644
index 0000000000..cb49220627
--- /dev/null
+++ b/_overviews/contribute/codereviews.md
@@ -0,0 +1,60 @@
+---
+title: Code Review Contributions
+num: 3
+---
+## Code Review Contributions
+
+In addition to [bug fixing][bug-fixing], you can help us review
+[waiting pull requests](#pull-requests-awaiting-comment).
+This is also a good (and recommended) way to get to know the feel of
+the bug-fixing and submissions process before jumping in with your
+own pull requests.
+
+
+### Review Guidelines
+
+[Code of Conduct reminder](https://scala-lang.org/conduct.html)
+
+* Keep comments on-topic, concise and precise.
+* Attach comments to particular lines or regions they pertain to whenever possible.
+* Short code examples are often more descriptive than prose.
+* If you have thoroughly reviewed the PR and thought through all angles, LGTM (Looks Good To Me) is the preferred acceptance response.
+* Additional reviews should try to offer additional insights: "I also thought about it from this angle, and it still looks good.."
+* Above all, remember that the people you are reviewing might be reviewing your PRs one day too.
+* If you are receiving the review, consider that the advice is being given to make you, and Scala, better rather than as a negative critique. Assume the best, rather than the worst.
+
+## Pull Requests Awaiting Comment
+
+
For other PRs, follow the scala project from here.
+
+
+
+
+Also note that the [Tools contributions][tools] page has more projects that will generate pull requests.
+
+[bug-fixing]: {% link _overviews/contribute/guide.md %}
+[tools]: {% link _overviews/contribute/tools.md %}
diff --git a/_overviews/contribute/corelibs.md b/_overviews/contribute/corelibs.md
new file mode 100644
index 0000000000..4fcab907a2
--- /dev/null
+++ b/_overviews/contribute/corelibs.md
@@ -0,0 +1,21 @@
+---
+title: Core Library Contributions
+num: 4
+---
+## Core Library Contributions
+
+There are several options for contributing to Scala's core libraries. You can:
+
+* Help with [Documentation][documentation].
+* [Report Bugs or Issues][bug-reporting-guide] against the core libraries.
+* [Fix Bugs or Issues][guide] against the
+ [reported library bugs/issues](https://github.com/scala/bug).
+
+### Significant changes
+
+For significant new functionality or a whole new API to be considered for inclusion in the core Scala distribution,
+please take into account [scala/scala-dev#661](https://github.com/scala/scala-dev/issues/661) before doing so.
+
+[documentation]: {% link _overviews/contribute/documentation.md %}
+[bug-reporting-guide]: {% link _overviews/contribute/bug-reporting-guide.md %}
+[guide]: {% link _overviews/contribute/guide.md %}
diff --git a/_overviews/contribute/documentation.md b/_overviews/contribute/documentation.md
new file mode 100644
index 0000000000..469396e40c
--- /dev/null
+++ b/_overviews/contribute/documentation.md
@@ -0,0 +1,60 @@
+---
+title: Documentation Contributions
+num: 5
+---
+## Contributing Documentation to the Scala project
+
+There are several ways you can help out with the improvement of Scala documentation. These include:
+
+* API Documentation in Scaladoc
+* Guides, Overviews, Tutorials, Cheat Sheets and more on the [docs.scala-lang.org][home] site
+* Updating [scala-lang.org](https://scala-lang.org)
+
+Please read this page, and the pages linked from this one, fully before contributing documentation. Many frequently asked questions will be answered in these resources. If you have a question that isn't answered, feel free to ask on the [Scala Contributors](https://contributors.scala-lang.org/) forum and then, please, submit a pull request with updated documentation reflecting that answer.
+
+**General requirements** for documentation submissions include spell-checking all written language, ensuring code samples compile and run correctly, correct grammar, and clean formatting/layout of the documentation.
+
+Thanks
+
+### API Documentation (Scaladoc)
+
+The Scala API documentation lives with the scala project source code. There are many ways you can help with improving Scaladoc, including:
+
+* [Log issues for missing scaladoc documentation][report-api-doc-bugs] -
+Please *follow the issue submission process closely* to help prevent duplicate issues being created.
+* [Claim Scaladoc Issues and Provide Documentation][scala-standard-library-api-documentation] - please claim issues prior to working on a specific scaladoc task to prevent duplication of effort. If you sit on an issue for too long without submitting a pull request, it will revert to unassigned, and you will need to re-claim it.
+* You can also just
+[submit new Scaladoc][scala-standard-library-api-documentation]
+without creating an issue, but please look to see if there is an issue already submitted for your task and claim it if there is. If not, please post your intention to work on a specific scaladoc task on [Scala Contributors](https://contributors.scala-lang.org/) so that people know what you are doing.
+
+### The Main Scala Documentation Site
+
+[docs.scala-lang.org][home] houses the primary source of written, non-API documentation for Scala. It's a GitHub project that you can fork and submit pull requests from. It includes:
+
+* Overviews
+* Tutorials
+* Conversion Guides from Other Languages
+* Cheat Sheets
+* A Glossary
+* The Scala Style Guide
+* The Scala Language Specification
+* SIP (Scala Improvement Process) Proposals
+and more
+
+Please read [Add New Guides/Tutorials][add-guides] through before embarking on changes. The site uses
+the [Jekyll](https://jekyllrb.com/) Markdown engine, so you will need to follow the instructions to get that running as well.
+
+### Updating scala-lang.org
+
+Additional high-level documentation (including documentation on contributing
+to Scala and related projects) is provided on the main
+[Scala Language site](https://scala-lang.org), and is also kept in the
+[scala-lang GitHub project](https://github.com/scala/scala-lang) which may be forked to create pull requests.
+
+Please read both the
+[Add New Guides/Tutorials][add-guides] document and the [scala-lang.org GitHub README](https://github.com/scala/scala-lang#scala-langorg) before embarking on any changes to the Scala language site, as it uses the same Jekyll markdown tool and many of the same conventions as the Scala documentation site.
+
+[report-api-doc-bugs]: {% link _overviews/contribute/scala-standard-library-api-documentation.md %}#contribute-api-documentation-bug-reports
+[scala-standard-library-api-documentation]: {% link _overviews/contribute/scala-standard-library-api-documentation.md %}
+[home]: {% link index.md %}
+[add-guides]: {% link _overviews/contribute/add-guides.md %}
diff --git a/_overviews/contribute/guide.md b/_overviews/contribute/guide.md
new file mode 100644
index 0000000000..f5307a325a
--- /dev/null
+++ b/_overviews/contribute/guide.md
@@ -0,0 +1,84 @@
+---
+title: Contributing guide
+num: 10
+---
+
+| **Shortcut** | **Description** |
+|----------------------------------------|-----------------|
+| [Scala Contributors][contrib-forum] | Get a peek into the inners of the Scala compiler. |
+| [Report an Issue][bug-reporting-guide] | File a bug report or a feature request. |
+| [Community Issues][community-tickets] | Get cracking on some easy to approach issues. |
+| [Scala 2 Hacker's Guide][hackers] | Learn to write good code and improve your chances of contributing to the Scala galaxy. |
+| [Scala 3 Contributing Guide][scala3-hackers] | Walkthrough contributing to the Scala 3 compiler, along with a guide to compiler internals. |
+
+
+
+### Why contribute a patch to Scala?
+
+Just to name a few common reasons:
+
+* contributing a patch is the best way to make sure your desired changes will be available in the next Scala version
+* Scala is written in Scala, so going through the source code and patching it will improve your knowledge of Scala.
+* last but not least, it only takes a few accepted commits to make it into the [Scala Contributor Hall of Fame](https://github.com/scala/scala/contributors).
+
+The main Scala project consists of the standard Scala library, the Scala reflection and macros library,
+the Scala compiler and the Scaladoc tool. This means there's plenty to choose from when deciding what to work on.
+Typically, the scaladoc tool provides a low entry point for new committers, so it is a good first step into contributing.
+
+On the [Scala bug tracker](https://github.com/scala/bug) you will find the bugs that you could pick up. Once you decided on a ticket to look at, see the next step on how to proceed further.
+
+If you are interested in contributing code, we ask you to sign the
+[Scala Contributor License Agreement](https://www.lightbend.com/contribute/cla/scala),
+which allows us to ensure that all code submitted to the project is
+unencumbered by copyrights or patents.
+
+### Bug-fix Check List
+> Originally these steps cover the [Scala 2 compiler](https://github.com/scala/scala), but they also are relevant to
+> the [Scala 3 compiler](https://github.com/scala/scala3).
+
+This is the impatient developer's checklist for the steps to submit a bug-fix pull request to the Scala project. For more information, description and justification for the steps, follow the links in that step. Further specific instructions for the release of Scala you are targeting can be found in the `CONTRIBUTING.md` file for that [GitHub branch](https://github.com/scala/scala)
+
+1. [Select a bug to fix from GitHub][community-tickets], or if you found the bug yourself and want to fix it, [create a GitHub issue][bug-reporting-guide] (but please
+[make sure it's not a duplicate][bug-report-check-dupes]).
+2. Optional ([but recommended][why-its-a-good-idea]), announce your intention to work on the bug on [Scala Contributors](https://contributors.scala-lang.org/). After all, don't you want to work on a team with
+[these friendly people][hackers-connect] - it's one of the perks of contributing.
+3. [Fork the Scala repository][hackers-fork] and clone your fork (if you haven't already).
+4. [Create a feature branch][hackers-branch] to work on: use the branch name `issue/NNNN` where NNNN is the GitHub issue number.
+5. [Fix the bug, or implement the new small feature][hackers-implement], include new tests (yes, for bug fixes too).
+6. [Test, rinse][hackers-test] and [test some more][partest-guide] until [all the tests pass][hackers-verify].
+7. [Commit your changes][hackers-commit] to your feature branch in your fork. Please choose your commit message based on the [Git Hygiene](https://github.com/scala/scala#user-content-git-hygiene) section of the Scala project README.
+8. If necessary [re-write git history](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) so that [commits are organized by major steps to the fix/feature](
+https://github.com/scala/scala#git-hygiene). For bug fixes, a single commit is requested, for features several commits may be desirable (but each separate commit must compile and pass all tests)
+9. [Submit a pull request][hackers-submit].
+10. [Work with a reviewer](https://github.com/scala/scala#reviewing) to [get your pull request merged in][hackers-review].
+11. Celebrate!
+
+Need more information or a little more hand-holding for the first one? We got you covered: take a read through the entire [Hacker Guide][hackers] (or the [equivalent Scala 3 Contributing Guide][scala3-hackers]) for an example of implementing a new feature (some steps can be skipped for bug fixes, this will be obvious from reading it, but many of the steps here will help with bug fixes too).
+
+### Larger Changes, New Features
+
+For larger, more ambitious changes (e.g. new language features), the first step to making a change is to discuss it with the community at large, to make sure everyone agrees on the idea
+and on the implementation plan. Announce the change
+on the [Scala Contributors](https://contributors.scala-lang.org/) mailing list and get developer feedback. For really complex changes, a [Scala Improvement Process (SIP)][sips] document might be required, but the first step is always to discuss it on the mailing list and if a SIP is required, that will be discussed on the mailing list.
+
+Contributions, big or small, simple or complex, controversial or undisputed, need to materialize as patches against
+the Scala project source tree. The hacker's guides ([Scala 2][hackers], or [Scala 3][scala3-hackers]) will explain how to materialize your idea into a full-fledged pull request against the Scala code base.
+
+[hackers]: {% link _overviews/contribute/hacker-guide.md %}
+[community-tickets]: {% link _overviews/contribute/index.md %}#community-tickets
+[bug-reporting-guide]: {% link _overviews/contribute/bug-reporting-guide.md %}
+[bug-report-check-dupes]: {% link _overviews/contribute/bug-reporting-guide.md %}#please-check-before-reporting-a-bug
+[scala3-hackers]: {% link _overviews/contribute/scala3.md %}
+[contrib-forum]: https://contributors.scala-lang.org/
+[why-its-a-good-idea]: {% link _overviews/contribute/scala-internals.md %}#why-its-a-good-idea
+[hackers-connect]: {% link _overviews/contribute/hacker-guide.md %}#1-connect
+[hackers-fork]: {% link _overviews/contribute/hacker-guide.md %}#fork
+[hackers-branch]: {% link _overviews/contribute/hacker-guide.md %}#branch
+[hackers-implement]: {% link _overviews/contribute/hacker-guide.md %}#implement
+[hackers-test]: {% link _overviews/contribute/hacker-guide.md %}#test
+[hackers-verify]: {% link _overviews/contribute/hacker-guide.md %}#verify
+[hackers-commit]: {% link _overviews/contribute/hacker-guide.md %}#commit
+[hackers-submit]: {% link _overviews/contribute/hacker-guide.md %}#submit
+[hackers-review]: {% link _overviews/contribute/hacker-guide.md %}#review
+[partest-guide]: {% link _overviews/contribute/partest-guide.md %}
+[sips]: {% link _sips/index.md %}
diff --git a/_overviews/contribute/hacker-guide.md b/_overviews/contribute/hacker-guide.md
new file mode 100644
index 0000000000..ea77feee0d
--- /dev/null
+++ b/_overviews/contribute/hacker-guide.md
@@ -0,0 +1,387 @@
+---
+title: Scala 2 Hacker's Guide
+by: Eugene Burmako
+num: 12
+---
+
+This guide is intended to help you get from an idea of fixing a bug or implementing a new feature into a nightly Scala build, and, ultimately, to a production release of Scala incorporating your idea.
+
+This guide covers the entire process, from the conception of your idea or bugfix to the point where it is merged into Scala. Throughout, we will use a running example of an idea or bugfix one might wish to contribute.
+
+Other good starting points for first-time contributors include the [Scala README](https://github.com/scala/scala#get-in-touch) and [contributor's guidelines](https://github.com/scala/scala/blob/2.13.x/CONTRIBUTING.md).
+
+## The Running Example
+
+Let's say that you particularly enjoy the new string interpolation language feature introduced in Scala 2.10.0, and you use it quite heavily.
+
+Though, there's an annoying issue
+which you occasionally stumble upon: the formatting string interpolator `f` [does not support](https://github.com/scala/bug/issues/6725)
+new line tokens `%n`.
+
+One approach would be to go the [Scala 2 bug tracker](https://github.com/scala/bug), request that the bug be fixed, and then to wait indefinitely for the fix arrive. Another approach would be to instead patch Scala yourself, and to submit the fix to the Scala repository in hopes that it might make it into a subsequent release.
+
+**_Of note_**: There are several types of releases/builds. Nightly builds are produced every night at a fixed time. Minor releases happen once every few months. Major releases typically happen once per year.
+
+## 1. Connect
+
+Sometimes it's appealing to hack alone and not to have to interact with others. However, in the context a big project such as Scala, there might be better ways. There are people in the Scala community who have spent years accumulating knowledge about Scala libraries and internals. They might provide
+unique insights and, what's even better, direct assistance in their areas, so it is not only advantageous, but recommended to communicate with the community about your new patch.
+
+Typically, bug fixes and new features start out as an idea or an experiment posted on one of [our forums](https://scala-lang.org/community/index.html#forums) to find out how people feel
+about things you want to implement. People proficient in certain areas of Scala usually monitor forums and discussion rooms, so you'll often get some help by posting a message.
+But the most efficient way to connect is to mention in your message one of the people responsible for maintaining the aspect of Scala which you wish to contribute to.
+
+A list of language features/libraries along with their maintainer's full names and GitHub usernames is [in the Scala repo README](https://github.com/scala/scala#get-in-touch).
+
+In our running example, since Martin is the person who submitted the string interpolation Scala Improvement Proposal and implemented this language feature for Scala 2.10.0, he might be interested in learning of new bugfixes to that feature.
+
+As alluded to earlier, one must also choose an appropriate avenue to discuss the issue. Typically, one would use the [Scala Contributor's Forum][contrib-forum], as there are post categories devoted to discussions about the core internal design and implementation of the Scala system.
+
+In this example, the issue was previously discussed on the (now unused) scala-user mailing list, at the time,
+we would have posted to [the (now unused) scala-user mailing list](https://groups.google.com/group/scala-user) about our issue:
+
+
+
+
+Now that we have the approval of the feature's author, we can get to work!
+
+## 2. Set up
+
+Hacking Scala begins with creating a branch for your work item. To develop Scala we use [Git](https://git-scm.com/)
+and [GitHub](https://github.com/). This section of the guide provides a short walkthrough, but if you are new to Git,
+it probably makes sense to familiarize yourself with Git first. We recommend
+
+* the [Git Pro](https://git-scm.com/book/en/v2) online book.
+* the help page on [Forking a Git Repository](https://help.github.com/articles/fork-a-repo).
+* this great training tool [LearnGitBranching](https://pcottle.github.io/learnGitBranching/). One-hour hands-on training helps more than 1000 hours reading.
+
+### Fork
+
+Log into [GitHub](https://github.com/), go to [https://github.com/scala/scala](https://github.com/scala/scala) and click the `Fork`
+button in the top right corner of the page. This will create your own copy of our repository that will serve as a scratchpad for your work.
+
+If you're new to Git, don't be afraid of messing up-- there is no way you can corrupt our repository.
+
+
+
+### Clone
+
+If everything went okay, you will be redirected to your own fork at `https://github.com/user-name/scala`, where `username`
+is your GitHub username. You might find it helpful to read [https://help.github.com/fork-a-repo/](https://help.github.com/fork-a-repo/),
+which covers some things that will follow below. Then, _clone_ your repository (i.e. pull a copy from GitHub to your local machine) by running the following on the command line:
+
+ 16:35 ~/Projects$ git clone https://github.com/xeno-by/scala
+ Cloning into 'scala'...
+ remote: Counting objects: 258564, done.
+ remote: Compressing objects: 100% (58239/58239), done.
+ remote: Total 258564 (delta 182155), reused 254094 (delta 178356)
+ Receiving objects: 100% (258564/258564), 46.91 MiB | 700 KiB/s, done.
+ Resolving deltas: 100% (182155/182155), done.
+
+This will create a local directory called `scala`, which contains a clone of your own copy of our repository. The changes that you make
+in this directory can be propagated back to your copy hosted on GitHub and, ultimately, pushed into Scala when your patch is ready.
+
+### Branch
+
+Before you start making changes, always create your own branch. Never work on the `master` branch. Think of a name that describes
+the changes you plan on making. Use a prefix that describes the nature of your change. There are essentially two kinds of changes:
+bug fixes and new features.
+
+* For bug fixes, use `issue/NNNN` or `ticket/NNNN` for bug `NNNN` from the [Scala bug tracker](https://github.com/scala/bug).
+* For new feature use `topic/XXX` for feature `XXX`. Use feature names that make sense in the context of the whole Scala project and not just to you personally. For example, if you work on diagrams in Scaladoc, use `topic/scaladoc-diagrams` instead of just `topic/diagrams` would be a good branch name.
+
+Since in our example, we're going to fix an existing bug
+[scala/bug#6725](https://github.com/scala/bug/issues/6725), we'll create a branch named `ticket/6725`.
+
+ 16:39 ~/Projects/scala (master)$ git checkout -b ticket/6725
+ Switched to a new branch 'ticket/6725'
+
+If you are new to Git and branching, read the [Branching Chapter](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell) in the Git Pro book.
+
+### Build
+
+The next step after cloning your fork is setting up your machine to build Scala.
+
+You need the following tools:
+
+* A Java JDK. The baseline version is `8` for 2.13.x and higher. It's possible to use a higher JDK version for local development, but the continuous integration builds will verify against the baseline version.
+* `sbt`, an interactive build tool commonly used in Scala projects. Acquiring sbt manually is not necessary -- the recommended approach is to download the [sbt-extras runner script](https://github.com/paulp/sbt-extras/blob/master/sbt) and use it in place of `sbt`. The script will download and run the correct version of sbt when run from the Scala repository's root directory.
+* `curl` -- the build uses `curl` in the `pull-binary-libs.sh` script to download bootstrap libs.
+
+macOS and Linux builds should work. Windows is supported, but it might have issues. Please report to the [Scala 2 bug tracker](https://github.com/scala/bug) if you encounter any.
+
+Building Scala can be done with a single command `sbt dist/mkPack`, from the root of your cloned repository. In general, it's much more efficient to enter the `sbt` shell once and run the various tasks from there, instead of running each task by launching `sbt some-task` on your command prompt.
+
+Be prepared to wait for a while -- a full "clean" build takes 5+ minutes depending on your machine (longer on older machines with less memory). On a recent laptop, incremental builds usually complete within 10-30 seconds.
+
+### IDE
+
+There's no single editor of choice for working with Scala sources, as there are trade-offs associated with each available tool.
+
+IntelliJ IDEA has a Scala plugin, which is known to work with our codebase. Alternatively you can use Visual Studio Code with the [Metals IDE extension](https://marketplace.visualstudio.com/items?itemName=scalameta.metals).
+Both of these Scala IDE solutions provide navigation, refactoring, error reporting functionality, and integrated debugging.
+See [the Scala README](https://github.com/scala/scala#ide-setup) for instructions on using either IntelliJ IDEA or Metals with the Scala repository.
+
+Other alternative editors exist, such as Atom, Emacs, Sublime Text or jEdit. These are faster and much less memory/compute-intensive to run, but lack semantic services and debugging.
+
+We recognise that there exist preferences towards specific IDE/editor experiences, so ultimately we recommend that your choice be your personal preference.
+
+## 3. Hack
+
+When hacking on your topic of choice, you'll be modifying Scala, compiling it and testing it on relevant input files.
+Typically, you would want to first make sure that your changes work on a small example and afterwards verify that nothing break
+by running a comprehensive test suite.
+
+We'll start by creating a `sandbox` directory (`./sandbox` is listed in the .gitignore of the Scala repository), which will hold a single test file and its compilation results. First, let's make sure that
+[the bug](https://github.com/scala/bug/issues/6725) is indeed reproducible by putting together a simple test and compiling and running it with the Scala compiler that we built using `sbt`. The Scala compiler that we just built is located in `build/pack/bin`.
+
+ 17:25 ~/Projects/scala (ticket/6725)$ mkdir sandbox
+ 17:26 ~/Projects/scala (ticket/6725)$ cd sandbox
+ 17:26 ~/Projects/scala/sandbox (ticket/6725)$ edit Test.scala
+ 17:26 ~/Projects/scala/sandbox (ticket/6725)$ cat Test.scala
+ object Test extends App {
+ val a = 1
+ val s = f"$a%s%n$a%s"
+ println(s)
+ }
+ 17:27 ~/Projects/scala/sandbox (ticket/6725)$ ../build/pack/bin/scalac Test.scala
+ 17:28 ~/Projects/scala/sandbox (ticket/6725)$ ../build/pack/bin/scala Test
+ 1%n1 // %n should've been replaced by a newline here
+
+### Implement
+
+Now, implement your bugfix or new feature!
+
+Here are also some tips & tricks that have proven useful in Scala development:
+
+* After building your working copy with the `compile` sbt task, there's no need to leave the comfort of your sbt shell to try it out: the REPL is available as the `scala` task, and you can also run the compiler using the `scalac` task. If you prefer to run the REPL outside sbt, you can generate the scripts in `build/quick/bin` using the `dist/mkQuick` task.
+* The sbt workflow is also great for debugging, as you can create a remote debugging session in your favorite IDE, and then activate the JVM options for the next time you run the `scala` or `scalac` tasks using:
+
+```
+> set javaOptions in compiler := List("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8002")
+> scalac test.scala
+[info] Running scala.tools.nsc.Main -usejavacp test.scala
+Listening for transport dt_socket at address: 8002
+```
+
+* Also see [the Scala README](https://github.com/scala/scala#incremental-compilation) for tips on speeding up compile times.
+* If after introducing changes or updating your clone, you get `AbstractMethodError` or other linkage exceptions, try the `clean` task and building again.
+* Don't underestimate the power of using `println` to print debug information. When starting with Scala, I spent a lot of time in the debugger trying to figure out how
+ things work. However later I found out that print-based debugging is often more effective than jumping around. It's also useful to print stack traces to understand the flow of execution, for example what code executed before some action occurred. When working with `Trees`, you might want to use `showRaw` to get the `AST` representation.
+* You can publish your newly-built scala version locally using the `publishLocal` task in sbt.
+* It's convenient to enable the following local settings to speed up your workflow (put these in `local.sbt` in your working copy):
+
+```
+// skip docs for local publishing
+publishArtifact in (Compile, packageDoc) in ThisBuild := false
+// set version based on current sha, so that you can easily consume this build from another sbt project
+baseVersionSuffix := s"local-${Process("tools/get-scala-commit-sha").lines.head.substring(0, 7)}"
+// show more logging during a partest run
+testOptions in IntegrationTest in LocalProject("test") ++= Seq(Tests.Argument("--show-log"), Tests.Argument("--show-diff"))
+// if incremental compilation is compiling too much (should be fine under sbt 0.13.13)
+// antStyle := true
+```
+
+* Adding a macro to the `Predef` object is a pretty involved task. Due to bootstrapping, it makes it more complex to add a macro. For this reason, the process is more involved. It could be useful to replicate the way `StringContext.f` itself is added. In short, you need to define your macro under `src/compiler/scala/tools/reflect/` and provide no implementation in `Predef` (it will look like `def fn = macro ???`). Now you have to set up the wiring. Add the name of your macro to `src/reflect/scala/reflect/internal/StdNames.scala`, add the needed links to it to `src/reflect/scala/reflect/internal/Definitions.scala`, and finally specify the bindings in `src/compiler/scala/tools/reflect/FastTrack.scala`. [Here's](https://github.com/folone/scala/commit/59536ea833ca16c985339727baed5d70e577b0fe) an example of adding a macro.
+
+### Where to Find Documentation
+
+The separate projects under Scala have varying amounts of documentation:
+
+##### The Scala Library
+
+Contributing to the Scala standard library is about the same as working on one of your own libraries.
+
+If documentation is necessary for some trait/class/object/method/etc in the Scala standard library, typically maintainers will include inline comments describing their design decisions or rationale for implementing things the way they have, if it is not straightforward.
+
+The Scala collections framework, part of the Scala standard library, is more complex. You should become familiar
+with its architecture, which is documented in [the Architecture of Scala Collections][collections-arch].
+The [Scala Collections Guide][collections-intro] is more general, covering the synchronous portion of collections. For parallel collections, there also exists a detailed [Scala Parallel Collections Guide][collections-par].
+
+##### The Scala Compiler
+
+Documentation about the internal workings of the Scala compiler is scarce, and most of the knowledge is passed around by forum ([Scala Contributors](https://contributors.scala-lang.org/) forum), chat-rooms (see `#scala-contributors` on [Discord][discord-contrib]), ticket, or word of mouth. However, the situation is steadily improving. Here are the resources that might help:
+
+* [Compiler internals videos by Martin Odersky](https://www.scala-lang.org/old/node/598.html) are quite dated, but still very useful. In this three-video
+ series Martin explains the general architecture of the compiler, and the basics of the front-end, which later became the `scala-reflect` module's API.
+* [Reflection documentation][reflect-overview] describes fundamental data structures (like `Tree`s, `Symbol`s, and `Types`) that
+ are used to represent Scala programs and operations defined on then. Since much of the compiler has been factored out and made accessible via the `scala-reflect` module, all the fundamentals needed for reflection are the same for the compiler.
+* [Scala compiler corner](https://lampwww.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/) contains extensive documentation about
+ most of the post-typer phases (i.e. the backend) in the Scala compiler.
+* [Scala Contributors](https://contributors.scala-lang.org/), a forum which hosts discussions about the core
+ internal design and implementation of the Scala system.
+
+##### Other Projects
+
+Tools like Scaladoc also welcome contributions. Unfortunately these smaller projects have less developer documentation. In these cases, the best thing to do is to directly explore the code base (which often contains documentation as inline comments) or to write to the appropriate maintainers for pointers.
+
+### Interlude
+
+To fix [the bug we're interested in](https://github.com/scala/bug/issues/6725) we've tracked the `StringContext.f` interpolator
+down to a macro implemented in `MacroImplementations.scala` There we notice that the interpolator only processes conversions,
+but not tokens like `%n`. Looks like an easy fix.
+
+ 18:44 ~/Projects/scala/sandbox (ticket/6725)$ git diff
+ diff --git a/src/compiler/scala/tools/reflect/MacroImplementations.scala b/src/compiler/scala/tools/
+ index 002a3fce82..4e8f02084d 100644
+ --- a/src/compiler/scala/tools/reflect/MacroImplementations.scala
+ +++ b/src/compiler/scala/tools/reflect/MacroImplementations.scala
+ @@ -117,7 +117,8 @@ abstract class MacroImplementations {
+ if (!strIsEmpty) {
+ val len = str.length
+ while (idx < len) {
+ - if (str(idx) == '%') {
+ + def notPercentN = str(idx) != '%' || (idx + 1 < len && str(idx + 1) != 'n')
+ + if (str(idx) == '%' && notPercentN) {
+ bldr append (str substring (start, idx)) append "%%"
+ start = idx + 1
+ }
+
+After applying the fix and running `sbt compile`, our simple test case in `sandbox/Test.scala` started working!
+
+ 18:51 ~/Projects/scala/sandbox (ticket/6725)$ cd ..
+ 18:51 ~/Projects/scala (ticket/6725)$ sbt compile
+ ...
+ [success] Total time: 18 s, completed Jun 6, 2016 9:03:02 PM
+ Total time: 18 seconds
+
+ 18:51 ~/Projects/scala (ticket/6725)$ cd sandbox
+ 18:51 ~/Projects/scala/sandbox (ticket/6725)$ ../build/pack/bin/scalac Test.scala
+ 18:51 ~/Projects/scala/sandbox (ticket/6725)$ ../build/pack/bin/scala Test
+ 1
+ 1 // no longer getting the %n here - it got transformed into a newline
+
+### Test
+
+To guard your change against accidental breakage in the future, it is important to add tests.
+I have already written one test earlier, so that's a good start but not enough! Apart from obvious usages of our new functionality, we need to cover corner-cases as well.
+
+Adding tests to the test suite is as easy as moving them to the appropriate directory:
+
+* Code which should compile successfully, but doesn't need to be executed, needs to go into the [“pos” directory](https://github.com/scala/scala/tree/2.12.x/test/files/pos).
+* Code which should not compile needs to go into the [“neg” directory](https://github.com/scala/scala/tree/2.12.x/test/files/neg).
+* Code which should compile and get executed by the test suite needs to go into the [“run” directory](https://github.com/scala/scala/tree/2.12.x/test/files/run) and have a corresponding `.check` file with the expected output. You will get test failures if the content of a `.check` file is different from what the test produces while running. If the change in the output is an expected product of your work, you might not want to change the `.check` file by hand. To make partest change the `.check` file, run it with a `--update-check` flag, like so `./test/partest --update-check path/to/test.scala`. For more information on partest, please refer to its [documentation](https://github.com/scala/scala-partest).
+* Everything that can be unit-tested should go to ["junit" directory](https://github.com/scala/scala/tree/2.12.x/test/junit)
+* Property-based tests go to the ["scalacheck" directory](https://github.com/scala/scala/tree/2.12.x/test/scalacheck)
+
+Here are some more testing tips:
+
+* If you have several tests, and want a tool for only running tests that conform to some regular expression, you can use `partest-ack` in the `tools` directory: `./tools/partest-ack "dottype"`. `partest-ack` was removed in 2.12.
+* If you want to run all scalacheck tests from sbt use `scalacheck/testOnly`
+* To run scalacheck tests by name when in sbt use `scalacheck/testOnly ... `, for example `scalacheck/testOnly scala.tools.nsc.scaladoc.HtmlFactoryTest`
+* If your tests fail in the following way:
+
+ test.bc:
+ [echo] Checking backward binary compatibility for scala-library (against 2.11.0)
+ [mima] Found 2 binary incompatibiities
+ [mima] ================================
+ [mima] * synthetic method
+ [mima] scala$package$Class$method(java.lang.String)Unit in trait
+ [mima] scala.package.Class does not have a correspondent in old version
+ [mima] * synthetic method
+ [mima] scala$package$AnotherClass$anotherMethod(java.lang.String)Unit in trait
+ [mima] scala.package.AnotherClass does not have a correspondent in old version
+ [mima] Generated filter config definition
+ [mima] ==================================
+ [mima]
+ [mima] filter {
+ [mima] problems=[
+ [mima] {
+ [mima] matchName="scala.package.Class$method"
+ [mima] problemName=MissingMethodProblem
+ [mima] },
+ [mima] {
+ [mima] matchName="scala.package.AnotherClass$anotherMethod"
+ [mima] problemName=MissingMethodProblem
+ [mima] }
+ [mima] ]
+ [mima] }
+ [mima]
+
+ ...
+ Finished: FAILURE
+
+This means your change is backward or forward binary incompatible with the specified version (the check is performed by the [migration manager](https://github.com/typesafehub/migration-manager)). The error message is actually saying what you need to modify `project/MimaFilters.scala` to make the error go away. If you are getting this on an internal/experimental api, it should be safe to add suggested sections to the config. Otherwise, you might want to target a newer version of scala for this change.
+
+### Verify
+
+Now to make sure that my fix doesn't break anything I need to run the test suite. The Scala test suite uses [JUnit](https://junit.org/junit4/) and [partest][partest-guide], a tool we wrote for testing Scala.
+Run `sbt test` and `sbt partest` to run all the JUnit and partest tests, respectively.
+`partest` (not `sbt partest`) also allows you to run a subset of the tests using wildcards:
+
+ 18:52 ~/Projects/scala/sandbox (ticket/6725)$ cd ../test
+ 18:56 ~/Projects/scala/test (ticket/6725)$ partest files/run/*interpol*
+ Testing individual files
+ testing: [...]/files/run/interpolationArgs.scala [ OK ]
+ testing: [...]/files/run/interpolationMultiline1.scala [ OK ]
+ testing: [...]/files/run/interpolationMultiline2.scala [ OK ]
+ testing: [...]/files/run/sm-interpolator.scala [ OK ]
+ testing: [...]/files/run/interpolation.scala [ OK ]
+ testing: [...]/files/run/stringinterpolation_macro-run.scala [ OK ]
+ All of 6 tests were successful (elapsed time: 00:00:08)
+
+## 4. Publish
+
+After development is finished, it's time to publish the code and submit your patch for discussion and potential inclusion into Scala.
+In a nutshell, this involves:
+
+1. making sure that your code and commit messages are of high quality,
+2. clicking a few buttons in the GitHub interface,
+3. assigning one or more reviewers who will look through your pull request.
+
+Let's go into each of these points in more detail.
+
+### Commit
+
+The [Git Basics](https://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository) chapter in the Git online book covers most of the basic workflow during this stage.
+There are two things you should know here:
+
+1. Commit messages are often the only way to understand the intentions of authors of code written a few years ago. Thus, writing a quality is of utmost importance. The more context you provide for the change you've introduced, the larger the chance that some future maintainer understand your intentions. Consult [the pull request policies](https://github.com/scala/scala/blob/2.12.x/CONTRIBUTING.md) for more information about the desired style of your commits.
+2. Keeping Scala's git history clean is also important. Therefore we won't accept pull requests for bug fixes that have more than one commit. For features, it is okay to have several commits, but all tests need to pass after every single commit. To clean up your commit structure, you want to [rewrite history](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) using `git rebase` so that your commits are against the latest revision of `master`.
+
+Once you are satisfied with your work, synced with `master` and cleaned up your commits you are ready to submit a patch to the central Scala repository. Before proceeding make sure you have pushed all of your local changes to your fork on GitHub.
+
+ 19:22 ~/Projects/scala/test (ticket/6725)$ git add ../src/compiler/scala/tools/reflect/MacroImplementations.scala
+ 19:22 ~/Projects/scala/test (ticket/6725)$ git commit
+ [ticket/6725 3c3098693b] SI-6725 `f` interpolator now supports %n tokens
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+ 19:34 ~/Projects/scala/test (ticket/6725)$ git push origin ticket/6725
+ Username for 'https://github.com': xeno-by
+ Password for 'https://xeno-by@github.com':
+ Counting objects: 15, done.
+ Delta compression using up to 8 threads.
+ Compressing objects: 100% (8/8), done.
+ Writing objects: 100% (8/8), 1.00 KiB, done.
+ Total 8 (delta 5), reused 0 (delta 0)
+ To https://github.com/xeno-by/scala
+ * [new branch] ticket/6725 -> ticket/6725
+
+### Submit
+
+Now, we must simply submit our proposed patch. Navigate to your branch in GitHub (for me, it was `https://github.com/xeno-by/scala/tree/ticket/6725`)
+and click the pull request button to submit your patch as a pull request to Scala. If you've never submitted patches to Scala, you will
+need to sign the contributor license agreement, which [can be done online](https://www.lightbend.com/contribute/cla/scala) within a few minutes.
+
+
+
+### Review
+
+After the pull request has been submitted, you need to pick a reviewer (usually the person you've contacted in the beginning of your
+workflow) and be ready to elaborate and adjust your patch if necessary. In this example, we picked Martin, because we had such a nice chat on the mailing list:
+
+
+
+## Merge
+
+After your reviewer is happy with your code (usually signaled by a LGTM — “Looks good to me”), your job is done.
+Note that there can be a gap between a successful review and the merge, because not every reviewer has merge rights. In that case, someone else from the team will pick up your pull request and merge it.
+So don't be confused if your reviewer says “LGTM”, but your code doesn't get merged immediately.
+
+[collections-arch]: {% link _overviews/core/architecture-of-scala-collections.md %}
+[collections-intro]: {% link _overviews/collections-2.13/introduction.md %}
+[collections-par]: {% link _overviews/parallel-collections/overview.md %}
+[reflect-overview]: {% link _overviews/reflection/overview.md %}
+[partest-guide]: {% link _overviews/contribute/partest-guide.md %}
+[documentation]: {% link _overviews/contribute/documentation.md %}
+[contrib-forum]: https://contributors.scala-lang.org/
+[discord-contrib]: https://discord.com/invite/scala
diff --git a/_overviews/contribute/inclusive-language-guide.md b/_overviews/contribute/inclusive-language-guide.md
new file mode 100644
index 0000000000..d32b5144a8
--- /dev/null
+++ b/_overviews/contribute/inclusive-language-guide.md
@@ -0,0 +1,136 @@
+---
+title: Inclusive Language Guide
+num: 2
+---
+
+We are committed to providing a friendly, safe and welcoming environment for
+all, regardless of age, body size, disability, ethnicity, sex characteristics,
+gender identity and expression, level of experience, education, socio-economic
+status, nationality, personal appearance, race, religion, sexual identity
+and orientation, or other such characteristics.
+
+Language is a powerful vehicle of ideas and representations, and as such, can highlight, accentuate, or blur certain characteristics of the world.
+Language -- in its use and structure -- may bias our perception of the world, sometimes to the disadvantage of some people.
+Different language strategies have therefore been suggested to promote more inclusive forms of language, echoing the need for more equal treatment for all.
+
+This inclusive language guide is therefore intended to help us adopt a more inclusive way of communicating.
+Although the present guide does not exhaustively cover all issues pertaining to non-inclusive language, it covers the most important issues we are currently aware of.
+
+Contributions made to the core Scala projects and their documentation -- including to this website -- should follow this guide.
+
+## Non gendered language
+
+The use of *He*, *Him*, *His*, *Man* and *Men* should be avoided.
+Although these terms are intended to refer to any genders (male, female, other, unknown or irrelevant), they imply that the subject is male and therefore excludes all other genders.
+Instead, use the singular *they*, as already used by famous authors like Jane Austen.
+
+Example of the use of singular they:
+
+> When a developer wants to contribute to a project, they open a pull request.
+
+Although *they* refers to a single person, we conjugate the verb with the plural form.
+This is similar to the polite form of pronouns in certain languages, such as "Sie" in German or "vous" in French.
+
+When possible, avoid (combined) words that refer to a specific gender, and use gender-neutral alternatives instead.
+For example:
+
+* *man* or *woman* -> *person*
+* *chairman* -> *chairperson*
+
+## The words easy, simple, quick, and trivial
+
+What might be easy for you might not be easy for others.
+The same applies to other words like *quick* or *simple*.
+When used in the positive or superlative forms, try eliminating this word from sentences because usually the same meaning can be conveyed without it.
+
+Example of a positive form:
+
+> You can then simply execute the program with the `run` command.
+
+can be replaced with
+
+> You can then execute the program with the `run` command.
+
+without changing the meaning of the sentence.
+
+Example of a superlative form:
+
+> The foobar method is the easiest way to get started with our library.
+
+can be replaced with
+
+> We show here how to use the foobar method to get started with our library.
+
+However, the comparative form of these adjectives and adverbs can be used when relevant.
+
+Example of a comparative form:
+
+> The foobar method is quicker to get started with than the baz method.
+
+Similarly, the word *just* is usually redundant and can be removed without altering the meaning.
+
+Example:
+
+> You can just add these settings to your build.
+
+can be replaced with
+
+> You can add these settings to your build.
+
+Of course, every situation is different, and there may be cases where using "the easy words" is still the best thing to do.
+In that case, it should be a deliberate decision to use them, taking the above considerations into account.
+
+## Specific loaded words
+
+Some words may have a derogatory connotation and/or have clear oppressive origins.
+Avoid these words to the greatest extent possible, and use neutral alternatives instead.
+Currently, the following words, used for common computer science concepts, are discouraged.
+This list is neither comprehensive nor definitive, and it can evolve over time.
+
+* **blacklist/whitelist** \
+ While the etymology of these words has no relation to racism, their use suggests an association between the color black and some form of badness or exclusion, and between the color white and some form of goodness or inclusion.
+ Prefer alternatives when possible.
+ Several alternatives have been proposed but none sticks as "the one". We suggest using the pair *denylist*/*allowlist* or the pair *excludelist*/*includelist*, as these are generic enough to replace most uses of *blacklist*/*whitelist*.
+* **master/slave** \
+ Never use *slave*.
+ Never use *master* in conjunction with *slave*.
+ Depending on the specific architecture, use one of the following alternatives instead: *controller*/*worker*, *primary*/*secondary*, *leader*/*follower*, etc.
+ When in doubt, if you cannot choose, *primary*/*secondary* is always a decent fallback. \
+ When used with the meaning of *teacher*, *expert*, *guide*, or *reference*, the word *master* is not specifically discouraged.
+ For example, the term *Master of the arts* is acceptable. \
+ Note: there exists a broader movement of using `main` instead of `master` as the default git branch, led by GitHub and the git project themselves, and which we encourage people to follow as well.
+* **sanity check** \
+ Prefer *confidence check*.
+* **segregated** \
+ Computer science concepts like the *interface segregation principle* and *segregated networks* present segregation as being desirable, instead of bad.
+ Prefer alternatives like *separation of concerns* and *segmented networks*.
+* **guru** \
+ While a *guru* initially refers to a respected spiritual leader, it also designates the chief of a sect.
+ Both are of a spiritual nature and are ambiguous.
+ If possible, use a more precise term such as *teacher* or *expert*.
+
+A good source with explainers and references can be found at [https://github.com/dialpad/inclusive-language](https://github.com/dialpad/inclusive-language).
+
+Keep in mind that your particular application domain may contain its own share of domain-specific loaded words.
+We encourage you to research inclusive language guidelines applicable to your domain.
+
+You may want to use automated software like [In Solidarity](https://github.com/apps/in-solidarity) to steer contributors away from loaded words.
+
+## Dysphemism
+
+Dysphemisms, the opposite of euphemisms, can be disturbingly violent if you are not used to them.
+Examples include the English expressions "pull the trigger" (enforce a decision) and "bite the bullet" (endure hardship).
+Prefer the direct meaning instead.
+
+## Backward compatibility
+
+Sometimes, we have existing code, APIs or commands that do not follow the above recommendations.
+It is generally advisable to perform renaming to address the issue, but that should not be done to the detriment of backward compatibility (in particular, backward binary compatibility of libraries).
+Deprecated aliases should be retained when possible.
+
+Sometimes, it is not possible to preserve backward compatibility through renaming; for example for methods intended to be overridden by user-defined subclasses.
+In those cases, we recommend to keep the old names, but document (e.g., in Scaladoc comments) that they are named as they are for historical reasons and to preserve compatibility, and what their intended name should be.
+
+## See also
+
+* Our [code of conduct](https://scala-lang.org/conduct/).
diff --git a/_overviews/contribute/index.md b/_overviews/contribute/index.md
new file mode 100644
index 0000000000..1daa8cc13b
--- /dev/null
+++ b/_overviews/contribute/index.md
@@ -0,0 +1,287 @@
+---
+title: Becoming a Scala OSS Contributor
+num: 1
+
+explore_resources:
+ - title: Who can contribute?
+ description: "Open source is for everyone! If you are reading this you are already a contributor..."
+ icon: "fa fa-hand-sparkles"
+ link: "#who-can-contribute-to-open-source"
+ - title: Why should I contribute?
+ description: "Giving back to the community has many benefits..."
+ icon: "fa fa-circle-question"
+ link: "#why-should-i-contribute-to-open-source"
+ - title: How can I contribute?
+ description: "From friendly documentation to coding a bug-fix, there is lots to do..."
+ icon: "fa fa-clipboard-list"
+ link: "#how-can-i-contribute-to-open-source"
+ - title: Where should I contribute?
+ description: "If you are already using OSS, or are curious about projects, you can begin right away..."
+ icon: "fa fa-check-to-slot"
+ link: "#how-do-i-choose-where-to-contribute"
+
+compiler_resources:
+ - title: "Join the Compiler Issue Spree"
+ description: "A tri-weekly event where you can get mentored on the compiler. Register for participation here."
+ icon: "fa fa-clipboard-user"
+ link: https://airtable.com/app94nwzow5R6W1O6/pagvjIzxYnqTTlhwY/form
+ - title: "Compiler Academy videos"
+ description: "In-depth tours of the Scala 3 compiler's internals, aimed to help you get started."
+ icon: "fa fa-circle-play"
+ link: https://www.youtube.com/channel/UCIH0OgqE54-KEvYDg4LRhKQ
+ - title: "Scala 3 contributing guide"
+ description: "Guide to the Scala 3 Compiler and fixing an issue"
+ icon: "fa fa-code-merge"
+ link: https://dotty.epfl.ch/docs/contributing/index.html
+
+spree_resources:
+ - title: "Scala open source sprees"
+ description: "Learn about the next upcoming community spree"
+ icon: "fa fa-hand-holding-heart"
+ link: "https://github.com/scalacenter/sprees"
+ - title: "Upcoming conferences"
+ description: "See upcoming Scala conferences where you can meet open source maintainers."
+ icon: "fa fa-calendar-check"
+ link: "https://www.scala-lang.org/events/"
+
+scala_resources:
+ - title: Documentation
+ description: "Library API docs, new guides on docs.scala-lang.org, and help with scala-lang.org."
+ icon: fa fa-book
+ link: /contribute/documentation.html
+ - title: Bug fixes
+ description: "Issues with the tools, core libraries and compiler. Also, you can help us by reporting bugs."
+ icon: fa fa-bug
+ link: /contribute/guide.html
+ - title: Code Reviews
+ description: "Review pull requests against scala/scala, scala/scala3, scala/scala-lang, scala/docs.scala-lang, and others."
+ icon: fa fa-eye
+ link: /contribute/codereviews.html
+ - title: Core Libraries
+ description: "Update and expand the capabilities of the core (and associated) Scala libraries."
+ icon: fa fa-clipboard
+ link: /contribute/corelibs.html
+ - title: IDE and Build Tools
+ description: "Enhance the Scala tools with features for build tools, IDE plug-ins and other related projects."
+ icon: fa fa-terminal
+ link: /contribute/tools.html
+ - title: Compiler/Language
+ description: "Larger language features and compiler enhancements including language specification and SIPs."
+ icon: fa fa-cogs
+ link: /contribute/guide.html#larger-changes-new-features
+
+library_resources:
+ - title: Library Authors Guide
+ description: "Lists all the tools that library authors should setup to publish and document their libraries."
+ icon: "fa fa-book"
+ link: "/overviews/contributors/index.html"
+ - title: Make Projects more Inclusive
+ description: "How you can write code and documentation that welcomes all"
+ icon: "fa fa-door-open"
+ link: "inclusive-language-guide.html"
+ - title: Create a Welcoming Community
+ description: "Our code of conduct is practical agreement for a healthy community"
+ icon: "fa fa-handshake-simple"
+ link: "https://scala-lang.org/conduct"
+ - title: Binary Compatability Guide
+ description: "Evolve your library over time, giving users the confidence to upgrade safely."
+ icon: "fa fa-puzzle-piece"
+ link: "/overviews/core/binary-compatibility-for-library-authors.html"
+---
+
+Welcome to the guide on contributing to all parts of Scala's open-source ecosystem!
+
+## Newcomers' FAQ
+
+If you are reading this page, we welcome you, regardless of your background, to begin contributing to Scala's
+open-source ecosystem. We have answered some common questions for you below:
+
+{% include inner-documentation-sections.html links=page.explore_resources %}
+
+## Ways to start today
+
+### Join the nearest open source spree
+
+The [Scala Center](https://scala.epfl.ch) hosts open source sprees, colocated with other Scala events.
+In the spree, regular project maintainers will mentor you to create your first contribution to the project.
+
+{% include inner-documentation-sections.html links=page.spree_resources %}
+
+### So you want to improve the Scala 3 compiler...
+
+The [Scala 3 compiler](https://github.com/scala/scala3) is an open source project.
+If you are curious about contributing but don't know how to begin, the [Scala Center](https://scala.epfl.ch)
+runs the **Scala Compiler Academy** project to onboard and educate new people to the project. You can join the regular
+**Compiler Issue Spree**, watch in-depth videos, and read the contributing guide:
+
+{% include inner-documentation-sections.html links=page.compiler_resources %}
+
+#### Which areas are perfect for newcomers?
+- Adding new linting options, which help enforce cleaner code.
+- Improving the clarity of error messages, so that the user understands better what went wrong.
+- Add IDE quick-fix actions to error messages, e.g. PR [scala/scala3#18314](https://github.com/scala/scala3/pull/18314).
+
+### So you want to write a library...
+
+Read these guides if you are a maintainer of a library, or are thinking of starting a new project:
+
+{% include inner-documentation-sections.html links=page.library_resources %}
+
+### Want to improve Scala itself?
+The Scala programming language is an open source project with a very
+diverse community, where people from all over the world contribute their work,
+with everyone benefiting from friendly help and advice, and
+kindly helping others in return.
+
+Read on to learn how to join the Scala community and help
+everyone make things better.
+
+## Contributing to the Scala project
+
+**What Can I Do?**
+That depends on what you want to contribute. Below are some getting started resources for different contribution domains. Please read all the documentation and follow all the links from the topic pages below before attempting to contribute, as many of the questions you have will already be answered.
+
+### Reporting bugs
+
+See our [bug reporting guide][bug-reporting-guide] to learn
+how to efficiently report a bug.
+
+### Contribute
+
+Coordination of contribution efforts takes place on
+[Scala Contributors](https://contributors.scala-lang.org/).
+
+{% include inner-documentation-sections.html links=page.scala_resources %}
+
+### Guidelines
+
+When contributing, please follow:
+
+* The [Scala Code of Conduct](https://scala-lang.org/conduct/)
+* The [Inclusive Language Guide][inclusive-language-guide]
+
+### Community tickets
+
+All issues can be found in the [Scala bug tracker](https://github.com/scala/bug), or the [Scala 3 issue tracker](https://github.com/scala/scala3/issues). Most issues are labeled
+to make it easier to find issues you are interested in.
+
+### Tools and libraries
+
+The Scala ecosystem includes a great many diverse open-source projects
+with their own maintainers and community of contributors. Helping out
+one of these projects is another way to help Scala. Consider lending
+on a hand on a project you're already using. Or, to find out about
+other projects, see the
+[Libraries and Tools section](https://scala-lang.org/community/#community-libraries-and-tools)
+on our Community page.
+
+### Scala community build
+
+The Scala community build enables the Scala compiler team
+to build and test a corpus of
+Scala open source projects
+against development versions of the Scala compiler and standard
+library in order to discover regressions prior to releases.
+The build uses Lightbend's
+[dbuild](https://github.com/typesafehub/dbuild) tool,
+which leverages [sbt](https://www.scala-sbt.org).
+
+If you're the maintainer -- or just an interested user! -- of an
+open-source Scala library or tool, please visit the
+[community build documentation](https://github.com/scala/community-build/wiki)
+for guidelines on what projects are suitable for the community build
+and how projects can be added.
+
+## Your questions, answered
+
+{% capture backButton %}
+
+{% endcapture %}
+
+### Who can contribute to open source?
+{{backButton}}
+- **Everyone:** No matter your skills or background, non-technical or otherwise, there is always
+ [some way](#how-can-i-contribute-to-open-source) you can contribute to a project.
+- **Community organisers:** Communities often form around open source projects, perhaps you would like to help grow a
+ community.
+- **Scala learners:** If you are at the start of your Scala journey, once you have a basic understanding of everyday
+ Scala programming, becoming familiar with open source code will show you new techniques, helping you to improve
+ your expertise.
+- **Got a cool idea?** Perhaps you have gained confidence in your skills and are looking to give back to the community,
+ start a new project that fills that perfect niche, or maybe is the life-changing tool everyone never knew they needed.
+
+### Why should I contribute to open source?
+{{backButton}}
+- **The world is built on OSS:**
+ Open Source Software (OSS) libraries are the flesh on top of the bone structure of the core language itself.
+ They power vast majority of the commercial and non-commercial projects out there alike.
+- **Become more visible:**
+ Contributing is a great way to strengthen your CV. It's also good from the community standpoint: if you do it
+ consistently, with time, you get to know people, and people get to know you. Such a networking can lead to all
+ sorts of opportunities.
+- **Learn by doing something practical:** Contributing to open source libraries is a great way to learn Scala.
+ A standard practice in open source software is code review – which means you are going to get expert feedback
+ about your code. Learning together with feedback from competent people is much faster than making all the
+ mistakes and figuring them out alone.
+- **Have fun and help out:** Finally, by contributing you improve the projects you are using yourself. Being a part of
+ a maintainer team can be a source of personal satisfaction, and working on an innovative library can be a lot of fun.
+
+The above benefits are something good to achieve regardless of your level of experience.
+
+### How can I contribute to open source?
+{{backButton}}
+- **Documentation:** Often it is outdated, incomplete, or with mistakes. If you see a way to improve the
+ documentation for a project you are using, you should consider if the project is accepting contributions,
+ in which case you can submit a pull request to include your changes.
+- **Building community:** All projects have users, and users come together to form communities. Managing and growing
+ communities takes coordination and effort.
+- **Issue minimization:** Many of the reported issues found on a project's issue tracker are hard to reproduce and the
+ reproduction involves a lot of code. However, it is very frequently the case that only a tiny fraction of the
+ reported setup and code is necessary to reproduce the issue. More reproduction code means more work for the
+ maintainer to fix an issue. You can help them considerably by investigating already reported issues in an attempt
+ to make their reproduction as small as possible.
+- **Issue reproduction:** Some reported issues lack reproduction instructions at all! If a maintainer can't
+ reproduce it, they won't be able to fix it. Pinning down exact conditions that make an issue manifest is another
+ way to contribute.
+- **Fixing a bug:** If you are comfortable with reproducing an issue, perhaps you would like to trace its
+ origin in code, and even try to build a solution that prevents the issue from occurring.
+- **Adding a feature:** Sometimes projects maintain lists of planned or requested features, and you could assist
+ in bringing those ideas to reality. Although please beware - you should only do this if the core maintainers
+ have already approved the idea for the feature, they are not obligated to accept your additions!
+- **Feel free to ask for help:** While implementing or fixing the feature, it is important to ask for help early
+ when you feel stuck. Even if your code doesn't work, don't hesitate to submit a pull request while stating clearly
+ that you need help. More information about the guidelines of good contribution you can find in the
+ [talk by Seth Tisue](https://youtu.be/DTUpSTrnI-0) on how to be a good contributor.
+- **Open-source your own project:** Do you have a pet project you are working on? Is there anything you're working
+ on at work parts of which are generic enough that you can share them online? Open-sourcing your work is a way to
+ solve a problem for other programmers who may also have it. If you are interested in going open-source, the
+ [Library Author's Guide](https://docs.scala-lang.org/overviews/contributors/index.html) is an
+ excellent resource on how to get started.
+
+### How do I choose where to contribute?
+{{backButton}}
+- **Ask yourself, what am I using?** The best project to contribute to is the one that you are using yourself.
+ Take an inventory of your work and hobby projects: what OSS libraries do they use? Have you ever encountered bugs in
+ them? Or have you ever wanted a certain feature implemented? Pick a bug and a feature and commit to fixing or
+ implementing it. Clone the project you are trying to improve, figure out how the tests are written and run there.
+ Write a test for your feature or bug.
+- **Try out an awesome library:** [Scaladex](https://index.scala-lang.org/awesome) is a great place to find new
+ libraries. If you are passionate about contributing but don't see any attractive opportunities to contribute
+ to projects you are already using, try learning a new Scala library, push it to its limits and see where it can
+ be improved. For best results, spend a lot of time with the library to get a feel of what's important
+ and what can improve.
+- **Lookout for announcements:** You may want to keep an eye on the Scala Center
+ [LinkedIn](https://www.linkedin.com/company/scala-center/) and [Bluesky](https://bsky.app/profile/scala-lang.org) or [X](https://x.com/scala_lang) to stay up-to-date with the possible contribution opportunities. For example, every year, the Scala Center participates
+ in the Google Summer of Code program where you are paid to work on open source Scala projects over the course
+ of summer.
+{{backButton}}
+
+
+
+[bug-reporting-guide]: {% link _overviews/contribute/bug-reporting-guide.md %}
+[inclusive-language-guide]: {% link _overviews/contribute/inclusive-language-guide.md %}
diff --git a/_overviews/contribute/partest-guide.md b/_overviews/contribute/partest-guide.md
new file mode 100644
index 0000000000..c8eb5cbf02
--- /dev/null
+++ b/_overviews/contribute/partest-guide.md
@@ -0,0 +1,92 @@
+---
+title: Running the Test Suite
+num: 13
+---
+
+Partest is a custom parallel testing tool that we use to run the test suite for the Scala compiler and library. Go to the scala project folder from your local checkout and run it via `sbt`, `ant` or standalone as follows.
+
+## Using sbt
+
+The test suite can be run from the sbt console with:
+
+```
+sbt:root> partest
+```
+
+You can get a summary of the usage by running `partest --help`.
+
+If you would like to run particular tests pass the test paths as arguments
+
+```
+sbt:root> partest test/files/pos/bounds.scala test/scaladoc/run/diagrams-base.scala
+```
+
+To run only the Scaladoc tests use `--srcpath` with the location of the tests
+
+```
+sbt:root> partest --srcpath scaladoc
+```
+
+## Using ant
+
+> Please note support for ant was removed on the 2.12 branch.
+
+The test suite can be run by using ant from the command line:
+
+ $ ant test.suite
+
+## Standalone
+
+Please note the standalone scripts mentioned below were removed in 2.12.2. sbt is the preferred way to run the test suite.
+
+There are launch scripts `partest` and `partest.bat` in the `test` folder of the scala project. To have partest run failing tests only and print details about test failures to the console, you can use
+
+ ./test/partest --show-diff --show-log --failed
+
+You can get a summary of the usage by running partest without arguments.
+
+* Most commonly you want to invoke partest with an option that tells it which part of the tests to run. For example `--all`, `--pos`, `--neg` or `--run`.
+* You can test individual files by specifying individual test files (`.scala` files) as options. Several files can be tested if they are from the same category, e.g., `pos`.
+* You can enable output of log and diff using the `-show-log` and `-show-diff` options.
+* If you get into real trouble, and want to find out what partest does, you can run it with option `--verbose`. This info is useful as part of bug reports.
+* Set custom path from where to load classes: `-classpath ` and `-buildpath `.
+* You can use the `SCALAC_OPTS` environment variable to pass command line options to the compiler.
+* You can use the `JAVA_OPTS` environment variable to pass command line options to the runner (e.g., for `run/jvm` tests).
+* The launch scripts run partest as follows:
+
+ scala -cp scala.tools.partest.nest.NestRunner
+
+ Partest classes from a `quick` build, e.g., can be found in `./build/quick/classes/partest/`.
+
+ Partest will tell you where it loads compiler/library classes from by adding the `partest.debug` property:
+
+ scala -Dpartest.debug=true -cp scala.tools.partest.nest.NestRunner
+
+
+
+## ScalaCheck tests
+
+Tests that depend on [ScalaCheck](https://github.com/rickynils/scalacheck) can be added under folder `./test/files/scalacheck`. A sample test:
+
+ import org.scalacheck._
+ import Prop._
+
+ object Test {
+ val prop_ConcatLists = property{ (l1: ListInt, l2: ListInt) =>
+ l1.size + l2.size == (l1 ::: l2).size
+ }
+
+ val tests = List(("prop_ConcatLists", prop_ConcatLists))
+ }
+
+## Troubleshooting
+
+### Windows
+
+Some tests might fail because line endings in the `.check` files and the produced results do not match. In that case, set either
+
+ git config core.autocrlf false
+
+or
+
+ git config core.autocrlf input
diff --git a/_overviews/contribute/scala-internals.md b/_overviews/contribute/scala-internals.md
new file mode 100644
index 0000000000..738746f9d3
--- /dev/null
+++ b/_overviews/contribute/scala-internals.md
@@ -0,0 +1,60 @@
+---
+title: Scala Contributors Forum
+num: 9
+---
+
+The [Scala Contributors Forum][scala-contributors] is where discussions about the Scala ecosystem
+occur, from the perspectives of core compiler, documentation and library contributors. It features updates from the
+Scala Center, along with technical and logistical discussions concerning bugs, bug fixes, documentation, improvements,
+new features and other contributor related topics.
+
+> The now legacy [scala-internals mailing list](https://groups.google.com/d/forum/scala-internals) used to fulfil this
+> purpose, but has since expanded to encompass more topics in the new [forum][scala-contributors].
+
+## Coordinating on Scala Contributors
+
+Prior to commencing on contribution work on larger changes to the Scala project, it is recommended (but not required)
+that you make a post on [Scala Contributors][scala-contributors] announcing your intention.
+It's a great time to invite any help, advice or ask any questions you might have. It's also a great place to meet peers,
+one of whom will probably be reviewing your contribution at some point.
+For smaller bug fixes or documentation changes where the risk of effort duplication is minimal, you can skip this post.
+
+To help users to sort through the posts, we request that the following categories are applied when you start a
+new post please:
+
+| Category | Topics |
+|-----------------------------|---------------------------------------------------------------------|
+| `Documentation` | Documentation, e.g. docs.scala-lang.org, API (scaladoc), etc. |
+| `Compiler` | Bug reporting/fixing, Scala compiler discussions/issues |
+| `Tooling` | Tools including sbt, IDE plugins, testing, scaladoc generator, etc. |
+| `Scala Standard Library` | Core libraries |
+| `Scala Platform` | Extension libraries |
+| `Language Design` | Scala language feature discussions / informal proposals |
+| `Scala Improvement Process` | Scala language feature formal proposals |
+| `Meta Discourse` | Administrative/coordination topics |
+| `Community` | Discussions about events, community organising |
+
+### Why It's a Good Idea
+
+While it is optional to announce your intentions/work items on [Scala Contributors][scala-contributors] before starting, it is recommended thing to do for a number of reasons:
+
+* To attempt to cut down on duplicate effort (i.e. to avoid two people working on the same bug at the same time without coordinating effort).
+* Related to the above: to allow the compiler team and core committers to warn of or smooth over potential merge conflicts between separate bugs that might affect the same code.
+* Potentially someone has already thought about or even worked on that issue or a related one, and has valuable insight
+that might save you time (including warnings about what you might find and may want to avoid - perhaps one option
+already tried lead to no benefit).
+* You might find a group of impassioned individuals who want to volunteer and help you. You will have the momentum since
+you posted first, so then it's up to you to decide if you want their help or not.
+* Posting could start a dialog with a potential reviewer, smoothing the later stages of your contribution before
+merging your changes.
+* There are a lot of nice people waiting to talk to you on [Scala Contributors][scala-contributors], you might be
+surprised how valuable and pleasant you find the experience of talking to them.
+
+Even if you do not wish to post on [Scala Contributors][scala-contributors], please feel welcome to make contributions
+anyway, as posting to the forum is *not* criteria for it to be accepted. For smaller, self-contained bugs it is
+especially less important to make a post, however larger issues or features take more time to consider accepting them.
+For large contributions we strongly recommend that you do to notify of your intention, which will help you determine if
+there is large community support for your change, making it more likely that your large contribution will be accepted,
+before you spend a long time implementing it.
+
+[scala-contributors]: https://contributors.scala-lang.org
diff --git a/_overviews/contribute/scala-standard-library-api-documentation.md b/_overviews/contribute/scala-standard-library-api-documentation.md
new file mode 100644
index 0000000000..27f2093d93
--- /dev/null
+++ b/_overviews/contribute/scala-standard-library-api-documentation.md
@@ -0,0 +1,126 @@
+---
+title: Contribute to API Documentation
+num: 6
+---
+
+This page is specific to API documentation contributions – that is, API
+documentation for
+[Scala's standard library](https://scala-lang.org/api/current/#package) –
+sometimes referred to as Scaladoc contributions.
+
+For contributions to tutorial and guide-style documentation on
+[docs.scala-lang.org][home],
+see [Add New Guides/Tutorials][add-guides].
+
+*Please note, these instructions cover documentation contributions Scala core
+libraries only. For other Scala projects please check those projects for the
+contribution steps and guidelines. Thank you.*
+
+## Overview
+
+Since API documentation is located in Scala source code files, the
+process for contributing API documentation is similar to that of contributing bug-fixes
+to the Scala code base, but without the requirement that there be an issue filed on GitHub
+first. When forking/branching, it would help to use a `scaladoc/xxxx` branch name, where `xxxx` is a
+descriptive, but short branch name (e.g. `scaladoc/future-object`).
+However, if an issue *does* exist, please use `issue/NNNN`, where `NNNN` is the ticket number,
+instead.
+
+If you would like to assist us, you can
+[report missing/incorrect API documentation](#contribute-api-documentation-bug-reports), or
+[contribute new API documentation](#contribute-new-api-documentation).
+
+## Contribute API Documentation Bug Reports
+
+One good way to contribute is by helping us to identify missing documentation. To do
+this, [browse the current API documentation](https://www.scala-lang.org/api/current/)
+and identify missing, incorrect or inadequate documentation. A good place to start is
+package objects for important packages (these often get overlooked for documentation
+and are a good place for API overviews).
+
+If you find an issue, please log it in the [Scala bug tracker](https://github.com/scala/bug),
+(or else the [Scala 3 issue tracker](https://github.com/scala/scala3/issues) for Scala 3 library additions)
+**after making sure it is not already logged as an issue**. To help with
+disambiguation, please use the following format for issue title:
+
+* Use an action describing the work required, e.g. **Add**, **Document**, **Correct**, **Remove**.
+* Use the full package, class/trait/object/enum name (or state package object if
+ that is the case).
+* Extremely short description of what to do.
+* More detail can (and should) go into the issue description, including a short
+ justification for the issue if it provides additional detail.
+
+Here is an example of the title and description for an example API documentation issue:
+
+`Document scala.concurrent.Future object, include code examples`
+
+(note the explicit companion object called out in the title)
+
+and the description:
+
+> The methods on the `Future` companion object are critical
+> for using Futures effectively without blocking. Provide code
+> examples of how methods like `sequence`, `transform`, `fold` and
+> `firstCompletedOf` should be used.
+
+In addition to following these conventions, please add `documentation` and
+`community` labels to the issue, and put them in the `Documentation and API`
+component so that they show up in the correct issue filters.
+
+## Contribute New API Documentation
+
+### Required Reading
+
+Please familiarize yourself with the following before contributing
+new API documentation to save time, effort, mistakes and repetition.
+
+* [Forking the Repo][hackers-setup] - follow the setup steps through
+ the Branch section. If providing new documentation related to an existing GitHub issue, use `issue/NNNN`
+ or `ticket/NNNN` as the guide states. If providing API documentation with no associated
+ GitHub issue, use `scaladoc/xxxx` instead.
+* [Scaladoc for library authors][scaladoc-lib-authors]
+ covers the use of scaladoc tags, markdown and other features.
+* [Scaladoc's interface][scaladoc-interface]
+ covers all the features of Scaladoc's interface, e.g. switching between
+ companions, browsing package object documentation, searching, token searches
+ and so on.
+* Prior to commit, be sure to read
+ [A note about git commit messages](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) and the [Scala Project & Developer Guidelines](https://github.com/scala/scala/blob/2.11.x/CONTRIBUTING.md).
+ Some of this latter document will clearly not apply (like the sections on providing tests,
+ however see below for some special requirements for documentation). Do still read
+ the whole document though, and pay close attention to the title and commit
+ message formats, noting *present tense*, *length limits* and that it must merge
+ cleanly. Remember that the title of the pull request will become the commit
+ message when merged. **Also**, be sure to assign one or more reviewers to the PR, if this is
+ not possible for you, you could mention a user **in the pull request comments**.
+
+### Extra Requirements for Scaladoc Documentation Commits
+
+Although some requirements for bug fix pull requests are not needed for
+API documentation commits, here are the step by step requirements to ensure your API documentation
+PR is merged in smoothly:
+
+* Any and all code examples provided should *be correct, compile and run* as
+ expected (ensure this in the REPL or your IDE).
+* Spelling must be checked for all written language *and* code examples where
+ possible. Most editors have some spell checking feature available. Scala code
+ itself is permitted to not pass a spell-checker, however any written language
+ should be checked. If you can also use a grammar checker, it will help. We
+ *will* ask for spelling and grammar to be corrected before acceptance.
+* You **must** also run `sbt doc`, fix any problems and check the formatting and
+ layout of your changes. Again, corrections will be required if formatting or
+ layout are inadequate. After running `sbt doc` the generated documents can be
+ found under the `build/scaladoc/` folders (probably in the `library` subdirectory
+ but maybe under the others depending on what section of the Scala source you
+ are working on).
+* All of these steps are required to save time for both the reviewers and
+ contributors. It benefits everyone to ensure that the PR to merge process is
+ as smooth and streamlined as possible.
+
+Thanks for helping us improve the Scaladoc API documentation!
+
+[home]: {% link index.md %}
+[add-guides]: {% link _overviews/contribute/add-guides.md %}
+[hackers-setup]: {% link _overviews/contribute/hacker-guide.md %}#2-set-up
+[scaladoc-lib-authors]: {% link _overviews/scaladoc/for-library-authors.md %}
+[scaladoc-interface]: {% link _overviews/scaladoc/interface.md %}
diff --git a/_overviews/contribute/scala3.md b/_overviews/contribute/scala3.md
new file mode 100644
index 0000000000..2501012a1e
--- /dev/null
+++ b/_overviews/contribute/scala3.md
@@ -0,0 +1,13 @@
+---
+title: Contribute to Scala 3
+description: This page describes the format of the contribution guide for the Scala 3 compiler.
+num: 14
+redirect_from: /scala3/guides/contribution/contribution-intro.html
+---
+Thank you for wanting to contribute to Scala 3!
+
+Dotty is an open-source project, and as such, we welcome contributions from the community to help us make it even better.
+
+If you are interested in contributing to Scala 3, please visit the project [developer website](https://dotty.epfl.ch/docs/contributing/index.html), where you will find all the information you need to get started. We encourage everyone, regardless of their level of expertise, to contribute to Scala 3, as there are many ways to help, from fixing bugs and implementing new features to improving documentation and testing.
+
+If you have any questions, please feel free to ask them on the [Contributors Forum](https://contributors.scala-lang.org/c/scala-3/scala-3-contributors/9).
diff --git a/_overviews/contribute/tools.md b/_overviews/contribute/tools.md
new file mode 100644
index 0000000000..77115d03ab
--- /dev/null
+++ b/_overviews/contribute/tools.md
@@ -0,0 +1,80 @@
+---
+title: IDE and Build Tool Contributions
+num: 11
+
+# Projects list:
+projects:
+ - title: sbt
+ description: The interactive build tool.
+ icon: https://www.scala-sbt.org/assets/sbt-logo.svg
+ link: https://github.com/sbt/sbt
+ homeLink: https://www.scala-sbt.org/
+ issuesLink: https://github.com/sbt/sbt#issues-and-pull-requests
+ readmeLink: https://github.com/sbt/sbt/blob/0.13/README.md
+ contributingLink: https://github.com/sbt/sbt/blob/0.13/CONTRIBUTING.md
+ - title: Scaladoc Tool
+ description: (Contribute through scala/scala)
+ icon: https://avatars1.githubusercontent.com/u/57059?v=3&s=200
+ link: https://github.com/scala/scala
+ homeLink: https://www.scala-lang.org/api
+ issuesLink: https://github.com/scala/bug/labels/scaladoc
+ readmeLink: https://github.com/scala/scala#welcome
+ contributingLink: /contribute/guide.html
+ - title: Partest
+ description: Scala Compiler/Library Testing (Contribute through scala/scala)
+ icon: https://avatars1.githubusercontent.com/u/57059?v=3&s=200
+ link: https://github.com/scala/scala
+ homeLink: https://github.com/scala/scala
+ issuesLink: https://github.com/scala/scala/issues
+ readmeLink: https://github.com/scala/scala/blob/2.13.x/CONTRIBUTING.md#partest
+ contributingLink:
+
+projectsInNeed:
+ - title: Scoverage
+ description: Scala code coverage tool
+ icon: https://avatars1.githubusercontent.com/u/5998302?v=3&s=200
+ link: https://github.com/scoverage/scalac-scoverage-plugin
+ homeLink: http://scoverage.org/
+ issuesLink: https://github.com/scoverage/scalac-scoverage-plugin/issues
+ readmeLink: https://github.com/scoverage/scalac-scoverage-plugin/blob/master/README.md
+ contributingLink: https://groups.google.com/forum/#!forum/scala-code-coverage-tool
+---
+## Contributing to IDE and Build Tools
+
+The links below are to a number of Scala build and IDE related projects that are important in the larger Scala space, and which welcome contributions.
+
+Since these tools are in separate projects, they may (and likely will) have their own rules and guidelines for contributing. You should also check the `README.md` and (if it's present) `CONTRIBUTING.md` files from the actual projects before contributing to them.
+
+Typically, issues for these projects will be reported and kept in the GitHub project issue tracker for that project rather than in the Scala bug tracker.
+
+Many of these projects have a chat room on Discord or Gitter (usually linked from their `README.md` or `CONTRIBUTING.md` files) which is a great place to discuss proposed work before starting.
+
+There are some projects in this section that are in
+[particular need](#projects-in-particular-need) so please check those out
+if you would like to help revive them.
+
+### Broken Links?
+
+Stuff changes. Found a broken link or something that needs updating on this page? Please, consider [submitting a documentation pull request](/contribute/documentation.html#updating-scala-langorg) to fix it.
+
+### Projects
+
+{% if page.projects.size > 0 %}
+{% include contributions-projects-list.html collection=page.projects %}
+{% else %}
+There are no projects.
+{% endif %}
+
+### Projects in Particular Need
+
+{% if page.projectsInNeed.size > 0 %}
+
+The following projects are important to the Scala community but are particularly in need of contributors to continue their development.
+
+{% include contributions-projects-list.html collection=page.projectsInNeed %}
+
+{% else %}
+
+There are no projects in particular need.
+
+{% endif %}
diff --git a/_overviews/contributors/index.md b/_overviews/contributors/index.md
index 4a685c7a70..c482c6f8dc 100644
--- a/_overviews/contributors/index.md
+++ b/_overviews/contributors/index.md
@@ -22,7 +22,7 @@ that the license and copyright notices are preserved. For the record, Scala itse
Once you have chosen a license, *apply* it to your project by creating a `LICENSE` file in the root directory
of your project with the license contents or a link to it. This file usually indicates who owns the copyright.
-In our example of [LICENSE file](https://github.com/scalacenter/library-example/blob/master/LICENSE), we have
+In our example of [LICENSE file](https://github.com/scalacenter/library-example/blob/main/LICENSE), we have
written that all the contributors (as per the Git log) own the copyright.
## Host the Source Code
@@ -31,82 +31,80 @@ We recommend sharing the source code of your library by hosting it on a public [
hosting site such as [GitHub](https://github.com), [Bitbucket](https://bitbucket.org) or [GitLab](https://gitlab.com).
In our example, we use GitHub.
-Your project should include a [README](https://github.com/scalacenter/library-example/blob/master/README.md) file
+Your project should include a [README](https://github.com/scalacenter/library-example/blob/main/README.md) file
including a description of what the library does and some documentation (or links to the documentation).
You should take care of putting only source files under version control. For instance, artifacts generated by the
build system should *not* be versioned. You can instruct Git to ignore such files by adding them to a
-[.gitignore](https://github.com/scalacenter/library-example/blob/master/.gitignore) file.
+[.gitignore](https://github.com/scalacenter/library-example/blob/main/.gitignore) file.
In case you are using sbt, make sure your repository has a
-[project/build.properties](https://github.com/scalacenter/library-example/blob/master/project/build.properties)
+[project/build.properties](https://github.com/scalacenter/library-example/blob/main/project/build.properties)
file indicating the sbt version to use, so that people (or tools) working on your repository will automatically
use the correct sbt version.
## Setup Continuous Integration
The first reason for setting up a continuous integration (CI) server is to systematically run tests on pull requests.
-Examples of CI servers that are free for open source projects are [Travis CI](https://travis-ci.org),
-[Drone](https://drone.io) or [AppVeyor](https://appveyor.com).
+Examples of CI servers that are free for open source projects are [GitHub Actions](https://github.com/features/actions),
+[Travis CI](https://travis-ci.com), [Drone](https://drone.io) or [AppVeyor](https://appveyor.com).
-Our example uses Travis CI. To enable Travis CI on your project, go to [travis-ci.org](https://travis-ci.org/),
-sign up using your GitHub account, and enable your project repository. Then, add a `.travis.yml` file to your
-repository with the following content:
+Our example uses GitHub Actions. This feature is enabled by default on GitHub repositories. You can verify if that is
+the case in the *Actions* section of the *Settings* tab of the repository.
+If *Disable all actions* is checked, then Actions are not enabled, and you can activate them
+by selecting *Allow all actions*, *Allow local actions only* or *Allow select actions*.
-~~~ yaml
-language: scala
-~~~
-
-Push your changes and check that Travis CI triggers a build for your repository.
-
-Travis CI tries to guess which build tool your project uses and executes a default command to run the project tests.
-For instance, if your repository contains a `build.sbt` file in the root directory, Travis CI executes the
-`sbt ++$TRAVIS_SCALA_VERSION test` command, where the `TRAVIS_SCALA_VERSION` variable is, by default, set to an
-arbitrary Scala version (`2.12.8`, at the time these lines are written), which could be inconsistent with the
-`scalaVersion` defined in your `build.sbt` file.
-
-To avoid this potential inconsistency, you want to use one Scala version definition as a single source of truth.
-For instance, the [sbt-travisci](https://github.com/dwijnand/sbt-travisci) plugin lets you define the Scala version
-in the `.travis.yml` file, and then forwards this version to your sbt build definition. Alternatively, you can
-override the default command run by Travis CI to use the Scala version defined by the `scalaVersion` settings of
-your build.
-
-The latter approach is the one used in this guide. Override the command run by Travis CI by adding the folliwng
-lines to your `.travis.yml` file:
-
-~~~ yaml
-jobs:
- include:
- - stage: test
- script: sbt test
-~~~
+With Actions enabled, you can create a *workflow definition file*. A **workflow** is an automated procedure,
+composed of one or more jobs. A **job** is a set of sequential steps that are executed on the same runner.
+A **step** is an individual task that can run commands; a step can be either an *action* or a shell command.
+An **action** is the smallest building block of a workflow, it is possible to reuse community actions or to
+define new ones.
-Travis CI will now execute the `sbt test` command, which uses the Scala version from the build definition.
-
-Last, an important thing to setup is caching, to avoid the CI server to re-download your project dependencies each
-time it runs. For instance, in case you use sbt, you can instruct Travis CI to save the content of the `~/.ivy2/`
-and `~/.sbt/` directories across builds by adding the following lines to your `.travis.yml` file:
+To create a workflow, create a *yaml* file in the directory `.github/workflows/` in the repository, for example
+`.github/workflows/ci.yml` with the following content:
~~~ yaml
-# These directories are cached at the end of the build
-cache:
- directories:
- - $HOME/.ivy2/cache
- - $HOME/.sbt
-before_cache:
- # Cleanup the cached directories to avoid unnecessary cache updates
- - rm -fv $HOME/.ivy2/.sbt.ivy.lock
- - find $HOME/.ivy2/cache -name "ivydata-*.properties" -print -delete
- - find $HOME/.sbt -name "*.lock" -print -delete
-~~~
+name: Continuous integration
+on: push
-For reference, here is our complete
-[.travis.yml example file](https://github.com/scalacenter/library-example/blob/master/.travis.yml).
+jobs:
+ ci:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3 # Retrieve the content of the repository
+ - uses: actions/setup-java@v3 # Set up a jdk
+ with:
+ distribution: temurin
+ java-version: 8
+ cache: sbt # Cache the artifacts downloaded by sbt accross CI runs
+ - name: unit tests # Custom action consisting of a shell command
+ run: sbt +test
+~~~
+
+This workflow is called *Continuous integration*, and it will run every time one
+or more commits are pushed to the repository. It contains only one job called
+*ci*, which will run on an Ubuntu runner and that is composed of three
+actions. The action `setup-java` installs a JDK and caches the library dependencies
+downloaded by sbt so that they are not downloaded again everytime the CI runs.
+
+Then, the job runs `sbt +test`, which loads the sbt version specified in
+`project/build.properties`, and runs the project tests using the Scala version
+defined in the file `build.sbt`.
+
+The workflow above will run at any push to any branch of the repository. You
+can specify the branch or add more triggers such as pull requests, releases,
+tags or schedules. More information about workflow triggers is available
+[here](https://docs.github.com/en/actions/reference/events-that-trigger-workflows).
+while the `setup-java` action is hosted [in this
+repository](https://github.com/actions/setup-java).
+
+For reference, here is our complete [workflow example
+file](https://github.com/scalacenter/library-example/blob/main/.github/workflows/ci.yml).
## Publish a Release
Most build tools resolve third-party dependencies by looking them up on public repositories such as
-[Maven Central](https://search.maven.org/) or [Bintray](https://bintray.com/). These repositories host
+[Maven Central](https://search.maven.org/). These repositories host
the library binaries as well as additional information such as the library authors, the open source
license, and the dependencies of the library itself. Each release of a library is identified by
a `groupId`, an `artifactId`, and a `version` number. For instance, consider the following dependency
@@ -125,7 +123,7 @@ sign the binaries.
### Create a Sonatype Account and Project
Follow the instructions given on the [OSSRH Guide](https://central.sonatype.org/pages/ossrh-guide.html#initial-setup)
-to create a new Sonatype account (unless you already have one) and to
+to create a new Sonatype account (unless you already have one) and to
[create a new project ticket](https://issues.sonatype.org/secure/CreateIssue.jspa?issuetype=21&pid=10134). This latter
step is where you define the `groupId` that you will release to. You can use a domain name that you already own,
otherwise a common practice is to use `io.github.(username)` (where `(username)` is replaced with your GitHub
@@ -135,24 +133,24 @@ This step has to be performed only once per `groupId` you want to have.
### Create a PGP Key Pair
-Sonatype [requires](https://central.sonatype.org/pages/requirements.html) that you sign the published files
-with PGP. Follow the instructions [here](https://central.sonatype.org/pages/working-with-pgp-signatures.html)
+Sonatype [requires](https://central.sonatype.org/publish/requirements) that you sign the published files
+with PGP. Follow the instructions [here](https://central.sonatype.org/publish/requirements/gpg)
to generate a key pair and to distribute your public key to a key server.
This step has to be performed only once per person.
### Setup Your Project
-In case you use sbt, we recommend using the [sbt-sonatype](https://github.com/xerial/sbt-sonatype)
+In case you use sbt, we recommend using the [sbt-sonatype](https://github.com/xerial/sbt-sonatype)
and [sbt-pgp](https://www.scala-sbt.org/sbt-pgp/) plugins to publish your artifacts. Add the following
dependencies to your `project/plugins.sbt` file:
~~~ scala
-addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "2.4")
-addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.0")
+addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.21")
+addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.2.1")
~~~
-And make sure your build fulfills the [Sonatype requirements](https://central.sonatype.org/pages/requirements.html)
+And make sure your build fulfills the [Sonatype requirements](https://central.sonatype.org/publish/requirements)
by defining the following settings:
~~~ scala
@@ -171,7 +169,7 @@ import xerial.sbt.Sonatype._
sonatypeProjectHosting := Some(GitHubHosting("scalacenter", "library-example", "julien.richard-foy@epfl.ch"))
// publish to the sonatype repository
-publishTo := sonatypePublishTo.value
+publishTo := sonatypePublishToBundle.value
~~~
Put your Sonatype credentials in a `$HOME/.sbt/1.0/sonatype.sbt` file:
@@ -183,7 +181,7 @@ credentials += Credentials("Sonatype Nexus Repository Manager",
"(Sonatype password)")
~~~
-(Put your actual user name and password in place of `(Sonatype user name)` and `(Sonatype password)`)
+(Put your actual username and password in place of `(Sonatype user name)` and `(Sonatype password)`)
**Never** check this file into version control.
@@ -191,7 +189,7 @@ Last, we recommend using the [sbt-dynver](https://github.com/dwijnand/sbt-dynver
of your releases. Add the following dependency to your `project/plugins.sbt` file:
~~~ scala
-addSbtPlugin("com.dwijnand" % "sbt-dynver" % "3.1.0")
+addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.0.1")
~~~
And make sure your build does **not** define the `version` setting.
@@ -201,7 +199,7 @@ And make sure your build does **not** define the `version` setting.
With this setup, the process for cutting a release is the following.
Create a Git tag whose name begins with a lowercase `v` followed by the version number:
-
+
~~~ bash
$ git tag v0.1.0
~~~
@@ -236,9 +234,17 @@ Continuous publication addresses these issues by delegating the publication proc
follows: any contributor with write access to the repository can cut a release by pushing a Git tag, the CI server
first checks that the tests pass and then runs the publication commands.
-The remaining sections show how to setup Travis CI for continuous publication on Sonatype. You can find instructions
-for other CI servers and repositories in the [sbt-release-early](https://github.com/scalacenter/sbt-release-early)
-plugin documentation.
+We achieve this by replacing the plugins `sbt-pgp`, `sbt-sonatype`, and `sbt-dynver` with `sbt-ci-release`, in the file `project/plugins.sbt`:
+
+{% highlight diff %}
+- addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.2.1")
+- addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.21")
+- addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.0.1")
++ addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.12")
+{% endhighlight %}
+
+The remaining sections show how to setup GitHub Actions for continuous publication on Sonatype. You can find instructions
+for Travis CI in the [sbt-ci-release](https://github.com/olafurpg/sbt-ci-release) plugin documentation.
### Setup the CI Server
@@ -247,28 +253,14 @@ it is possible to securely give this information by using the secret management
#### Export Your Sonatype Account Credentials
-The `SONATYPE_USERNAME` and `SONATYPE_PASSWORD` environment variables are recognized by the `sbt-sonatype`
-plugin, as documented [here](https://github.com/xerial/sbt-sonatype#homesbtsbt-version-013-or-10sonatypesbt-1).
-
-With Travis CI, you will have to install the [Travis CLI](https://github.com/travis-ci/travis.rb#installation).
-
-Then, run the following commands from your project root directory to add your Sonatype credentials as
-environment variables to your `.travis.yml` file in an encrypted form:
-
-~~~ bash
-$ travis encrypt SONATYPE_USERNAME="(Sonatype user name)" --add
-$ travis encrypt SONATYPE_PASSWORD="(Sonatype password)" --add
-~~~
-
-(Put your actual user name and password in place of `(Sonatype user name)` and `(Sonatype password)`)
+Create two [GitHub Encrypted secrets](https://docs.github.com/en/actions/reference/encrypted-secrets)
+for your Sonatype account credentials: `SONATYPE_USERNAME` and `SONATYPE_PASSWORD`.
+To do so, go to the *Settings* tab of the repository and select *Secrets* on the left panel.
+You can then use the button *New repository secret* to open the secret creation menu where you will enter
+the name of the secret and its content.
-The `--add` option updates your `.travis.yml` file with entries like the following:
-
-~~~ yaml
-env:
- global:
- - secure: "dllL1w+pZT6yTBYwy5hX07t8r0JL5Cqer6YgYnXJ+q3OhSGUs7ul2fDUiqVxGIgUpTij1cGwBmoJOTbRk2V/be4+3Ua4ZNrAxjNF2ehqUcV5KdC3ufTTTXX0ZoL9MqEIb+GKzKtPqbzR4uly/5q5NbV7J1GeZRhummnx87POl6yH4kmXTpahig7vvnwN5dLanMshRb2Z8tO8kF4SnC31QuNBDQLnS89PEajHQu+LRAJloYvcikm+NeUj79m64CYg9JZdrHvZpIYKOMY1twT+lYoerqzG+asiNE1WrDs/We1RFVgcrKLpEThcvuIxuuPKhu24+0KteAX+7z/ulT0lndyBRfuuDjHV844LrNbjhnTB64V1uF7aEdaEZRLTsFQnFZqzpoqYqxzgfow9LN/kU5CMJX1R4wwf3YgR1VC9ZfjZnu0Pbt24g48I+72ZDNk3oRZoPsN9AtovwdZcg7TgU/iPcHNKSNhEZRP6ryhv/9aX3URLkfhnDaJmTXAnC3YCYt5cGo0FBUHARA+AHcas14Dx95bFSbH7EBivb2LiDmi44goRCWR4p+vNSBJ6Ak1NZz/+paai0pXDG6S/VdqwGSmmfjn7m9H3L5c8X5xNich9qtZbWz0fj2baZGq/doA8KE91JCzX11p/9fKNzbVivQZdsw3C3ZWDjkMZM+hl++0="
-~~~
+Repository Secrets allow us to safely store confidential information and to expose
+it to Actions workflows without the risk of committing them to git history.
#### Export Your PGP Key Pair
@@ -285,72 +277,69 @@ uid Julien Richard-Foy
In my case, I have one key pair, whose ID is `BE614499`.
-Export your public and private keys into files, in a `ci` directory:
-~~~ bash
-$ mkdir ci
-$ gpg -a --export (key ID) > ci/pubring.asc
-$ gpg -a --export-secret-keys (key ID) > ci/secring.asc
-~~~
+Then:
+ 1. Create a new Secret containing the passphrase of your PGP key named `PGP_PASSPHRASE`.
+ 2. Create a new Secret containing the base64 encoded secret of your private key named `PGP_SECRET`. The encoded secret can obtain by running:
+```
+# macOS
+gpg --armor --export-secret-keys $LONG_ID | base64
+# Ubuntu (assuming GNU base64)
+gpg --armor --export-secret-keys $LONG_ID | base64 -w0
+# Arch
+gpg --armor --export-secret-keys $LONG_ID | base64 | sed -z 's;\n;;g'
+# FreeBSD (assuming BSD base64)
+gpg --armor --export-secret-keys $LONG_ID | base64
+# Windows
+gpg --armor --export-secret-keys %LONG_ID% | openssl base64
+```
+ 3. Publish your public key signature to a public server, for example [http://keyserver.ubuntu.com:11371](http://keyserver.ubuntu.com:11371/).
+ You can obtain the signature by running:
+```
+# macOS and linux
+gpg --armor --export $LONG_ID
+# Windows
+gpg --armor --export %LONG_ID%
+```
(Replace `(key ID)` with **your** key ID)
-Add the `ci/pubring.asc` file (which contains your public key) to your repository. The `secring.asc` file
-(which contains your private key) should **not** be added as it is to the repository, so make sure it will
-be ignored by Git by adding it to the `.gitignore` file:
-
-~~~
-ci/secring.asc
-~~~
-
-Encrypt it with the `travis` tool:
-
-~~~ bash
-$ travis encrypt-file ci/secring.asc ci/secring.asc.enc --add
-~~~
-
-As advised in the command output, make sure to add the `secring.asc.enc` to the git repository.
-
-The `--add` option above adds a line like the following to your `.travis.yml` file:
-
-~~~ diff
-before_install:
- - openssl aes-256-cbc -K $encrypted_602f530300eb_key -iv $encrypted_602f530300eb_iv -in ci/secring.asc.enc -out ci/secring.asc -d
-~~~
-
-Finally, add export your PGP passphrase to the `.travis.yml` file:
-
-~~~
-$ travis encrypt PGP_PASSPHRASE="(your passphrase)" --add
-~~~
-
-(Replace `(your passphrase)` with your actual passphrase)
#### Publish From the CI Server
-On Travis CI, you can define a
-[conditional stage](https://docs.travis-ci.com/user/build-stages/#specifying-stage-order-and-conditions)
-publishing the library when a tag is pushed:
+On GitHub Actions, you can define a workflow to publish the library when a tag starting with “v” is pushed:
-~~~ yaml
-jobs:
- include:
- - stage: test
- script: sbt test
- - stage: deploy
- if: tag =~ ^v
- script: sbt publishSigned sonatypeRelease
-~~~
+{% highlight yaml %}
+{% raw %}
+# .github/workflows/publish.yml
+name: Continuous publication
+on:
+ push:
+ tags: [v*]
-The last step is to tell your build definition how to retrieve the PGP passphrase from the `PGP_PASSPHRASE`
-environment variable and to use the `pubring.asc` and `secring.asc` files as the PGP key pair.
-Include the following settings in your `build.sbt` file:
+jobs:
+ release:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0 # fetch all tags, required to compute the release version
+ - uses: actions/setup-java@v3
+ with:
+ distribution: temurin
+ java-version: 8
+ cache: sbt
+ - run: sbt ci-release
+ env:
+ PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }}
+ PGP_SECRET: ${{ secrets.PGP_SECRET }}
+ SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
+ SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
+{% endraw %}
+{% endhighlight %}
-~~~ scala
-pgpPublicRing := file("ci/pubring.asc")
-pgpSecretRing := file("ci/secring.asc")
-pgpPassphrase := sys.env.get("PGP_PASSPHRASE").map(_.toArray)
-~~~
+The `env` statement exposes the secrets you defined earlier to the publication process through
+environment variables.
### Cut a Release
@@ -361,38 +350,28 @@ $ git tag v0.2.0
$ git push origin v0.2.0
~~~
+This will trigger the workflow, which will ultimately invoke `sbt ci-release`, which will perform a `publishSigned` followed by a `sonatypeRelease`.
+
## Cross-Publish
-If you have written a library, you probably want it to be usable from several Scala major versions (e.g., 2.11.x,
-2.12.x, 2.13.x, etc.).
+If you have written a library, you probably want it to be usable from several Scala major versions (e.g.,
+2.12.x, 2.13.x, 3.x, etc.).
Define the versions you want to support in the `crossScalaVersions` setting, in your `build.sbt` file:
~~~ scala
-crossScalaVersions := Seq("2.12.8", "2.11.12")
+crossScalaVersions := Seq("3.3.0", "2.13.12", "2.12.18")
scalaVersion := crossScalaVersions.value.head
~~~
The second line makes sbt use by default the first Scala version of the `crossScalaVersions`.
-
-Modify the CI jobs to use all the Scala versions of your build definition by using the `+` prefix,
-when appropriate:
-
-~~~ yaml
-jobs:
- include:
- - stage: test
- script: sbt +test
- - stage: deploy
- if: tag =~ ^v
- script: sbt +publishSigned sonatypeRelease
-~~~
+The CI job will use all the Scala versions of your build definition.
## Publish Online Documentation
An important property of documentation is that the code examples should compile and behave as they
are presented. There are various ways to ensure that this property holds. One way, supported by
-[tut](https://github.com/tpolecat/tut) and [mdoc](https://github.com/olafurpg/mdoc), is to actually
+[mdoc](https://github.com/scalameta/mdoc), is to actually
evaluate code examples and write the result of their evaluation in the produced documentation.
Another way consists in embedding snippets of source code coming from a real module or example.
@@ -407,26 +386,24 @@ an sbt-site to GitHub Pages.
### Create the Documentation Site
-In this example we choose to use [Paradox](https://developer.lightbend.com/docs/paradox/current/index.html)
-because it runs on the JVM and thus doesn’t require setting up another VM on your system (in contrast with
+In this example we choose to use [Paradox](https://github.com/lightbend/paradox)
+because it runs on the JVM and thus doesn't require setting up another VM on your system (in contrast with
most other documentation generators, which are based on Ruby, Node.js or Python).
To install Paradox and sbt-site, add the following lines to your `project/plugins.sbt` file:
~~~ scala
-addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.3.2")
-addSbtPlugin("com.lightbend.paradox" % "sbt-paradox" % "0.4.4")
+addSbtPlugin("com.github.sbt" % "sbt-site-paradox" % "1.5.0")
~~~
And then add the following configuration to your `build.sbt` file:
{% highlight scala %}
-enablePlugins(ParadoxPlugin, ParadoxSitePlugin)
+enablePlugins(ParadoxSitePlugin, SitePreviewPlugin)
Paradox / sourceDirectory := sourceDirectory.value / "documentation"
{% endhighlight %}
-The `ParadoxPlugin` is responsible of generating the website, and the `ParadoxSitePlugin` provides
-integration with `sbt-site`.
+The `ParadoxSitePlugin` provides a task `makeSite` that generates a website using [Paradox](https://github.com/lightbend/paradox), and the `SitePreviewPlugin` provides handy tasks when working on the website content, to preview the result in your browser.
The second line is optional, it defines the location of the website source files. In our case, in
`src/documentation`.
@@ -435,6 +412,7 @@ uses the library name as title, shows a short sentence describing the purpose of
snippet for adding the library to a build definition:
{% highlight markdown %}
+{% raw %}
# Library Example
A library that does nothing.
@@ -453,6 +431,7 @@ libraryDependencies += "ch.epfl.scala" %% "library-example" % "$project.version$
* [Getting Started](getting-started.md)
* [Reference](reference.md)
@@@
+{% endraw %}
{% endhighlight %}
Note that in our case we rely on a variable substitution mechanism to inject the correct version number
@@ -484,76 +463,18 @@ and behave as they are presented.
#### Using a Markdown Preprocessor
-One approach consists in using a Markdown preprocessor, such as [tut](https://github.com/tpolecat/tut) or
-[mdoc](https://github.com/olafurpg/mdoc). These tools read your Markdown source files, search for code fences,
+One approach consists in using a Markdown preprocessor such as
+[mdoc](https://github.com/scalameta/mdoc). These tools read your Markdown source files, search for code fences,
evaluate them (throwing an error if they don’t compile), and produce a copy of your Markdown files where
code fences have been updated to also include the result of evaluating the Scala expressions.
-For instance, given the following `src/documentation/getting-started.md` file:
-
-{% highlight markdown %}
-# Getting Started
-
-First, start with the following import:
-
-```tut
-import ch.epfl.scala.Example
-```
-
-Then, do nothing with something:
-
-```tut
-Example.doNothing(42)
-```
-{% endhighlight %}
-
-The tut tool will produce the following Markdown file:
-
-{% highlight markdown %}
-# Getting Started
-
-First, start with the following import:
-
-```scala
-scala> import ch.epfl.scala.Example
-import ch.epfl.scala.Example
-```
-
-Then, do nothing with something:
-
-```scala
-scala> Example.doNothing(42)
-res0: Int = 42
-```
-{% endhighlight %}
-
-You can see that `tut` code fences have been replaced with `scala` code fences, and the result of
-evaluating their content is shown, as it would look like from a REPL.
-
-To enable tut, add the following line to your `project/plugins.sbt` file:
-
-~~~ scala
-addSbtPlugin("org.tpolecat" % "tut-plugin" % "0.6.10")
-~~~
-
-And apply the following changes to your `build.sbt` file:
-
-{% highlight diff %}
-+enablePlugins(TutPlugin)
--Paradox / sourceDirectory := sourceDirectory.value / "documentation"
-+tutSourceDirectory := sourceDirectory.value / "documentation"
-+Paradox / sourceDirectory := tutTargetDirectory.value
-+makeSite := makeSite.dependsOn(tut).value
-{% endhighlight %}
-
-These changes add the `TutPlugin`, configure it to read sources from the `src/documentation` directory,
-configure Paradox to read the output of tut, and make sure tut is run before the site is built.
-
#### Embedding Snippets
Another approach consists in embedding fragments of Scala source files that are part of a module which
is compiled by your build. For instance, given the following test in file `src/test/ch/epfl/scala/Usage.scala`:
+{% tabs usage-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
~~~ scala
package ch.epfl.scala
@@ -570,16 +491,37 @@ object Usage extends Scalaprops {
}
~~~
+{% endtab %}
+{% tab 'Scala 3' %}
+~~~ scala
+package ch.epfl.scala
+
+import scalaprops.{Property, Scalaprops}
+
+object Usage extends Scalaprops:
+
+ val testDoNothing =
+// #do-nothing
+ Property.forAll: (x: Int) =>
+ Example.doNothing(x) == x
+// #do-nothing
+
+end Usage
+~~~
+{% endtab %}
+{% endtabs %}
You can embed the fragment surrounded by the `#do-nothing` identifiers with the `@@snip` Paradox directive,
as shown in the `src/documentation/reference.md` file:
{% highlight markdown %}
+{% raw %}
# Reference
The `doNothing` function takes anything as parameter and returns it unchanged:
@@snip [Usage.scala]($root$/src/test/scala/ch/epfl/scala/Usage.scala) { #do-nothing }
+{% endraw %}
{% endhighlight %}
The resulting documentation looks like the following:
@@ -616,7 +558,7 @@ The `@scaladoc` directive will produce a link to the `/api/ch/epfl/scala/Example
Add the `sbt-ghpages` plugin to your `project/plugins.sbt`:
~~~ scala
-addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.6.3")
+addSbtPlugin("com.github.sbt" % "sbt-ghpages" % "0.8.0")
~~~
And add the following configuration to your `build.sbt`:
@@ -649,78 +591,34 @@ can browse it at [https://scalacenter.github.io/library-example/](https://scalac
### Continuous Publication
-You need to grant the CI job write access to the Git repository hosting the documentation. This can be achieved
-by creating an SSH key that the CI job can use to push the website to GitHub.
-
-Create an SSH key:
-
-~~~ bash
-$ ssh-keygen -t rsa -b 4096 -C "sbt-site@travis" -f ci/travis-key
-~~~
-
-Make sure to **not** define a passphrase (just leave it empty and press enter), and to add the private
-key (the `ci/travis-key` file) to your `.gitignore`:
-
-~~~
-ci/secring.asc
-ci/travis-key
-~~~
-
-Add the public key, `ci/travis-key.pub`, in the Deploy Keys section of your GitHub project’s settings page:
+You can extend `.github/workflows/publish.yml` to automatically publish documentation to GitHub pages.
+To do so, add another job:
-
+```yaml
+# .github/workflows/publish.yml
+name: Continuous publication
-Make sure you “allow write access” by checking the box.
-
-The private key has to be added to the repository, like we did with the PGP private key. Unfortunately, due
-to a limitation of Travis CI, you can not add several encrypted files. The
-[workaround](https://docs.travis-ci.com/user/encrypting-files/#encrypting-multiple-files) consists in
-creating an archive containing all the files to encrypt. In your case, you want to encrypt the PGP
-key and the SSH key into a single `ci/secrets.tar` file:
-
-~~~ bash
-$ tar cvf ci/secrets.tar ci/secring.asc ci/travis-key
-$ travis encrypt-file ci/secrets.tar ci/secrets.tar.enc --add
-~~~
-
-Make sure to add the `ci/secrets.tar` file to your `.gitignore`:
-
-~~~
-ci/secring.asc
-ci/travis-key
-ci/secrets.tar
-~~~
-
-Finally, update the `.travis.yml` file to unpack the archive and push the documentation website
-on releases:
-
-~~~ yaml
jobs:
- include:
- - stage: test
- # Run tests for all Scala versions
- script: sbt +test
- name: "Tests"
- # Check that the documentation can be built
- - script: sbt makeSite
- name: "Documentation"
-
- - stage: deploy
- if: tag =~ ^v
- script:
- # decrypt PGP secret key and GitHub SSH key
- - openssl aes-256-cbc -K $encrypted_602f530300eb_key -iv $encrypted_602f530300eb_iv -in ci/secrets.tar.enc -out ci/secrets.tar -d
- - tar xvf ci/secrets.tar
- # load the key in the ssh-agent
- - chmod 600 ci/travis-key
- - eval "$(ssh-agent -s)"
- - ssh-add ci/travis-key
- # perform deployment
- - sbt makeSite +publishSigned sonatypeRelease ghpagesPushSite
-~~~
+ release: # The release job is not changed, you can find it above
+ publishSite:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ - uses: actions/setup-java@v3
+ with:
+ distribution: temurin
+ java-version: 8
+ cache: sbt
+ - name: Generate site
+ run: sbt makeSite
+ - uses: JamesIves/github-pages-deploy-action@4.1.3
+ with:
+ branch: gh-pages
+ folder: target/site
-(Replace the `$encrypted_602f530300eb_key` and `$encrypted_602f530300eb_iv` variables with the ones produced by the
-`travis encrypt-file` command)
+```
As usual, cut a release by pushing a Git tag. The CI server will run the tests, publish the binaries and update the
online documentation.
@@ -735,7 +633,7 @@ Add a `CONTRIBUTING.md` file to your repository, answering the following questio
What are the coding practices to follow? Where are the tests and how to run them?
For reference, you can read our minimal example of
-[`CONTRIBUTING.md` file](https://github.com/scalacenter/library-example/blob/master/CONTRIBUTING.md).
+[`CONTRIBUTING.md` file](https://github.com/scalacenter/library-example/blob/main/CONTRIBUTING.md).
### Issue Labels
@@ -753,20 +651,25 @@ For instance, to use [scalafmt](https://scalameta.org/scalafmt/), add the follow
file:
~~~ scala
-addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "1.5.1")
+addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.2")
~~~
In the `CONTRIBUTING.md` file, mention that you use that code formatter and encourage users to use the “format
on save” feature of their editor.
-In your `.travis.yml` file, add a first stage checking that the code has been properly formatted:
+In your `.github/workflows/ci.yml` file, add a step checking that the code has been properly formatted:
~~~ yaml
+# .github/workflows/ci.yml
+# The three periods `...` indicate the parts of file that do not change
+# from the snippets above and they are omitted for brevity
jobs:
- include:
-
- - stage: style
- script: sbt scalafmtCheck
+ ci:
+ # ...
+ steps:
+ # ...
+ - name: Code style
+ run: sbt scalafmtCheck
~~~
## Evolve
@@ -774,35 +677,45 @@ jobs:
From the user point of view, upgrading to a new version of a library should be a smooth process. Possibly,
it should even be a “non-event”.
-Breaking changes and migration steps should be thoroughly documented, and a we recommend following the
+Breaking changes and migration steps should be thoroughly documented, and we recommend following the
[semantic versioning](/overviews/core/binary-compatibility-for-library-authors.html#versioning-scheme---communicating-compatibility-breakages)
policy.
-The [MiMa](https://github.com/lightbend/migration-manager) tool can help you checking that you don’t
+The [MiMa](https://github.com/lightbend/migration-manager) tool can help you to check that you don't
break this versioning policy. Add the `sbt-mima-plugin` to your build with the following, in your
`project/plugins.sbt` file:
~~~ scala
-addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.3.0")
+addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "1.1.2")
~~~
-Configure it as follow, in `build.sbt`:
+Configure it as follows, in `build.sbt`:
~~~ scala
mimaPreviousArtifacts := previousStableVersion.value.map(organization.value %% name.value % _).toSet
~~~
-Last, add the following job to the “test” stage, in the `.travis.yml` file:
+Last, add the following step to the job `ci` of the `Continuous integration` workflow, in the `.github/workflows/ci.yml` file:
~~~ yaml
- - script: sbt mimaReportBinaryIssues
- name: "Binary compatibility"
+# .github/workflows/ci.yml
+# The three periods `...` indicate the parts of file that do not change
+# from the snippets above and they are omitted for brevity
+
+# ...
+jobs:
+ ci:
+ # ...
+ steps:
+ # ...
+ - name: Binary compatibility
+ run: sbt mimaReportBinaryIssues
~~~
This will check that pull requests don’t make changes that are binary incompatible with the
previous stable version.
-We suggest working with the following Git workflow: the `master` branch always receives pull requests
+We suggest working with the following Git workflow: the `main` branch always receives pull requests
for the next major version (so, binary compatibility checks are disabled, by setting the `mimaPreviousArtifacts`
value to `Set.empty`), and each major version `N` has a corresponding `N.x` branch (e.g., `1.x`, `2.x`, etc.) branch
where the binary compatibility checks are enabled.
diff --git a/_overviews/core/actors-migration-guide.md b/_overviews/core/actors-migration-guide.md
deleted file mode 100644
index c82aecc3e5..0000000000
--- a/_overviews/core/actors-migration-guide.md
+++ /dev/null
@@ -1,583 +0,0 @@
----
-layout: singlepage-overview
-title: The Scala Actors Migration Guide
-
-partof: actor-migration
-
-languages: [zh-cn]
-
-permalink: /overviews/core/:title.html
----
-
-**Vojin Jovanovic and Philipp Haller**
-
-## Introduction
-
-Starting with Scala 2.11.0, the Scala
-[Actors](actors.html)
-library is deprecated. Already in Scala 2.10.0 the default actor library is
-[Akka](https://akka.io).
-
-To ease the migration from Scala Actors to Akka we are providing the
-Actor Migration Kit (AMK). The AMK consists of an extension to Scala
-Actors which is enabled by including the `scala-actors-migration.jar`
-on a project's classpath. In addition, Akka 2.1 includes features,
-such as the `ActorDSL` singleton, which enable a simpler conversion of
-code using Scala Actors to Akka. The purpose of this document is to
-guide users through the migration process and explain how to use the
-AMK.
-
-This guide has the following structure. In Section "Limitations of the
-Migration Kit" we outline the main limitations of the migration
-kit. In Section "Migration Overview" we describe the migration process
-and talk about changes in the [Scala
-distribution](https://www.scala-lang.org/downloads) that make the
-migration possible. Finally, in Section "Step by Step Guide for
-Migrating to Akka" we show individual steps, with working examples,
-that are recommended when migrating from Scala Actors to Akka's
-actors.
-
-A disclaimer: concurrent code is notorious for bugs that are hard to
-debug and fix. Due to differences between the two actor
-implementations it is possible that errors appear. It is recommended
-to thoroughly test the code after each step of the migration process.
-
-## Limitations of the Migration Kit
-
-Due to differences in Akka and Scala actor models the complete functionality can not be migrated smoothly. The following list explains parts of the behavior that are hard to migrate:
-
-1. Relying on termination reason and bidirectional behavior with `link` method - Scala and Akka actors have different fault-handling and actor monitoring models.
-In Scala linked actors terminate if one of the linked parties terminates abnormally. If termination is tracked explicitly (by `self.trapExit`) the actor receives
-the termination reason from the failed actor. This functionality can not be migrated to Akka with the AMK. The AMK allows migration only for the
-[Akka monitoring](https://doc.akka.io/docs/akka/2.1.0/general/supervision.html#What_Lifecycle_Monitoring_Means)
-mechanism. Monitoring is different than linking because it is unidirectional and the termination reason is now known. If monitoring support is not enough, the migration
-of `link` must be postponed until the last possible moment (Step 5 of migration).
-Then, when moving to Akka, users must create an [supervision hierarchy](https://doc.akka.io/docs/akka/2.1.0/general/supervision.html) that will handle faults.
-
-2. Usage of the `restart` method - Akka does not provide explicit restart of actors so we can not provide the smooth migration for this use-case.
-The user must change the system so there are no usages of the `restart` method.
-
-3. Usage of method `getState` - Akka actors do not have explicit state so this functionality can not be migrated. The user code must not
-have `getState` invocations.
-
-4. Not starting actors right after instantiation - Akka actors are automatically started when instantiated. Users will have to
-reshape their system so it starts all the actors right after their instantiation.
-
-5. Method `mailboxSize` does not exist in Akka and therefore can not be migrated. This method is seldom used and can easily be removed.
-
-
-## Migration Overview
-
-### Migration Kit
-In Scala 2.10.0 actors reside inside the [Scala distribution](https://www.scala-lang.org/downloads) as a separate jar ( *scala-actors.jar* ), and
-the their interface is deprecated. The distribution also includes Akka actors in the *akka-actor.jar*.
-The AMK resides both in the Scala actors and in the *akka-actor.jar*. Future major releases of Scala will not contain Scala actors and the AMK.
-
-To start the migration user needs to add the *scala-actors.jar* and the *scala-actors-migration.jar* to the build of their projects.
-Addition of *scala-actors.jar* and *scala-actors-migration.jar* enables the usage of the AMK described below.
-
-### Step by Step Migration
-Actor Migration Kit should be used in 5 steps. Each step is designed to introduce minimal changes
-to the code base and allows users to run all system tests after it. In the first four steps of the migration
-the code will use the Scala actors implementation. However, the methods and class signatures will be transformed to closely resemble Akka.
-The migration kit on the Scala side introduces a new actor type (`ActWithStash`) and enforces access to actors through the `ActorRef` interface.
-
-It also enforces creation of actors through special methods on the `ActorDSL` object. In these steps it will be possible to migrate one
-actor at a time. This reduces the possibility of complex errors that are caused by several bugs introduced at the same time.
-
-After the migration on the Scala side is complete the user should change import statements and change
-the library used to Akka. On the Akka side, the `ActorDSL` and the `ActWithStash` allow
- modeling the `react` construct of Scala Actors and their life cycle. This step migrates all actors to the Akka back-end and could introduce bugs in the system. Once code is migrated to Akka, users will be able to use all the features of Akka.
-
-## Step by Step Guide for Migrating to Akka
-
-In this chapter we will go through 5 steps of the actor migration. After each step the code can be tested for possible errors. In the first 4
- steps one can migrate one actor at a time and test the functionality. However, the last step migrates all actors to Akka and it can be tested
-only as a whole. After this step the system should have the same functionality as before, however it will use the Akka actor library.
-
-### Step 1 - Everything as an Actor
-The Scala actors library provides public access to multiple types of actors. They are organized in the class hierarchy and each subclass
-provides slightly richer functionality. To make further steps of the migration easier we will first change each actor in the system to be of type `Actor`.
-This migration step is straightforward since the `Actor` class is located at the bottom of the hierarchy and provides the broadest functionality.
-
-The Actors from the Scala library should be migrated according to the following rules:
-
-1. `class MyServ extends Reactor[T]` -> `class MyServ extends Actor`
-
- Note that `Reactor` provides an additional type parameter which represents the type of the messages received. If user code uses
-that information then one needs to: _i)_ apply pattern matching with explicit type, or _ii)_ do the downcast of a message from
-`Any` to the type `T`.
-
-2. `class MyServ extends ReplyReactor` -> `class MyServ extends Actor`
-
-3. `class MyServ extends DaemonActor` -> `class MyServ extends Actor`
-
- To pair the functionality of the `DaemonActor` add the following line to the class definition.
-
- override def scheduler: IScheduler = DaemonScheduler
-
-### Step 2 - Instantiations
-
-In Akka, actors can be accessed only through the narrow interface called `ActorRef`. Instances of `ActorRef` can be acquired either
-by invoking an `actor` method on the `ActorDSL` object or through the `actorOf` method on an instance of an `ActorRefFactory`.
-In the Scala side of AMK we provide a subset of the Akka `ActorRef` and the `ActorDSL` which is the actual singleton object in the Akka library.
-
-This step of the migration makes all accesses to actors through `ActorRef`s. First, we show how to migrate common patterns for instantiating
-Scala `Actor`s. Then we show how to overcome issues with the different interfaces of `ActorRef` and `Actor`, respectively.
-
-#### Actor Instantiation
-
-The translation rules for actor instantiation (the following rules require importing `scala.actors.migration._`):
-
-1. Constructor Call Instantiation
-
- val myActor = new MyActor(arg1, arg2)
- myActor.start()
-
- should be replaced with
-
- ActorDSL.actor(new MyActor(arg1, arg2))
-
-2. DSL for Creating Actors
-
- val myActor = actor {
- // actor definition
- }
-
- should be replaced with
-
- val myActor = ActorDSL.actor(new Actor {
- def act() {
- // actor definition
- }
- })
-
-3. Object Extended from the `Actor` Trait
-
- object MyActor extends Actor {
- // MyActor definition
- }
- MyActor.start()
-
- should be replaced with
-
- class MyActor extends Actor {
- // MyActor definition
- }
-
- object MyActor {
- val ref = ActorDSL.actor(new MyActor)
- }
-
- All accesses to the object `MyActor` should be replaced with accesses to `MyActor.ref`.
-
-Note that Akka actors are always started on instantiation. In case actors in the migrated
- system are created and started at different locations, and changing this can affect the behavior of the system,
-users need to change the code so actors are started right after instantiation.
-
-Remote actors also need to be fetched as `ActorRef`s. To get an `ActorRef` of an remote actor use the method `selectActorRef`.
-
-#### Different Method Signatures
-
-At this point we have changed all the actor instantiations to return `ActorRef`s, however, we are not done yet.
-There are differences in the interface of `ActorRef`s and `Actor`s so we need to change the methods invoked on each migrated instance.
-Unfortunately, some of the methods that Scala `Actor`s provide can not be migrated. For the following methods users need to find a workaround:
-
-1. `getState()` - actors in Akka are managed by their supervising actors and are restarted by default.
-In that scenario state of an actor is not relevant.
-
-2. `restart()` - explicitly restarts a Scala actor. There is no corresponding functionality in Akka.
-
-All other `Actor` methods need to be translated to two methods that exist on the ActorRef. The translation is achieved by the rules described below.
-Note that all the rules require the following imports:
-
- import scala.concurrent.duration._
- import scala.actors.migration.pattern.ask
- import scala.actors.migration._
- import scala.concurrent._
-
-Additionally rules 1-3 require an implicit `Timeout` with infinite duration defined in the scope. However, since Akka does not allow for infinite timeouts, we will use
-100 years. For example:
-
- implicit val timeout = Timeout(36500 days)
-
-Rules:
-
-1. `!!(msg: Any): Future[Any]` gets replaced with `?`. This rule will change a return type to the `scala.concurrent.Future` which might not type check.
-Since `scala.concurrent.Future` has broader functionality than the previously returned one, this type error can be easily fixed with local changes:
-
- actor !! message -> respActor ? message
-
-2. `!![A] (msg: Any, handler: PartialFunction[Any, A]): Future[A]` gets replaced with `?`. The handler can be extracted as a separate
-function and then applied to the generated future result. The result of a handle should yield another future like
-in the following example:
-
- val handler: PartialFunction[Any, T] = ... // handler
- actor !! (message, handler) -> (respActor ? message) map handler
-
-3. `!? (msg: Any): Any` gets replaced with `?` and explicit blocking on the returned future:
-
- actor !? message ->
- Await.result(respActor ? message, Duration.Inf)
-
-4. `!? (msec: Long, msg: Any): Option[Any]` gets replaced with `?` and explicit blocking on the future:
-
- actor !? (dur, message) ->
- val res = respActor.?(message)(Timeout(dur milliseconds))
- val optFut = res map (Some(_)) recover { case _ => None }
- Await.result(optFut, Duration.Inf)
-
-Public methods that are not mentioned here are declared public for purposes of the actors DSL. They can be used only
-inside the actor definition so their migration is not relevant in this step.
-
-### Step 3 - `Actor`s become `ActWithStash`s
-
-At this point all actors inherit the `Actor` trait, we instantiate actors through special factory methods,
-and all actors are accessed through the `ActorRef` interface.
-Now we need to change all actors to the `ActWithStash` class from the AMK. This class behaves exactly the same like Scala `Actor`
-but, additionally, provides methods that correspond to methods in Akka's `Actor` trait. This allows easy, step by step, migration to the Akka behavior.
-
-To achieve this all classes that extend `Actor` should extend the `ActWithStash`. Apply the
-following rule:
-
- class MyActor extends Actor -> class MyActor extends ActWithStash
-
-After this change code might not compile. The `receive` method exists in `ActWithStash` and can not be used in the body of the `act` as is. To redirect the compiler to the previous method
-add the type parameter to all `receive` calls in your system. For example:
-
- receive { case x: Int => "Number" } ->
- receive[String] { case x: Int => "Number" }
-
-Additionally, to make the code compile, users must add the `override` keyword before the `act` method, and to create
-the empty `receive` method in the code. Method `act` needs to be overridden since its implementation in `ActWithStash`
-mimics the message processing loop of Akka. The changes are shown in the following example:
-
- class MyActor extends ActWithStash {
-
- // dummy receive method (not used for now)
- def receive = {case _ => }
-
- override def act() {
- // old code with methods receive changed to react.
- }
- }
-
-
-`ActWithStash` instances have variable `trapExit` set to `true` by default. If that is not desired set it to `false` in the initializer of the class.
-
-The remote actors will not work with `ActWithStash` out of the box. The method `register('name, this)` needs to be replaced with:
-
- registerActorRef('name, self)
-
-In later steps of the migration, calls to `registerActorRef` and `alive` should be treated like any other calls.
-
-After this point user can run the test suite and the whole system should behave as before. The `ActWithStash` and `Actor` use the same infrastructure so the system
-should behave exactly the same.
-
-### Step 4 - Removing the `act` Method
-
-In this section we describe how to remove the `act` method from `ActWithStash`s and how to
-change the methods used in the `ActWithStash` to resemble Akka. Since this step can be complex, it is recommended
-to do changes one actor at a time. In Scala, an actor's behavior is defined by implementing the `act` method. Logically, an actor is a concurrent process
-which executes the body of its `act` method, and then terminates. In Akka, the behavior is defined by using a global message
-handler which processes the messages in the actor's mailbox one by one. The message handler is a partial function, returned by the `receive` method,
-which gets applied to each message.
-
-Since the behavior of Akka methods in the `ActWithStash` depends on the removal of the `act` method we have to do that first. Then we will give the translation
-rules for translating individual methods of the `scala.actors.Actor` trait.
-
-#### Removal of `act`
-
-In the following list we present the translation rules for common message processing patterns. This list is not
-exhaustive and it covers only some common patterns. However, users can migrate more complex `act` methods to Akka by looking
- at existing translation rules and extending them for more complex situations.
-
-A note about nested `react`/`reactWithin` calls: the message handling
-partial function needs to be expanded with additional constructs that
-bring it closer to the Akka model. Although these changes can be
-complicated, migration is possible for an arbitrary level of
-nesting. See below for examples.
-
-A note about using `receive`/`receiveWithin` with complex control
-flow: migration can be complicated since it requires refactoring the
-`act` method. A `receive` call can be modeled using `react` and
-`andThen` on the message processing partial function. Again, simple
-examples are shown below.
-
-1. If there is any code in the `act` method that is being executed before the first `loop` with `react` that code
-should be moved to the `preStart` method.
-
- def act() {
- // initialization code here
- loop {
- react { ... }
- }
- }
-
- should be replaced with
-
- override def preStart() {
- // initialization code here
- }
-
- def act() {
- loop {
- react{ ... }
- }
- }
-
- This rule should be used in other patterns as well if there is code before the first react.
-
-2. When `act` is in the form of a simple `loop` with a nested `react` use the following pattern.
-
- def act() = {
- loop {
- react {
- // body
- }
- }
- }
-
- should be replaced with
-
- def receive = {
- // body
- }
-
-3. When `act` contains a `loopWhile` construct use the following translation.
-
- def act() = {
- loopWhile(c) {
- react {
- case x: Int =>
- // do task
- if (x == 42) {
- c = false
- }
- }
- }
- }
-
- should be replaced with
-
- def receive = {
- case x: Int =>
- // do task
- if (x == 42) {
- context.stop(self)
- }
- }
-
-4. When `act` contains nested `react`s use the following rule:
-
- def act() = {
- var c = true
- loopWhile(c) {
- react {
- case x: Int =>
- // do task
- if (x == 42) {
- c = false
- } else {
- react {
- case y: String =>
- // do nested task
- }
- }
- }
- }
- }
-
- should be replaced with
-
- def receive = {
- case x: Int =>
- // do task
- if (x == 42) {
- context.stop(self)
- } else {
- context.become(({
- case y: String =>
- // do nested task
- }: Receive).andThen(x => {
- unstashAll()
- context.unbecome()
- }).orElse { case x => stash(x) })
- }
- }
-
-5. For `reactWithin` method use the following translation rule:
-
- loop {
- reactWithin(t) {
- case TIMEOUT => // timeout processing code
- case msg => // message processing code
- }
- }
-
- should be replaced with
-
- import scala.concurrent.duration._
-
- context.setReceiveTimeout(t millisecond)
- def receive = {
- case ReceiveTimeout => // timeout processing code
- case msg => // message processing code
- }
-
-6. Exception handling is done in a different way in Akka. To mimic Scala actors behavior apply the following rule
-
- def act() = {
- loop {
- react {
- case msg =>
- // work that can fail
- }
- }
- }
-
- override def exceptionHandler = {
- case x: Exception => println("got exception")
- }
-
- should be replaced with
-
- def receive = PFCatch({
- case msg =>
- // work that can fail
- }, { case x: Exception => println("got exception") })
-
- where `PFCatch` is defined as
-
- class PFCatch(f: PartialFunction[Any, Unit],
- handler: PartialFunction[Exception, Unit])
- extends PartialFunction[Any, Unit] {
-
- def apply(x: Any) = {
- try {
- f(x)
- } catch {
- case e: Exception if handler.isDefinedAt(e) =>
- handler(e)
- }
- }
-
- def isDefinedAt(x: Any) = f.isDefinedAt(x)
- }
-
- object PFCatch {
- def apply(f: PartialFunction[Any, Unit],
- handler: PartialFunction[Exception, Unit]) =
- new PFCatch(f, handler)
- }
-
- `PFCatch` is not included in the AMK as it can stay as the permanent feature in the migrated code
- and the AMK will be removed with the next major release. Once the whole migration is complete fault-handling
- can also be converted to the Akka [supervision](https://doc.akka.io/docs/akka/2.1.0/general/supervision.html#What_Supervision_Means).
-
-
-
-#### Changing `Actor` Methods
-
-After we have removed the `act` method we should rename the methods that do not exist in Akka but have similar functionality. In the following list we present
-the list of differences and their translation:
-
-1. `exit()`/`exit(reason)` - should be replaced with `context.stop(self)`
-
-2. `receiver` - should be replaced with `self`
-
-3. `reply(msg)` - should be replaced with `sender ! msg`
-
-4. `link(actor)` - In Akka, linking of actors is done partially by [supervision](https://doc.akka.io/docs/akka/2.1.0/general/supervision.html#What_Supervision_Means)
-and partially by [actor monitoring](https://doc.akka.io/docs/akka/2.1.0/general/supervision.html#What_Lifecycle_Monitoring_Means). In the AMK we support
-only the monitoring method so the complete Scala functionality can not be migrated.
-
- The difference between linking and watching is that watching actors always receive the termination notification.
-However, instead of matching on the Scala `Exit` message that contains the reason of termination the Akka watching
-returns the `Terminated(a: ActorRef)` message that contains only the `ActorRef`. The functionality of getting the reason
- for termination is not supported by the migration. It can be done in Akka, after the Step 4, by organizing the actors in a [supervision hierarchy](https://doc.akka.io/docs/akka/2.1.0/general/supervision.html).
-
- If the actor that is watching does not match the `Terminated` message, and this message arrives, it will be terminated with the `DeathPactException`.
-Note that this will happen even when the watched actor terminated normally. In Scala linked actors terminate, with the same termination reason, only if
-one of the actors terminates abnormally.
-
- If the system can not be migrated solely with `watch` the user should leave invocations to `link` and `exit(reason)` as is. However since `act()` overrides the `Exit` message the following transformation
-needs to be applied:
-
- case Exit(actor, reason) =>
- println("sorry about your " + reason)
- ...
-
- should be replaced with
-
- case t @ Terminated(actorRef) =>
- println("sorry about your " + t.reason)
- ...
-
- NOTE: There is another subtle difference between Scala and Akka actors. In Scala, `link`/`watch` to the already dead actor will not have affect.
-In Akka, watching the already dead actor will result in sending the `Terminated` message. This can give unexpected behavior in the Step 5 of the migration guide.
-
-### Step 5 - Moving to the Akka Back-end
-
-At this point user code is ready to operate on Akka actors. Now we can switch the actors library from Scala to
-Akka actors. To do this configure the build to exclude the `scala-actors.jar` and the `scala-actors-migration.jar`,
- and to include *akka-actor.jar* and *typesafe-config.jar*. The AMK is built to work only with Akka actors version 2.1 which are included in the [Scala distribution](https://www.scala-lang.org/downloads)
- and can be configured by these [instructions](https://doc.akka.io/docs/akka/2.1.0/intro/getting-started.html#Using_a_build_tool).
-
-After this change the compilation will fail due to different package names and slight differences in the API. We will have to change each imported actor
-from scala to Akka. Following is the non-exhaustive list of package names that need to be changed:
-
- scala.actors._ -> akka.actor._
- scala.actors.migration.ActWithStash -> akka.actor.ActorDSL._
- scala.actors.migration.pattern.ask -> akka.pattern.ask
- scala.actors.migration.Timeout -> akka.util.Timeout
-
-Also, method declarations `def receive =` in `ActWithStash` should be prepended with `override`.
-
-In Scala actors the `stash` method needs a message as a parameter. For example:
-
- def receive = {
- ...
- case x => stash(x)
- }
-
-In Akka only the currently processed message can be stashed. Therefore replace the above example with:
-
- def receive = {
- ...
- case x => stash()
- }
-
-#### Adding Actor Systems
-
-The Akka actors are organized in [Actor systems](https://doc.akka.io/docs/akka/2.1.0/general/actor-systems.html).
- Each actor that is instantiated must belong to one `ActorSystem`. To achieve this add an `ActorSystem` instance to each actor instantiation call as a first argument. The following example shows the transformation.
-
-To achieve this transformation you need to have an actor system instantiated. The actor system is usually instantiated in Scala objects or configuration classes that are global to your system. For example:
-
- val system = ActorSystem("migration-system")
-
-Then apply the following transformation:
-
- ActorDSL.actor(...) -> ActorDSL.actor(system)(...)
-
-If many calls to `actor` use the same `ActorSystem` it can be passed as an implicit parameter. For example:
-
- ActorDSL.actor(...) ->
- import project.implicitActorSystem
- ActorDSL.actor(...)
-
-Finally, Scala programs are terminating when all the non-daemon threads and actors finish. With Akka the program ends when all the non-daemon threads finish and all actor systems are shut down.
- Actor systems need to be explicitly terminated before the program can exit. This is achieved by invoking the `shutdown` method on an Actor system.
-
-#### Remote Actors
-
-Once the code base is moved to Akka remoting will not work any more. The methods `registerActorFor` and `alive` need to be removed. In Akka, remoting is done solely by configuration and
-for further details refer to the [Akka remoting documentation](https://doc.akka.io/docs/akka/2.1.0/scala/remoting.html).
-
-#### Examples and Issues
-All of the code snippets presented in this document can be found in the [Actors Migration test suite](https://github.com/scala/actors-migration/tree/master/src/test/) as test files with the prefix `actmig`.
-
-This document and the Actor Migration Kit were designed and implemented by: [Vojin Jovanovic](https://people.epfl.ch/vojin.jovanovic) and [Philipp Haller](https://lampwww.epfl.ch/~phaller/)
-
-If you find any issues or rough edges please report them at the [Scala Bugtracker](https://github.com/scala/actors-migration/issues).
diff --git a/_overviews/core/actors.md b/_overviews/core/actors.md
deleted file mode 100644
index cd1309e2ae..0000000000
--- a/_overviews/core/actors.md
+++ /dev/null
@@ -1,506 +0,0 @@
----
-layout: singlepage-overview
-title: The Scala Actors API
-
-partof: actors
-
-languages: [zh-cn, es]
-
-permalink: /overviews/core/:title.html
----
-
-**Philipp Haller and Stephen Tu**
-
-## Introduction
-
-This guide describes the API of the `scala.actors` package of Scala 2.8/2.9. The organization follows groups of types that logically belong together. The trait hierarchy is taken into account to structure the individual sections. The focus is on the run-time behavior of the various methods that these traits define, thereby complementing the existing Scaladoc-based API documentation.
-
-NOTE: In Scala 2.10 the Actors library is deprecated and will be removed in future Scala releases. Users should use [Akka](https://akka.io) actors from the package `akka.actor`. For migration from Scala actors to Akka refer to the [Actors Migration Guide](actors-migration-guide.html).
-
-## The actor traits Reactor, ReplyReactor, and Actor
-
-### The Reactor trait
-
-`Reactor` is the super trait of all actor traits. Extending this trait allows defining actors with basic capabilities to send and receive messages.
-
-The behavior of a `Reactor` is defined by implementing its `act` method. The `act` method is executed once the `Reactor` is started by invoking `start`, which also returns the `Reactor`. The `start` method is *idempotent* which means that invoking it on an actor that has already been started has no effect.
-
-The `Reactor` trait has a type parameter `Msg` which indicates the type of messages that the actor can receive.
-
-Invoking the `Reactor`'s `!` method sends a message to the receiver. Sending a message using `!` is asynchronous which means that the sending actor does not wait until the message is received; its execution continues immediately. For example, `a ! msg` sends `msg` to `a`. All actors have a *mailbox* which buffers incoming messages until they are processed.
-
-The `Reactor` trait also defines a `forward` method. This method is inherited from `OutputChannel`. It has the same effect as the `!` method. Subtraits of `Reactor`, in particular the `ReplyReactor` trait, override this method to enable implicit reply destinations (see below).
-
-A `Reactor` receives messages using the `react` method. `react` expects an argument of type `PartialFunction[Msg, Unit]` which defines how messages of type `Msg` are handled once they arrive in the actor's mailbox. In the following example, the current actor waits to receive the string "Hello", and then prints a greeting:
-
- react {
- case "Hello" => println("Hi there")
- }
-
-Invoking `react` never returns. Therefore, any code that should run after a message has been received must be contained inside the partial function that is passed to `react`. For example, two messages can be received in sequence by nesting two invocations of `react`:
-
- react {
- case Get(from) =>
- react {
- case Put(x) => from ! x
- }
- }
-
-The `Reactor` trait also provides control structures which simplify programming with `react`.
-
-#### Termination and execution states
-
-The execution of a `Reactor` terminates when the body of its `act` method has run to completion. A `Reactor` can also terminate itself explicitly using the `exit` method. The return type of `exit` is `Nothing`, because `exit` always throws an exception. This exception is only used internally, and should never be caught.
-
-A terminated `Reactor` can be restarted by invoking its `restart` method. Invoking `restart` on a `Reactor` that has not terminated, yet, throws an `IllegalStateException`. Restarting a terminated actor causes its `act` method to be rerun.
-
-`Reactor` defines a method `getState` which returns the actor's current execution state as a member of the `Actor.State` enumeration. An actor that has not been started, yet, is in state `Actor.State.New`. An actor that can run without waiting for a message is in state `Actor.State.Runnable`. An actor that is suspended, waiting for a message is in state `Actor.State.Suspended`. A terminated actor is in state `Actor.State.Terminated`.
-
-#### Exception handling
-
-The `exceptionHandler` member allows defining an exception handler that is enabled throughout the entire lifetime of a `Reactor`:
-
- def exceptionHandler: PartialFunction[Exception, Unit]
-
-`exceptionHandler` returns a partial function which is used to handle exceptions that are not otherwise handled: whenever an exception propagates out of the body of a `Reactor`'s `act` method, the partial function is applied to that exception, allowing the actor to run clean-up code before it terminates. Note that the visibility of `exceptionHandler` is `protected`.
-
-Handling exceptions using `exceptionHandler` works well together with the control structures for programming with `react`. Whenever an exception has been handled using the partial function returned by `exceptionHandler`, execution continues with the current continuation closure. Example:
-
- loop {
- react {
- case Msg(data) =>
- if (cond) // process data
- else throw new Exception("cannot process data")
- }
- }
-
-Assuming that the `Reactor` overrides `exceptionHandler`, after an exception thrown inside the body of `react` is handled, execution continues with the next loop iteration.
-
-### The ReplyReactor trait
-
-The `ReplyReactor` trait extends `Reactor[Any]` and adds or overrides the following methods:
-
-- The `!` method is overridden to obtain a reference to the current
- actor (the sender); together with the actual message, the sender
- reference is transferred to the mailbox of the receiving actor. The
- receiver has access to the sender of a message through its `sender`
- method (see below).
-
-- The `forward` method is overridden to obtain a reference to the
- `sender` of the message that is currently being processed. Together
- with the actual message, this reference is transferred as the sender
- of the current message. As a consequence, `forward` allows
- forwarding messages on behalf of actors different from the current
- actor.
-
-- The added `sender` method returns the sender of the message that is
- currently being processed. Given the fact that a message might have
- been forwarded, `sender` may not return the actor that actually sent
- the message.
-
-- The added `reply` method sends a message back to the sender of the
- last message. `reply` is also used to reply to a synchronous message
- send or a message send with future (see below).
-
-- The added `!?` methods provide *synchronous message sends*. Invoking
- `!?` causes the sending actor to wait until a response is received
- which is then returned. There are two overloaded variants. The
- two-parameter variant takes in addition a timeout argument (in
- milliseconds), and its return type is `Option[Any]` instead of
- `Any`. If the sender does not receive a response within the
- specified timeout period, `!?` returns `None`, otherwise it returns
- the response wrapped in `Some`.
-
-- The added `!!` methods are similar to synchronous message sends in
- that they allow transferring a response from the receiver. However,
- instead of blocking the sending actor until a response is received,
- they return `Future` instances. A `Future` can be used to retrieve
- the response of the receiver once it is available; it can also be
- used to find out whether the response is already available without
- blocking the sender. There are two overloaded variants. The
- two-parameter variant takes in addition an argument of type
- `PartialFunction[Any, A]`. This partial function is used for
- post-processing the receiver's response. Essentially, `!!` returns a
- future which applies the partial function to the response once it is
- received. The result of the future is the result of this
- post-processing.
-
-- The added `reactWithin` method allows receiving messages within a
- given period of time. Compared to `react` it takes an additional
- parameter `msec` which indicates the time period in milliseconds
- until the special `TIMEOUT` pattern matches (`TIMEOUT` is a case
- object in package `scala.actors`). Example:
-
- reactWithin(2000) {
- case Answer(text) => // process text
- case TIMEOUT => println("no answer within 2 seconds")
- }
-
- The `reactWithin` method also allows non-blocking access to the
- mailbox. When specifying a time period of 0 milliseconds, the
- mailbox is first scanned to find a matching message. If there is no
- matching message after the first scan, the `TIMEOUT` pattern
- matches. For example, this enables receiving certain messages with a
- higher priority than others:
-
- reactWithin(0) {
- case HighPriorityMsg => // ...
- case TIMEOUT =>
- react {
- case LowPriorityMsg => // ...
- }
- }
-
- In the above example, the actor first processes the next
- `HighPriorityMsg`, even if there is a `LowPriorityMsg` that arrived
- earlier in its mailbox. The actor only processes a `LowPriorityMsg`
- *first* if there is no `HighPriorityMsg` in its mailbox.
-
-In addition, `ReplyReactor` adds the `Actor.State.TimedSuspended` execution state. A suspended actor, waiting to receive a message using `reactWithin` is in state `Actor.State.TimedSuspended`.
-
-### The Actor trait
-
-The `Actor` trait extends `ReplyReactor` and adds or overrides the following members:
-
-- The added `receive` method behaves like `react` except that it may
- return a result. This is reflected in its type, which is polymorphic
- in its result: `def receive[R](f: PartialFunction[Any, R]): R`.
- However, using `receive` makes the actor more heavyweight, since
- `receive` blocks the underlying thread while the actor is suspended
- waiting for a message. The blocked thread is unavailable to execute
- other actors until the invocation of `receive` returns.
-
-- The added `link` and `unlink` methods allow an actor to link and unlink
- itself to and from another actor, respectively. Linking can be used
- for monitoring and reacting to the termination of another actor. In
- particular, linking affects the behavior of invoking `exit` as
- explained in the API documentation of the `Actor` trait.
-
-- The `trapExit` member allows reacting to the termination of linked
- actors independently of the exit reason (that is, it does not matter
- whether the exit reason is `'normal` or not). If an actor's `trapExit`
- member is set to `true`, this actor will never terminate because of
- linked actors. Instead, whenever one of its linked actors terminates
- it will receive a message of type `Exit`. The `Exit` case class has two
- members: `from` refers to the actor that terminated; `reason` refers to
- the exit reason.
-
-#### Termination and execution states
-
-When terminating the execution of an actor, the exit reason can be set
-explicitly by invoking the following variant of `exit`:
-
- def exit(reason: AnyRef): Nothing
-
-An actor that terminates with an exit reason different from the symbol
-`'normal` propagates its exit reason to all actors linked to it. If an
-actor terminates because of an uncaught exception, its exit reason is
-an instance of the `UncaughtException` case class.
-
-The `Actor` trait adds two new execution states. An actor waiting to
-receive a message using `receive` is in state
-`Actor.State.Blocked`. An actor waiting to receive a message using
-`receiveWithin` is in state `Actor.State.TimedBlocked`.
-
-## Control structures
-
-The `Reactor` trait defines control structures that simplify programming
-with the non-returning `react` operation. Normally, an invocation of
-`react` does not return. If the actor should execute code subsequently,
-then one can either pass the actor's continuation code explicitly to
-`react`, or one can use one of the following control structures which
-hide these continuations.
-
-The most basic control structure is `andThen`. It allows registering a
-closure that is executed once the actor has finished executing
-everything else.
-
- actor {
- {
- react {
- case "hello" => // processing "hello"
- }: Unit
- } andThen {
- println("hi there")
- }
- }
-
-For example, the above actor prints a greeting after it has processed
-the `"hello"` message. Even though the invocation of `react` does not
-return, we can use `andThen` to register the code which prints the
-greeting as the actor's continuation.
-
-Note that there is a *type ascription* that follows the `react`
-invocation (`: Unit`). Basically, it lets you treat the result of
-`react` as having type `Unit`, which is legal, since the result of an
-expression can always be dropped. This is necessary to do here, since
-`andThen` cannot be a member of type `Nothing` which is the result
-type of `react`. Treating the result type of `react` as `Unit` allows
-the application of an implicit conversion which makes the `andThen`
-member available.
-
-The API provides a few more control structures:
-
-- `loop { ... }`. Loops indefinitely, executing the code in braces in
- each iteration. Invoking `react` inside the loop body causes the
- actor to react to a message as usual. Subsequently, execution
- continues with the next iteration of the same loop.
-
-- `loopWhile (c) { ... }`. Executes the code in braces while the
- condition `c` returns `true`. Invoking `react` in the loop body has
- the same effect as in the case of `loop`.
-
-- `continue`. Continues with the execution of the current continuation
- closure. Invoking `continue` inside the body of a `loop` or
- `loopWhile` will cause the actor to finish the current iteration and
- continue with the next iteration. If the current continuation has
- been registered using `andThen`, execution continues with the
- closure passed as the second argument to `andThen`.
-
-The control structures can be used anywhere in the body of a `Reactor`'s
-`act` method and in the bodies of methods (transitively) called by
-`act`. For actors created using the `actor { ... }` shorthand the control
-structures can be imported from the `Actor` object.
-
-#### Futures
-
-The `ReplyReactor` and `Actor` traits support result-bearing message
-send operations (the `!!` methods) that immediately return a
-*future*. A future, that is, an instance of the `Future` trait, is a
-handle that can be used to retrieve the response to such a message
-send-with-future.
-
-The sender of a message send-with-future can wait for the future's
-response by *applying* the future. For example, sending a message using
-`val fut = a !! msg` allows the sender to wait for the result of the
-future as follows: `val res = fut()`.
-
-In addition, a `Future` can be queried to find out whether its result
-is available without blocking using the `isSet` method.
-
-A message send-with-future is not the only way to obtain a
-future. Futures can also be created from computations directly.
-In the following example, the computation body is started to
-run concurrently, returning a future for its result:
-
- val fut = Future { body }
- // ...
- fut() // wait for future
-
-What makes futures special in the context of actors is the possibility
-to retrieve their result using the standard actor-based receive
-operations, such as `receive` etc. Moreover, it is possible to use the
-event-based operations `react` and `reactWithin`. This enables an actor to
-wait for the result of a future without blocking its underlying
-thread.
-
-The actor-based receive operations are made available through the
-future's `inputChannel`. For a future of type `Future[T]`, its type is
-`InputChannel[T]`. Example:
-
- val fut = a !! msg
- // ...
- fut.inputChannel.react {
- case Response => // ...
- }
-
-## Channels
-
-Channels can be used to simplify the handling of messages that have
-different types but that are sent to the same actor. The hierarchy of
-channels is divided into `OutputChannel`s and `InputChannel`s.
-
-`OutputChannel`s can be sent messages. An `OutputChannel` `out`
-supports the following operations.
-
-- `out ! msg`. Asynchronously sends `msg` to `out`. A reference to the
- sending actor is transferred as in the case where `msg` is sent
- directly to an actor.
-
-- `out forward msg`. Asynchronously forwards `msg` to `out`. The
- sending actor is determined as in the case where `msg` is forwarded
- directly to an actor.
-
-- `out.receiver`. Returns the unique actor that is receiving messages
- sent to the `out` channel.
-
-- `out.send(msg, from)`. Asynchronously sends `msg` to `out` supplying
- `from` as the sender of the message.
-
-Note that the `OutputChannel` trait has a type parameter that specifies
-the type of messages that can be sent to the channel (using `!`,
-`forward`, and `send`). The type parameter is contravariant:
-
- trait OutputChannel[-Msg]
-
-Actors can receive messages from `InputChannel`s. Like `OutputChannel`,
-the `InputChannel` trait has a type parameter that specifies the type of
-messages that can be received from the channel. The type parameter is
-covariant:
-
- trait InputChannel[+Msg]
-
-An `InputChannel[Msg]` `in` supports the following operations.
-
-- `in.receive { case Pat1 => ... ; case Patn => ... }` (and similarly,
- `in.receiveWithin`). Receives a message from `in`. Invoking
- `receive` on an input channel has the same semantics as the standard
- `receive` operation for actors. The only difference is that the
- partial function passed as an argument has type
- `PartialFunction[Msg, R]` where `R` is the return type of `receive`.
-
-- `in.react { case Pat1 => ... ; case Patn => ... }` (and similarly,
- `in.reactWithin`). Receives a message from `in` using the
- event-based `react` operation. Like `react` for actors, the return
- type is `Nothing`, indicating that invocations of this method never
- return. Like the `receive` operation above, the partial function
- passed as an argument has a more specific type:
-
- PartialFunction[Msg, Unit]
-
-### Creating and sharing channels
-
-Channels are created using the concrete `Channel` class. It extends both
-`InputChannel` and `OutputChannel`. A channel can be shared either by
-making the channel visible in the scopes of multiple actors, or by
-sending it in a message.
-
-The following example demonstrates scope-based sharing.
-
- actor {
- var out: OutputChannel[String] = null
- val child = actor {
- react {
- case "go" => out ! "hello"
- }
- }
- val channel = new Channel[String]
- out = channel
- child ! "go"
- channel.receive {
- case msg => println(msg.length)
- }
- }
-
-Running this example prints the string `"5"` to the console. Note that
-the `child` actor has only access to `out` which is an
-`OutputChannel[String]`. The `channel` reference, which can also be used
-to receive messages, is hidden. However, care must be taken to ensure
-the output channel is initialized to a concrete channel before the
-`child` sends messages to it. This is done using the `"go"` message. When
-receiving from `channel` using `channel.receive` we can make use of the
-fact that `msg` is of type `String`; therefore, it provides a `length`
-member.
-
-An alternative way to share channels is by sending them in
-messages. The following example demonstrates this.
-
- case class ReplyTo(out: OutputChannel[String])
-
- val child = actor {
- react {
- case ReplyTo(out) => out ! "hello"
- }
- }
-
- actor {
- val channel = new Channel[String]
- child ! ReplyTo(channel)
- channel.receive {
- case msg => println(msg.length)
- }
- }
-
-The `ReplyTo` case class is a message type that we use to distribute a
-reference to an `OutputChannel[String]`. When the `child` actor receives a
-`ReplyTo` message it sends a string to its output channel. The second
-actor receives a message on that channel as before.
-
-## Schedulers
-
-A `Reactor` (or an instance of a subtype) is executed using a
-*scheduler*. The `Reactor` trait introduces the `scheduler` member which
-returns the scheduler used to execute its instances:
-
- def scheduler: IScheduler
-
-The run-time system executes actors by submitting tasks to the
-scheduler using one of the `execute` methods defined in the `IScheduler`
-trait. Most of the trait's other methods are only relevant when
-implementing a new scheduler from scratch, which is rarely necessary.
-
-The default schedulers used to execute instances of `Reactor` and `Actor`
-detect the situation when all actors have finished their
-execution. When this happens, the scheduler shuts itself down
-(terminating any threads used by the scheduler). However, some
-schedulers, such as the `SingleThreadedScheduler` (in package `scheduler`)
-have to be shut down explicitly by invoking their `shutdown` method.
-
-The easiest way to create a custom scheduler is by extending
-`SchedulerAdapter`, implementing the following abstract member:
-
- def execute(fun: => Unit): Unit
-
-Typically, a concrete implementation would use a thread pool to
-execute its by-name argument `fun`.
-
-## Remote Actors
-
-This section describes the remote actors API. Its main interface is
-the [`RemoteActor`](https://www.scala-lang.org/api/2.9.1/scala/actors/remote/RemoteActor$.html) object in package `scala.actors.remote`. This object
-provides methods to create and connect to remote actor instances. In
-the code snippets shown below we assume that all members of
-`RemoteActor` have been imported; the full list of imports that we use
-is as follows:
-
- import scala.actors._
- import scala.actors.Actor._
- import scala.actors.remote._
- import scala.actors.remote.RemoteActor._
-
-### Starting remote actors
-
-A remote actor is uniquely identified by a [`Symbol`](https://www.scala-lang.org/api/current/scala/Symbol.html). This symbol is
-unique to the JVM instance on which the remote actor is executed. A
-remote actor identified with name `'myActor` can be created as follows.
-
- class MyActor extends Actor {
- def act() {
- alive(9000)
- register('myActor, self)
- // ...
- }
- }
-
-Note that a name can only be registered with a single (alive) actor at
-a time. For example, to register an actor *A* as `'myActor`, and then
-register another actor *B* as `'myActor`, one would first have to wait
-until *A* terminated. This requirement applies across all ports, so
-simply registering *B* on a different port as *A* is not sufficient.
-
-### Connecting to remote actors
-
-Connecting to a remote actor is just as simple. To obtain a remote
-reference to a remote actor running on machine `myMachine`, on port
-8000, with name `'anActor`, use `select` in the following manner:
-
- val myRemoteActor = select(Node("myMachine", 8000), 'anActor)
-
-The actor returned from `select` has type `AbstractActor` which provides
-essentially the same interface as a regular actor, and thus supports
-the usual message send operations:
-
- myRemoteActor ! "Hello!"
- receive {
- case response => println("Response: " + response)
- }
- myRemoteActor !? "What is the meaning of life?" match {
- case 42 => println("Success")
- case oops => println("Failed: " + oops)
- }
- val future = myRemoteActor !! "What is the last digit of PI?"
-
-Note that `select` is lazy; it does not actually initiate any network
-connections. It simply creates a new `AbstractActor` instance which is
-ready to initiate a new network connection when needed (for instance,
-when `!` is invoked).
diff --git a/_overviews/core/architecture-of-scala-213-collections.md b/_overviews/core/architecture-of-scala-213-collections.md
index 7e14fd6248..1d8da0859d 100644
--- a/_overviews/core/architecture-of-scala-213-collections.md
+++ b/_overviews/core/architecture-of-scala-213-collections.md
@@ -9,13 +9,13 @@ permalink: /overviews/core/:title.html
This document describes the architecture of the Scala collections
framework in detail. Compared to
-[the Collections Introduction]({{ site.baseurl }}/overviews/collections/introduction.html) you
+[the Collections Introduction]({{ site.baseurl }}/overviews/collections-2.13/introduction.html) you
will find out more about the internal workings of the framework. You
will also learn how this architecture helps you define your own
collections in a few lines of code, while reusing the overwhelming
part of collection functionality from the framework.
-[The Collections API]({{ site.baseurl }}/overviews/collections/introduction.html)
+[The Collections API]({{ site.baseurl }}/overviews/collections-2.13/trait-iterable.html)
contains a large number of collection
operations, which exist uniformly on many different collection
implementations. Implementing every collection operation anew for
@@ -70,6 +70,8 @@ because we want them to return collection types that are unknown yet.
For instance, consider the signature of the `map` operation on `List[A]`
and `Vector[A]`:
+{% tabs factoring_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=factoring_1 %}
~~~ scala
trait List[A] {
def map[B](f: A => B): List[B]
@@ -79,6 +81,17 @@ trait Vector[A] {
def map[B](f: A => B): Vector[B]
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=factoring_1 %}
+~~~ scala
+trait List[A]:
+ def map[B](f: A => B): List[B]
+
+trait Vector[A]:
+ def map[B](f: A => B): Vector[B]
+~~~
+{% endtab %}
+{% endtabs %}
To generalize the type signature of `map` we have to abstract over
the resulting *collection type constructor*.
@@ -86,6 +99,8 @@ the resulting *collection type constructor*.
A slightly different example is `filter`. Consider its type signature on
`List[A]` and `Map[K, V]`:
+{% tabs factoring_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=factoring_2 %}
~~~ scala
trait List[A] {
def filter(p: A => Boolean): List[A]
@@ -95,6 +110,17 @@ trait Map[K, V] {
def filter(p: ((K, V)) => Boolean): Map[K, V]
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=factoring_2 %}
+~~~ scala
+trait List[A]:
+ def filter(p: A => Boolean): List[A]
+
+trait Map[K, V]:
+ def filter(p: ((K, V)) => Boolean): Map[K, V]
+~~~
+{% endtab %}
+{% endtabs %}
To generalize the type signature of `filter` we have to abstract
over the resulting *collection type*.
@@ -112,9 +138,13 @@ on the `Iterable[A]` collection type.
Here is the header of trait `IterableOps`:
+{% tabs abstracting_1 %}
+{% tab 'Scala 2 and 3' for=abstracting_1 %}
~~~ scala
trait IterableOps[+A, +CC[_], +C] { … }
~~~
+{% endtab %}
+{% endtabs %}
The type parameter `A` stands for the element type of the iterable,
the type parameter `CC` stands for the collection type constructor
@@ -123,21 +153,36 @@ and the type parameter `C` stands for the collection type.
This allows us to define the signature of `filter` and `map` like
so:
+{% tabs abstracting_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=abstracting_2 %}
~~~ scala
trait IterableOps[+A, +CC[_], +C] {
def filter(p: A => Boolean): C = …
def map[B](f: A => B): CC[B] = …
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=abstracting_2 %}
+~~~ scala
+trait IterableOps[+A, +CC[_], +C]:
+ def filter(p: A => Boolean): C = …
+ def map[B](f: A => B): CC[B] = …
+~~~
+{% endtab %}
+{% endtabs %}
Leaf collection types appropriately instantiate the type
parameters. For instance, in the case of `List[A]` we want `CC` to
be `List` and `C` to be `List[A]`:
+{% tabs abstracting_3 %}
+{% tab 'Scala 2 and 3' for=abstracting_3 %}
~~~ scala
trait List[+A] extends Iterable[A]
with IterableOps[A, List, List[A]]
~~~
+{% endtab %}
+{% endtabs %}
## Four branches of templates traits ##
@@ -149,19 +194,33 @@ parameter whereas `Map[K, V]` takes two type parameters.
To support collection types constructors with two types parameters
we have another template trait named `MapOps`:
+{% tabs fourBranches_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=fourBranches_1 %}
~~~ scala
trait MapOps[K, +V, +CC[_, _], +C] extends IterableOps[(K, V), Iterable, C] {
def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] = …
}
-~~~
+~~~
+{% endtab %}
+{% tab 'Scala 3' for=fourBranches_1 %}
+~~~ scala
+trait MapOps[K, +V, +CC[_, _], +C] extends IterableOps[(K, V), Iterable, C]:
+ def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] = …
+~~~
+{% endtab %}
+{% endtabs %}
And then `Map[K, V]` can extend this trait and appropriately instantiate its
type parameters:
+{% tabs fourBranches_2 %}
+{% tab 'Scala 2 and 3' for=fourBranches_2 %}
~~~ scala
trait Map[K, V] extends Iterable[(K, V)]
with MapOps[K, V, Map, Map[K, V]]
~~~
+{% endtab %}
+{% endtabs %}
Note that the `MapOps` trait inherits from `IterableOps` so that operations
defined in `IterableOps` are also available in `MapOps`. Also note that
@@ -169,6 +228,8 @@ the collection type constructor passed to the `IterableOps` trait is
`Iterable`. This means that `Map[K, V]` inherits two overloads of the `map`
operation:
+{% tabs fourBranches_3 %}
+{% tab 'Scala 2 and 3' for=fourBranches_3 %}
~~~ scala
// from MapOps
def map[K2, V2](f: ((K, V)) => (K2, V2)): Map[K2, V2]
@@ -176,6 +237,8 @@ def map[K2, V2](f: ((K, V)) => (K2, V2)): Map[K2, V2]
// from IterableOps
def map[B](f: ((K, V)) => B): Iterable[B]
~~~
+{% endtab %}
+{% endtabs %}
At use-site, when you call the `map` operation, the compiler selects one of
the two overloads. If the function passed as argument to `map` returns a pair,
@@ -196,9 +259,18 @@ operations defined in `IterableOps` don’t match the type signature of a
more concrete collection type: `SortedSet[A]`. In that case the type
signature of the `map` operation is the following:
+{% tabs fourBranches_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=fourBranches_4 %}
~~~ scala
def map[B](f: A => B)(implicit ord: Ordering[B]): SortedSet[B]
~~~
+{% endtab %}
+{% tab 'Scala 3' for=fourBranches_4 %}
+~~~ scala
+def map[B](f: A => B)(using ord: Ordering[B]): SortedSet[B]
+~~~
+{% endtab %}
+{% endtabs %}
The difference with the signature we have in `IterableOps` is that here
we need an implicit `Ordering` instance for the type of elements.
@@ -206,24 +278,36 @@ we need an implicit `Ordering` instance for the type of elements.
Like for `Map`, `SortedSet` needs a specialized template trait with
overloads for transformation operations:
+{% tabs fourBranches_5 class=tabs-scala-version %}
+{% tab 'Scala 2' for=fourBranches_5 %}
~~~ scala
trait SortedSetOps[A, +CC[_], +C] extends IterableOps[A, Set, C] {
-
def map[B](f: A => B)(implicit ord: Ordering[B]): CC[B] = …
-
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=fourBranches_5 %}
+~~~ scala
+trait SortedSetOps[A, +CC[_], +C] extends IterableOps[A, Set, C]:
+ def map[B](f: A => B)(using ord: Ordering[B]): CC[B] = …
+~~~
+{% endtab %}
+{% endtabs %}
And then collection types that inherit the `SortedSetOps` trait appropriately
instantiate its type parameters:
+{% tabs fourBranches_6 %}
+{% tab 'Scala 2 and 3' for=fourBranches_6 %}
~~~ scala
trait SortedSet[A] extends SortedSetOps[A, SortedSet, SortedSet[A]]
~~~
+{% endtab %}
+{% endtabs %}
Last, there is a fourth kind of collection that requires a specialized template
trait: `SortedMap[K, V]`. This type of collection has two type parameters and
-needs an implicit ordering instance on the type of keys. Therefore we have a
+needs an implicit ordering instance on the type of keys. Therefore, we have a
`SortedMapOps` template trait that provides the appropriate overloads.
In total, we’ve seen that we have four branches of template traits:
@@ -260,11 +344,21 @@ non-strict `View`. For the record, a `View` “describes” an operation applied
to a collection but does not evaluate its result until the `View` is
effectively traversed. Here is the (simplified) definition of `View`:
+{% tabs nonStrict_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=nonStrict_1 %}
~~~ scala
trait View[+A] extends Iterable[A] with IterableOps[A, View, View[A]] {
def iterator: Iterator[A]
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=nonStrict_1 %}
+~~~ scala
+trait View[+A] extends Iterable[A], IterableOps[A, View, View[A]]:
+ def iterator: Iterator[A]
+~~~
+{% endtab %}
+{% endtabs %}
A `View` is an `Iterable` that has only one abstract method returning
an `Iterator` for traversing its elements. The `View` elements are
@@ -276,6 +370,8 @@ Now that we are more familiar with the hierarchy of the template traits, we can
a look at the actual implementation of some operations. Consider for instance the
implementations of `filter` and `map`:
+{% tabs operations_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=operations_1 %}
~~~ scala
trait IterableOps[+A, +CC[_], +C] {
@@ -289,6 +385,22 @@ trait IterableOps[+A, +CC[_], +C] {
protected def from[E](it: IterableOnce[E]): CC[E]
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=operations_1 %}
+~~~ scala
+trait IterableOps[+A, +CC[_], +C]:
+
+ def filter(pred: A => Boolean): C =
+ fromSpecific(View.Filter(this, pred))
+
+ def map[B](f: A => B): CC[B] =
+ from(View.Map(this, f))
+
+ protected def fromSpecific(coll: IterableOnce[A]): C
+ protected def from[E](it: IterableOnce[E]): CC[E]
+~~~
+{% endtab %}
+{% endtabs %}
Let’s detail the implementation of `filter`, step by step:
@@ -306,6 +418,8 @@ iterable whose element type `E` is arbitrary.
Actually, the `from` operation is not defined directly in `IterableOps` but is accessed via
an (abstract) `iterableFactory` member:
+{% tabs operations_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=operations_2 %}
~~~ scala
trait IterableOps[+A, +CC[_], +C] {
@@ -313,24 +427,47 @@ trait IterableOps[+A, +CC[_], +C] {
def map[B](f: A => B): CC[B] =
iterableFactory.from(new View.Map(this, f))
-
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=operations_2 %}
+~~~ scala
+trait IterableOps[+A, +CC[_], +C]:
+
+ def iterableFactory: IterableFactory[CC]
+
+ def map[B](f: A => B): CC[B] =
+ iterableFactory.from(View.Map(this, f))
+~~~
+{% endtab %}
+{% endtabs %}
This `iterableFactory` member is implemented by concrete collections and typically
refer to their companion object, which provides factory methods to create concrete
collection instances. Here is an excerpt of the definition of `IterableFactory`:
+{% tabs operations_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=operations_3 %}
~~~ scala
trait IterableFactory[+CC[_]] {
def from[A](source: IterableOnce[A]): CC[A]
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=operations_3 %}
+~~~ scala
+trait IterableFactory[+CC[_]]:
+ def from[A](source: IterableOnce[A]): CC[A]
+~~~
+{% endtab %}
+{% endtabs %}
Last but not least, as explained in the above sections, since we have four branches
of template traits, we have four corresponding branches of factories. For instance,
-here are the relevant parts of code of the `map` operation implementation in `Map`:
+here are the relevant parts of code of the `map` operation implementation in `MapOps`:
+{% tabs operations_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=operations_4 %}
~~~ scala
trait MapOps[K, +V, +CC[_, _], +C]
extends IterableOps[(K, V), Iterable, C] {
@@ -347,11 +484,28 @@ trait MapFactory[+CC[_, _]] {
def from[K, V](it: IterableOnce[(K, V)]): CC[K, V]
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=operations_4 %}
+~~~ scala
+trait MapOps[K, +V, +CC[_, _], +C]
+ extends IterableOps[(K, V), Iterable, C]:
+
+ def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] =
+ mapFactory.from(View.Map(this, f))
+
+ // Similar to iterableFactory, but for Map collection types
+ def mapFactory: MapFactory[CC]
+
+trait MapFactory[+CC[_, _]]:
+ def from[K, V](it: IterableOnce[(K, V)]): CC[K, V]
+~~~
+{% endtab %}
+{% endtabs %}
## When a strict evaluation is preferable (or unavoidable) ##
In the previous sections we explained that the “strictness” of concrete collections
-should be preserved by default operation implementations. However in some cases this
+should be preserved by default operation implementations. However, in some cases this
leads to less efficient implementations. For instance, `partition` has to perform
two traversals of the underlying collection. In some other case (e.g. `groupBy`) it
is simply not possible to implement the operation without evaluating the collection
@@ -361,6 +515,8 @@ For those cases, we also provide ways to implement operations in a strict mode.
The pattern is different: instead of being based on a `View`, it is based on a
`Builder`. Here is an outline of the `Builder` trait:
+{% tabs builders_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=builders_1 %}
~~~ scala
package scala.collection.mutable
@@ -369,6 +525,17 @@ trait Builder[-A, +C] {
def result(): C
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=builders_1 %}
+~~~ scala
+package scala.collection.mutable
+
+trait Builder[-A, +C]:
+ def addOne(elem: A): this.type
+ def result(): C
+~~~
+{% endtab %}
+{% endtabs %}
Builders are generic in both the element type `A` and the type of collection they
return, `C`.
@@ -381,6 +548,8 @@ to get a builder resulting in a collection of the same type but with a different
type of elements. The following code shows the relevant parts of `IterableOps` and
`IterableFactory` to build collections in both strict and non-strict modes:
+{% tabs builders_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=builders_2 %}
~~~ scala
trait IterableOps[+A, +CC[_], +C] {
def iterableFactory: IterableFactory[CC]
@@ -393,8 +562,22 @@ trait IterableFactory[+CC[_]] {
def newBuilder[A]: Builder[A, CC[A]]
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=builders_2 %}
+~~~ scala
+trait IterableOps[+A, +CC[_], +C]:
+ def iterableFactory: IterableFactory[CC]
+ protected def fromSpecific(coll: IterableOnce[A]): C
+ protected def newSpecificBuilder: Builder[A, C]
+
+trait IterableFactory[+CC[_]]:
+ def from[A](source: IterableOnce[A]): CC[A]
+ def newBuilder[A]: Builder[A, CC[A]]
+~~~
+{% endtab %}
+{% endtabs %}
-Note that, in general, an operation that doesn’t *have to* be strict should
+Note that, in general, an operation that doesn't *have to* be strict should
be implemented in a non-strict mode, otherwise it would lead to surprising
behaviour when used on a non-strict concrete collection (you can read more
about that statement in
diff --git a/_overviews/core/architecture-of-scala-collections.md b/_overviews/core/architecture-of-scala-collections.md
index 76bcde648f..74f2bd1b98 100644
--- a/_overviews/core/architecture-of-scala-collections.md
+++ b/_overviews/core/architecture-of-scala-collections.md
@@ -217,7 +217,7 @@ maps the key/value pair to an integer, namely its value component. In
that case, we cannot form a `Map` from the results, but we can still
form an `Iterable`, a supertrait of `Map`.
-You might ask, why not restrict `map` so that it can always return the
+You might ask why, not restrict `map` so that it can always return the
same kind of collection? For instance, on bit sets `map` could accept
only `Int`-to-`Int` functions and on `Map`s it could only accept
pair-to-pair functions. Not only are such restrictions undesirable
@@ -270,7 +270,7 @@ construct another `BitSet` provided the element type of the collection to build
is `Int`. If this is not the case, the compiler will check the superclasses, and
fall back to the implicit builder factory defined in
`mutable.Set`'s companion object. The type of this more general builder
-factory, where `A` is a generic type parameter, is:
+factory, where `A` is a type parameter, is:
CanBuildFrom[Set[_], A, Set[A]]
@@ -646,7 +646,7 @@ function, which is also the element type of the new collection. The
`That` appears as the result type of `map`, so it represents the type of
the new collection that gets created.
-How is the `That` type determined? In fact it is linked to the other
+How is the `That` type determined? In fact, it is linked to the other
types by an implicit parameter `cbf`, of type `CanBuildFrom[Repr, B, That]`.
These `CanBuildFrom` implicits are defined by the individual
collection classes. Recall that an implicit value of type
@@ -747,7 +747,7 @@ ignoring its argument.
That is it. The final [`RNA` class](#final-version-of-rna-strands-class)
implements all collection methods at
-their expected types. Its implementation requires a little bit of
+their expected types. Its implementation requires a little of
protocol. In essence, you need to know where to put the `newBuilder`
factories and the `canBuildFrom` implicits. On the plus side, with
relatively little code you get a large number of methods automatically
@@ -789,7 +789,7 @@ storing the strings "abc", "abd", "al", "all" and "xy" would look
like this:
A sample patricia trie:
-
+
To find the node corresponding to the string "abc" in this trie,
simply follow the subtree labeled "a", proceed from there to the
@@ -979,14 +979,14 @@ provided by the `empty` method, which is the last method defined in
}
}
-We'll now turn to the companion object `PrefixMap`. In fact it is not
+We'll now turn to the companion object `PrefixMap`. In fact, it is not
strictly necessary to define this companion object, as class `PrefixMap`
can stand well on its own. The main purpose of object `PrefixMap` is to
define some convenience factory methods. It also defines a
`CanBuildFrom` implicit to make typing work out better.
The two convenience methods are `empty` and `apply`. The same methods are
-present for all other collections in Scala's collection framework so
+present for all other collections in Scala's collection framework, so
it makes sense to define them here, too. With the two methods, you can
write `PrefixMap` literals like you do for any other collection:
diff --git a/_overviews/core/binary-compatibility-of-scala-releases.md b/_overviews/core/binary-compatibility-of-scala-releases.md
index cadac052e8..f72d3979fd 100644
--- a/_overviews/core/binary-compatibility-of-scala-releases.md
+++ b/_overviews/core/binary-compatibility-of-scala-releases.md
@@ -7,31 +7,80 @@ partof: binary-compatibility
permalink: /overviews/core/:title.html
---
-When two versions of Scala are binary compatible, it is safe to compile your project on one Scala version and link against another Scala version at run time. Safe run-time linkage (only!) means that the JVM does not throw a (subclass of) [`LinkageError`](https://docs.oracle.com/javase/7/docs/api/java/lang/LinkageError.html) when executing your program in the mixed scenario, assuming that none arise when compiling and running on the same version of Scala. Concretely, this means you may have external dependencies on your run-time classpath that use a different version of Scala than the one you're compiling with, as long as they're binary compatible. In other words, separate compilation on different binary compatible versions does not introduce problems compared to compiling and running everything on the same version of Scala.
+When two versions of Scala are binary compatible, it is safe to compile your project on one Scala version and link against another Scala version at run time. Safe run-time linkage (only!) means that the JVM does not throw a (subclass of) [`LinkageError`](https://docs.oracle.com/javase/8/docs/api/java/lang/LinkageError.html) when executing your program in the mixed scenario, assuming that none arise when compiling and running on the same version of Scala. Concretely, this means you may have external dependencies on your run-time classpath that use a different version of Scala than the one you're compiling with, as long as they're binary compatible. In other words, separate compilation on different binary compatible versions does not introduce problems compared to compiling and running everything on the same version of Scala.
-We check binary compatibility automatically with [MiMa](https://github.com/lightbend/migration-manager). We strive to maintain a similar invariant for the `behavior` (as opposed to just linkage) of the standard library, but this is not checked mechanically (Scala is not a proof assistant so this is out of reach for its type system).
+We check binary compatibility automatically with [MiMa](https://github.com/lightbend/mima). We strive to maintain a similar invariant for the `behavior` (as opposed to just linkage) of the standard library, but this is not checked mechanically (Scala is not a proof assistant so this is out of reach for its type system).
+
+Note that for Scala.js and Scala Native, binary compatibility issues result in errors at build time, as opposed to run-time exceptions.
+They happen during their respective "linking" phases: `{fast,full}LinkJS` for Scala.js and `nativeLink` for Scala Native.
#### Forward and Back
-We distinguish forward and backward compatibility (think of these as properties of a sequence of versions, not of an individual version). Maintaining backwards compatibility means code compiled on an older version will link with code compiled with newer ones. Forward compatibility allows you to compile on new versions and run on older ones.
+We distinguish forward and backward compatibility (think of these as properties of a sequence of versions, not of an individual version). Maintaining backward compatibility means code compiled on an older version will link with code compiled with newer ones. Forward compatibility allows you to compile on new versions and run on older ones.
+
+Thus, backward compatibility precludes the removal of (non-private) methods, as older versions could call them, not knowing they would be removed, whereas forward compatibility disallows adding new (non-private) methods, because newer programs may come to depend on them, which would prevent them from running on older versions (private methods are exempted here as well, as their definition and call sites must be in the same source file).
+
+#### Guarantees and Versioning
+For Scala 2, the *minor* version is the *third* number in a version, e.g., 16 in v2.13.16.
+The major version is the second number, which is 13 in our example.
+
+Scala 2 up to 2.13.16 guarantees both backward and forward compatibility across *minor* releases within a single major release.
+This is about to change now that [SIP-51 has been accepted](https://docs.scala-lang.org/sips/drop-stdlib-forwards-bin-compat.html), future Scala 2.13 releases may be backward compatible only.
+
+For Scala 3, the minor version is the *second* number in a version, e.g., 2 in v3.2.1.
+The third number is the *patch* version.
+The major version is always 3.
+
+Scala 3 guarantees both backward and forward compatibility across *patch* releases within a single minor release (enforcing forward binary compatibility is helpful to maintain source compatibility).
+In particular, this applies within an entire [Long-Term-Support (LTS) series](https://www.scala-lang.org/blog/2022/08/17/long-term-compatibility-plans.html) such as Scala 3.3.x.
+
+Scala 3 also guarantees *backward* compatibility across *minor* releases in the entire 3.x series, but not forward compatibility.
+This means that libraries compiled with any Scala 3.x version can be used in projects compiled with any Scala 3.y version with y >= x.
-Thus, backwards compatibility precludes the removal of (non-private) methods, as older versions could call them, not knowing they would be removed, whereas forwards compatibility disallows adding new (non-private) methods, because newer programs may come to depend on them, which would prevent them from running on older versions (private methods are exempted here as well, as their definition and call sites must be in the same compilation unit).
+In addition, Scala 3.x provides backward binary compatibility with respect to Scala 2.13.y.
+Libraries compiled with Scala 2.13.y can be used in projects using Scala 3.x.
+This policy does not apply to experimental Scala 2 features, which notably includes *macros*.
-These are strict constraints, but they have worked well for us since Scala 2.10.x. They didn't stop us from fixing large numbers of issues in minor releases. The advantages are clear, so we will maintain this policy for future Scala major releases.
+In general, none of those guarantees apply to *experimental* features and APIs.
-#### Meta
-Note that so far we've only talked about the jars generated by scalac for the standard library and reflection.
-Our policies do not extend to the meta-issue: ensuring binary compatibility for bytecode generated from identical sources, by different version of scalac? (The same problem exists for compiling on different JDKs.) While we strive to achieve this, it's not something we can test in general. Notable examples where we know meta-binary compatibility is hard to achieve: specialisation and the optimizer.
+#### Checking
+For the Scala library artifacts (`scala-library`, `scala-reflect` and `scala3-library`), these guarantees are mechanically checked with [MiMa](https://github.com/lightbend/mima).
-In short, we recommend that library authors use [MiMa](https://github.com/lightbend/migration-manager) to verify compatibility of minor versions before releasing.
-Compiling identical sources with different versions of the scala compiler (or on different JVM versions!) could result in binary incompatible bytecode. This is rare, and we try to avoid it, but we can't guarantee it will never happen.
+The *policies* above extend to libraries compiled by particular Scala compiler versions.
+Every effort is made to preserve the binary compatibility of artifacts produced by the compiler.
+*However*, that cannot be mechanically checked.
+It is therefore possible, due to bugs or unforeseen consequences, that recompiling a library with a different compiler version affects its binary API.
+We cannot *guarantee* that it will never happen.
+
+We recommend that library authors use [MiMa](https://github.com/lightbend/mima) themselves to verify compatibility of minor versions before releasing.
+
+#### TASTy and Pickle Compatibility
+*Binary* compatibility is a concept relevant at link time of the target platform (JVM, Scala.js or Scala Native).
+TASTy and Pickle compatibility are similar but apply at *compile* time for the Scala compiler.
+TASTy applies to Scala 3, Pickle to Scala 2.
+
+If a library was compiled with an older version of the compiler, we say that the library is backward TASTy/Pickle compatible if it can be used within an application compiled with a newer compiler version.
+Likewise, forward TASTy/Pickle compatibility goes in the other direction.
+
+The same policies as for binary compatibility apply to TASTy/Pickle compatibility, although they are not mechanically checked.
+
+Library authors may automatically check TASTy/Pickle backward compatibility for their libraries using [TASTy-MiMa](https://github.com/scalacenter/tasty-mima).
+Disclaimer: TASTy-MiMa is a young project.
+At this point, you are likely going to run into bugs.
+Please report issues you find to its issue tracker.
#### Concretely
-We guarantee forwards and backwards compatibility of the `"org.scala-lang" % "scala-library" % "2.N.x"` and `"org.scala-lang" % "scala-reflect" % "2.N.x"` artifacts, except for
-- the `scala.reflect.internal` and `scala.reflect.io` packages, as scala-reflect is still experimental, and
+We guarantee backward compatibility of the `"org.scala-lang" % "scala-library" % "2.N.x"` and `"org.scala-lang" % "scala-reflect" % "2.N.x"` artifacts, except for
+- the `scala.reflect.internal` and `scala.reflect.io` packages, as scala-reflect is experimental, and
- the `scala.runtime` package, which contains classes used by generated code at runtime.
We also strongly discourage relying on the stability of `scala.concurrent.impl`, `scala.sys.process.*Impl`, and `scala.reflect.runtime`, though we will only break compatibility for severe bugs here.
-Note that we will only enforce *backwards* binary compatibility for modules (artifacts under the groupId `org.scala-lang.modules`). As they are opt-in, it's less of a burden to require having the latest version on the classpath. (Without forward compatibility, the latest version of the artifact must be on the run-time classpath to avoid linkage errors.)
+We guarantee backward compatibility of the `"org.scala-lang" % "scala3-library_3" % "3.x.y"` artifact.
+Forward compatibility is only guaranteed for `3.N.y` within a given `N`.
+
+We enforce *backward* (but not forward) binary compatibility for *modules* (artifacts under the groupId `org.scala-lang.modules`). As they are opt-in, it's less of a burden to require having the latest version on the classpath. (Without forward compatibility, the latest version of the artifact must be on the run-time classpath to avoid linkage errors.)
-Finally, from Scala 2.11 until Scala 2.13.0-M1, `scala-library-all` aggregates all modules that constitute a Scala release. Note that this means it does not provide forward binary compatibility, whereas the core `scala-library` artifact does. We consider the versions of the modules that `"scala-library-all" % "2.N.x"` depends on to be the canonical ones, that are part of the official Scala distribution. (The distribution itself is defined by the `scala-dist` maven artifact.)
+#### Build Tools
+Build tools like sbt and mill have assumptions about backward binary compatibility built in.
+They build a graph of a project's dependencies and select the most recent versions that are needed.
+To learn more, see the page on [library dependencies](https://www.scala-sbt.org/1.x/docs/Library-Dependencies.html) in the sbt documentation.
diff --git a/_overviews/core/collections-migration-213.md b/_overviews/core/collections-migration-213.md
index 68c5247774..76cd202cd3 100644
--- a/_overviews/core/collections-migration-213.md
+++ b/_overviews/core/collections-migration-213.md
@@ -15,6 +15,8 @@ The most important changes in the Scala 2.13 collections library are:
- Transformation methods no longer have an implicit `CanBuildFrom` parameter. This makes the library easier to understand (in source code, Scaladoc, and IDE code completion). It also makes compiling user code more efficient.
- The type hierarchy is simplified. `Traversable` no longer exists, only `Iterable`.
- The `to[Collection]` method was replaced by the `to(Collection)` method.
+ - The `toC` methods are strict by convention and yield the default collection type where applicable. For example, `Iterator.continually(42).take(10).toSeq` produces a `List[Int]` and without the limit would not.
+ - `toIterable` is deprecated wherever defined. For `Iterator`, in particular, prefer `to(LazyList)`.
- Views have been vastly simplified and work reliably now. They no longer extend their corresponding collection type, for example, an `IndexedSeqView` no longer extends `IndexedSeq`.
- `collection.breakOut` no longer exists, use `.view` and `.to(Collection)` instead.
- Immutable hash sets and hash maps have a new implementation (`ChampHashSet` and `ChampHashMap`, based on the ["CHAMP" encoding](https://michael.steindorfer.name/publications/oopsla15.pdf)).
@@ -27,7 +29,7 @@ The most important changes in the Scala 2.13 collections library are:
## Tools for migrating and cross-building
-The [scala-collection-compat](https://github.com/scala/scala-collection-compat) is a library released for 2.11, 2.12 and 2.13 that provides some of the new APIs from Scala 2.13 for the older versions. This simplifies cross-building projects.
+The [scala-collection-compat](https://github.com/scala/scala-collection-compat) is a library released for 2.11, 2.12 and 2.13 that provides some new APIs from Scala 2.13 for the older versions. This simplifies cross-building projects.
The module also provides [migration rules](https://github.com/scala/scala-collection-compat#migration-tool) for [scalafix](https://scalacenter.github.io/scalafix/docs/users/installation.html) that can update a project's source code to work with the 2.13 collections library.
@@ -40,7 +42,7 @@ a method such as `orderFood(xs: _*)` the varargs parameter `xs` must be an immut
[SLS 6.6]: https://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#function-applications
-Therefore any method signature in Scala 2.13 which includes `scala.Seq`, varargs, or `scala.IndexedSeq` is going
+Therefore, any method signature in Scala 2.13 which includes `scala.Seq`, varargs, or `scala.IndexedSeq` is going
to have a breaking change in API semantics (as the immutable sequence types require more — immutability — than the
not-immutable types). For example, users of a method like `def orderFood(order: Seq[Order]): Seq[Food]` would
previously have been able to pass in an `ArrayBuffer` of `Order`, but cannot in 2.13.
@@ -66,7 +68,7 @@ We recommend using `import scala.collection`/`import scala.collection.immutable`
`collection.Seq`/`immutable.Seq`.
We recommend against using `import scala.collection.Seq`, which shadows the automatically imported `scala.Seq`,
-because even if it's a oneline change it causes name confusion. For code generation or macros the safest option
+because even if it's a one-line change it causes name confusion. For code generation or macros the safest option
is using the fully-qualified `_root_.scala.collection.Seq`.
As an example, the migration would look something like this:
@@ -79,7 +81,7 @@ object FoodToGo {
}
~~~
-However users of this code in Scala 2.13 would also have to migrate, as the result type is source-incompatible
+However, users of this code in Scala 2.13 would also have to migrate, as the result type is source-incompatible
with any `scala.Seq` (or just `Seq`) usage in their code:
~~~ scala
@@ -231,7 +233,7 @@ Other notable changes are:
You can make this conversion explicit by writing `f _` or `f(_)` instead of `f`.
scala> Map(1 -> "a").map(f _)
res10: scala.collection.immutable.Map[Int,String] = ChampHashMap(2 -> a)
- - `View`s have been completely redesigned and we expect their usage to have a more predictable evaluation model.
+ - `View`s have been completely redesigned, and we expect their usage to have a more predictable evaluation model.
You can read more about the new design [here](https://scala-lang.org/blog/2017/11/28/view-based-collections.html).
- `mutable.ArraySeq` (which wraps an `Array[AnyRef]` in 2.12, meaning that primitives were boxed in the array) can now wrap boxed and unboxed arrays. `mutable.ArraySeq` in 2.13 is in fact equivalent to `WrappedArray` in 2.12, there are specialized subclasses for primitive arrays. Note that a `mutable.ArraySeq` can be used either way for primitive arrays (TODO: document how). `WrappedArray` is deprecated.
- There is no "default" `Factory` (previously known as `[A, C] => CanBuildFrom[Nothing, A, C]`): use `Factory[A, Vector[A]]` explicitly instead.
diff --git a/_overviews/core/custom-collection-operations.md b/_overviews/core/custom-collection-operations.md
index 87b2f863ae..f6d4f08d34 100644
--- a/_overviews/core/custom-collection-operations.md
+++ b/_overviews/core/custom-collection-operations.md
@@ -29,6 +29,8 @@ as parameter, or an `Iterable[A]` if you need more than one traversal.
For instance, say we want to implement a `sumBy` operation that sums the elements of a
collection after they have been transformed by a function:
+{% tabs sumBy_1 %}
+{% tab 'Scala 2 and 3' for=sumBy_1 %}
~~~ scala
case class User(name: String, age: Int)
@@ -36,10 +38,14 @@ val users = Seq(User("Alice", 22), User("Bob", 20))
println(users.sumBy(_.age)) // “42”
~~~
+{% endtab %}
+{% endtabs %}
+
+{% tabs sumBy_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=sumBy_2 %}
We can define the `sumBy` operation as an extension method, using an
[implicit class](/overviews/core/implicit-classes.html), so that it can be called like a method:
-
~~~ scala
import scala.collection.IterableOnce
@@ -54,15 +60,35 @@ implicit class SumByOperation[A](coll: IterableOnce[A]) {
}
}
~~~
-
Unfortunately, this extension method does not work with values of type `String` and not
even with `Array`. This is because these types are not part of the Scala collections
hierarchy. They can be converted to proper collection types, though, but the extension method
will not work directly on `String` and `Array` because that would require applying two implicit
conversions in a row.
+{% endtab %}
+{% tab 'Scala 3' for=sumBy_2 %}
+
+We can define the `sumBy` operation as an extension method so that it can be called like a method:
+~~~ scala
+import scala.collection.IterableOnce
+
+extension [A](coll: IterableOnce[A])
+ def sumBy[B: Numeric](f: A => B): B =
+ val it = coll.iterator
+ var result = f(it.next())
+ while it.hasNext do
+ result = summon[Numeric[B]].plus(result, f(it.next()))
+ result
+~~~
+{% endtab %}
+{% endtabs %}
+
### Consuming any type that is *like* a collection
+{% tabs sumBy_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=sumBy_3 %}
+
If we want the `sumBy` to work on any type that is *like* a collection, such as `String`
and `Array`, we have to add another indirection level:
@@ -81,11 +107,34 @@ The type `IsIterable[Repr]` has implicit instances for all types `Repr` that can
to `IterableOps[A, Iterable, C]` (for some element type `A` and some collection type `C`). There are
instances for actual collection types and also for `String` and `Array`.
+{% endtab %}
+{% tab 'Scala 3' for=sumBy_3 %}
+
+We expect the `sumBy` to work on any type that is *like* a collection, such as `String`
+and `Array`. Fortunately, the type `IsIterable[Repr]` has implicit instances for all types `Repr` that can be converted
+to `IterableOps[A, Iterable, C]` (for some element type `A` and some collection type `C`) and there are
+instances for actual collection types and also for `String` and `Array`.
+
+~~~ scala
+import scala.collection.generic.IsIterable
+
+extension [Repr](repr: Repr)(using iter: IsIterable[Repr])
+ def sumBy[B: Numeric](f: iter.A => B): B =
+ val coll = iter(repr)
+ ... // same as before
+~~~
+
+{% endtab %}
+{% endtabs %}
+
### Consuming a more specific collection than `Iterable`
In some cases we want (or need) the receiver of the operation to be more specific than `Iterable`.
For instance, some operations make sense only on `Seq` but not on `Set`.
+{% tabs sumBy_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=sumBy_4 %}
+
In such a case, again, the most straightforward solution would be to take as parameter a `Seq` instead
of an `Iterable` or an `IterableOnce`, but this would work only with *actual* `Seq` values. If you want
to support `String` and `Array` values you have to use `IsSeq` instead. `IsSeq` is similar to
@@ -95,6 +144,20 @@ Using `IsSeq` is also required to make your operation work on `SeqView` values,
does not extend `Seq`. Similarly, there is an `IsMap` type that makes operations work with
both `Map` and `MapView` values.
+{% endtab %}
+{% tab 'Scala 3' for=sumBy_4 %}
+
+In such a case, again, the most straightforward solution would be to take as parameter a `Seq` instead
+of an `Iterable` or an `IterableOnce`. Similarly to `IsIterable`, `IsSeq` provides a
+conversion to `SeqOps[A, Iterable, C]` (for some types `A` and `C`).
+
+`IsSeq` also make your operation works on `SeqView` values, because `SeqView`
+does not extend `Seq`. Similarly, there is an `IsMap` type that makes operations work with
+both `Map` and `MapView` values.
+
+{% endtab %}
+{% endtabs %}
+
## Producing any collection
This situation happens when a library provides an operation that produces a collection while leaving the
@@ -105,6 +168,8 @@ Such a type class is typically used to create arbitrary test data.
Our goal is to define a `collection` operation that generates arbitrary collections containing arbitrary
values. Here is an example of use of `collection`:
+{% tabs Gen_1 %}
+{% tab 'Scala 2 and 3' for=Gen_1 %}
~~~
scala> collection[List, Int].get
res0: List[Int] = List(606179450, -1479909815, 2107368132, 332900044, 1833159330, -406467525, 646515139, -575698977, -784473478, -1663770602)
@@ -115,19 +180,34 @@ res1: LazyList[Boolean] = LazyList(_, ?)
scala> collection[Set, Int].get
res2: Set[Int] = HashSet(-1775377531, -1376640531, -1009522404, 526943297, 1431886606, -1486861391)
~~~
+{% endtab %}
+{% endtabs %}
A very basic definition of `Gen[A]` could be the following:
-```tut
+{% tabs Gen_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=Gen_2 %}
+```scala mdoc
trait Gen[A] {
/** Get a generated value of type `A` */
def get: A
}
```
+{% endtab %}
+{% tab 'Scala 3' for=Gen_2 %}
+```scala
+trait Gen[A]:
+ /** Get a generated value of type `A` */
+ def get: A
+```
+{% endtab %}
+{% endtabs %}
And the following instances can be defined:
-```tut
+{% tabs Gen_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=Gen_3 %}
+```scala mdoc
import scala.util.Random
object Gen {
@@ -150,6 +230,29 @@ object Gen {
}
```
+{% endtab %}
+{% tab 'Scala 3' for=Gen_3 %}
+```scala
+import scala.util.Random
+
+object Gen:
+
+ /** Generator of `Int` values */
+ given Gen[Int] with
+ def get: Int = Random.nextInt()
+
+ /** Generator of `Boolean` values */
+ given Gen[Boolean] with
+ def get: Boolean = Random.nextBoolean()
+
+ /** Given a generator of `A` values, provides a generator of `List[A]` values */
+ given[A: Gen]: Gen[List[A]] with
+ def get: List[A] =
+ if Random.nextInt(100) < 10 then Nil
+ else summon[Gen[A]].get :: get
+```
+{% endtab %}
+{% endtabs %}
The last definition (`list`) generates a value of type `List[A]` given a generator
of values of type `A`. We could implement a generator of `Vector[A]` or `Set[A]` as
@@ -160,6 +263,8 @@ can decide which collection type they want to produce.
To achieve that we have to use `scala.collection.Factory`:
+{% tabs Gen_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=Gen_4 %}
~~~ scala
trait Factory[-A, +C] {
@@ -177,6 +282,27 @@ trait Factory[-A, +C] {
def newBuilder: Builder[A, C]
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=Gen_4 %}
+~~~ scala
+trait Factory[-A, +C]:
+
+ /** @return A collection of type `C` containing the same elements
+ * as the source collection `it`.
+ * @param it Source collection
+ */
+ def fromSpecific(it: IterableOnce[A]): C
+
+ /** Get a Builder for the collection. For non-strict collection
+ * types this will use an intermediate buffer.
+ * Building collections with `fromSpecific` is preferred
+ * because it can be lazy for lazy collections.
+ */
+ def newBuilder: Builder[A, C]
+end Factory
+~~~
+{% endtab %}
+{% endtabs %}
The `Factory[A, C]` trait provides two ways of building a collection `C` from
elements of type `A`:
@@ -193,6 +319,8 @@ In practice, it is recommended to [not eagerly evaluate the elements of the coll
Finally, here is how we can implement a generator of arbitrary collection types:
+{% tabs Gen_5 class=tabs-scala-version %}
+{% tab 'Scala 2' for=Gen_5 %}
~~~ scala
import scala.collection.Factory
@@ -211,6 +339,22 @@ implicit def collection[CC[_], A](implicit
}
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=Gen_5 %}
+~~~ scala
+import scala.collection.Factory
+
+given[CC[_], A: Gen](using Factory[A, CC[A]]): Gen[CC[A]] with
+ def get: CC[A] =
+ val lazyElements =
+ LazyList.unfold(()) { _ =>
+ if Random.nextInt(100) < 10 then None
+ else Some((summon[Gen[A]].get, ()))
+ }
+ summon[Factory[A, CC[A]]].fromSpecific(lazyElements)
+~~~
+{% endtab %}
+{% endtabs %}
The implementation uses a lazy source collection of a random size (`lazyElements`).
Then it calls the `fromSpecific` method of the `Factory` to build the collection
@@ -225,10 +369,14 @@ For instance, we want to implement an `intersperse` operation that can be applie
any sequence and returns a sequence with a new element inserted between each element of the
source sequence:
+{% tabs intersperse_1 %}
+{% tab 'Scala 2 and 3' for=intersperse_1 %}
~~~ scala
List(1, 2, 3).intersperse(0) == List(1, 0, 2, 0, 3)
"foo".intersperse(' ') == "f o o"
~~~
+{% endtab %}
+{% endtabs %}
When we call it on a `List`, we want to get back another `List`, and when we call it on
a `String` we want to get back another `String`, and so on.
@@ -236,12 +384,15 @@ a `String` we want to get back another `String`, and so on.
Building on what we’ve learned from the previous sections, we can start defining an extension method
using `IsSeq` and producing a collection by using an implicit `Factory`:
+{% tabs intersperse_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=intersperse_2 %}
~~~ scala
-import scala.collection.{ AbstractIterator, AbstractView, Factory, SeqOps }
+import scala.collection.{ AbstractIterator, AbstractView, Factory }
import scala.collection.generic.IsSeq
-class IntersperseOperation[A](seqOps: SeqOps[A, Iterable, _]) {
- def intersperse[B >: A, That](sep: B)(implicit factory: Factory[B, That]): That =
+class IntersperseOperation[Repr](coll: Repr, seq: IsSeq[Repr]) {
+ def intersperse[B >: seq.A, That](sep: B)(implicit factory: Factory[B, That]): That = {
+ val seqOps = seq(coll)
factory.fromSpecific(new AbstractView[B] {
def iterator = new AbstractIterator[B] {
val it = seqOps.iterator
@@ -254,18 +405,45 @@ class IntersperseOperation[A](seqOps: SeqOps[A, Iterable, _]) {
}
}
})
+ }
}
-implicit def IntersperseOperation[Repr](coll: Repr)(implicit seq: IsSeq[Repr]): IntersperseOperation[seq.A] =
- new IntersperseOperation(seq(coll))
+implicit def IntersperseOperation[Repr](coll: Repr)(implicit seq: IsSeq[Repr]): IntersperseOperation[Repr] =
+ new IntersperseOperation(coll, seq)
+~~~
+{% endtab %}
+{% tab 'Scala 3' for=intersperse_2 %}
+~~~ scala
+import scala.collection.{ AbstractIterator, AbstractView, Factory }
+import scala.collection.generic.IsSeq
+
+extension [Repr](coll: Repr)(using seq: IsSeq[Repr])
+ def intersperse[B >: seq.A, That](sep: B)(using factory: Factory[B, That]): That =
+ val seqOps = seq(coll)
+ factory.fromSpecific(new AbstractView[B]:
+ def iterator = new AbstractIterator[B]:
+ val it = seqOps.iterator
+ var intersperseNext = false
+ def hasNext = intersperseNext || it.hasNext
+ def next() =
+ val elem = if intersperseNext then sep else it.next()
+ intersperseNext = !intersperseNext && it.hasNext
+ elem
+ )
~~~
+{% endtab %}
+{% endtabs %}
However, if we try it we get the following behaviour:
+{% tabs intersperse_3 %}
+{% tab 'Scala 2 and 3' for=intersperse_3 %}
~~~
scala> List(1, 2, 3).intersperse(0)
res0: Array[Int] = Array(1, 0, 2, 0, 3)
~~~
+{% endtab %}
+{% endtabs %}
We get back an `Array` although the source collection was a `List`! Indeed, there is
nothing that constrains the result type of `intersperse` to depend on the receiver type.
@@ -274,6 +452,8 @@ To produce a collection whose type depends on a source collection, we have to us
`scala.collection.BuildFrom` (formerly known as `CanBuildFrom`) instead of `Factory`.
`BuildFrom` is defined as follows:
+{% tabs intersperse_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=intersperse_4 %}
~~~ scala
trait BuildFrom[-From, -A, +C] {
/** @return a collection of type `C` containing the same elements
@@ -287,11 +467,29 @@ trait BuildFrom[-From, -A, +C] {
def newBuilder(from: From): Builder[A, C]
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=intersperse_4 %}
+~~~ scala
+trait BuildFrom[-From, -A, +C]:
+ /** @return a collection of type `C` containing the same elements
+ * (of type `A`) as the source collection `it`.
+ */
+ def fromSpecific(from: From)(it: IterableOnce[A]): C
+
+ /** @return a Builder for the collection type `C`, containing
+ * elements of type `A`.
+ */
+ def newBuilder(from: From): Builder[A, C]
+~~~
+{% endtab %}
+{% endtabs %}
`BuildFrom` has similar operations to `Factory`, but they take an additional `from`
parameter. Before explaining how implicit instances of `BuildFrom` are resolved, let’s first have
a look at how you can use it. Here is the implementation of `intersperse` based on `BuildFrom`:
+{% tabs intersperse_5 class=tabs-scala-version %}
+{% tab 'Scala 2' for=intersperse_5 %}
~~~ scala
import scala.collection.{ AbstractView, BuildFrom }
import scala.collection.generic.IsSeq
@@ -308,13 +506,32 @@ class IntersperseOperation[Repr, S <: IsSeq[Repr]](coll: Repr, seq: S) {
implicit def IntersperseOperation[Repr](coll: Repr)(implicit seq: IsSeq[Repr]): IntersperseOperation[Repr, seq.type] =
new IntersperseOperation(coll, seq)
~~~
+{% endtab %}
+{% tab 'Scala 3' for=intersperse_5 %}
+~~~ scala
+import scala.collection.{ AbstractIterator, AbstractView, BuildFrom }
+import scala.collection.generic.IsSeq
+
+extension [Repr](coll: Repr)(using seq: IsSeq[Repr])
+ def intersperse[B >: seq.A, That](sep: B)(using bf: BuildFrom[Repr, B, That]): That =
+ val seqOps = seq(coll)
+ bf.fromSpecific(coll)(new AbstractView[B]:
+ // same as before
+ )
+~~~
+{% endtab %}
+{% endtabs %}
Note that we track the type of the receiver collection `Repr` in the `IntersperseOperation`
class. Now, consider what happens when we write the following expression:
+{% tabs intersperse_6 %}
+{% tab 'Scala 2 and 3' for=intersperse_6 %}
~~~ scala
List(1, 2, 3).intersperse(0)
~~~
+{% endtab %}
+{% endtabs %}
An implicit parameter of type `BuildFrom[Repr, B, That]` has to be resolved by the compiler.
The type `Repr` is constrained by the receiver type (here, `List[Int]`) and the type `B` is
@@ -329,5 +546,5 @@ be `List[Int]`.
as parameter,
- To also support `String`, `Array` and `View`, use `IsIterable`,
- To produce a collection given its type, use a `Factory`,
-- To produce a collection based on the type of a source collection and the type of elements of the collection
- to produce, use `BuildFrom`.
\ No newline at end of file
+- To produce a collection based on the type of source collection and the type of elements of the collection
+ to produce, use `BuildFrom`.
diff --git a/_overviews/core/custom-collections.md b/_overviews/core/custom-collections.md
index 6720bcf5de..6164ec3af2 100644
--- a/_overviews/core/custom-collections.md
+++ b/_overviews/core/custom-collections.md
@@ -27,15 +27,21 @@ to choose `Seq` because our collection can contain duplicates and
iteration order is determined by insertion order. However, some
[properties of `Seq`](/overviews/collections/seqs.html) are not satisfied:
+{% tabs notCapped_1 %}
+{% tab 'Scala 2 and 3' for=notCapped_1 %}
~~~ scala
(xs ++ ys).size == xs.size + ys.size
~~~
+{% endtab %}
+{% endtabs %}
Consequently, the only sensible choice as a base collection type
is `collection.immutable.Iterable`.
### First version of `Capped` class ###
+{% tabs capped1_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=capped1_1 %}
~~~ scala
import scala.collection._
@@ -72,11 +78,54 @@ class Capped1[A] private (val capacity: Int, val length: Int, offset: Int, elems
elem
}
}
-
+
override def className = "Capped1"
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=capped1_1 %}
+~~~scala
+import scala.collection.*
+
+class Capped1[A] private (val capacity: Int, val length: Int, offset: Int, elems: Array[Any])
+ extends immutable.Iterable[A]:
+ self =>
+
+ def this(capacity: Int) =
+ this(capacity, length = 0, offset = 0, elems = Array.ofDim(capacity))
+
+ def appended[B >: A](elem: B): Capped1[B] =
+ val newElems = Array.ofDim[Any](capacity)
+ Array.copy(elems, 0, newElems, 0, capacity)
+ val (newOffset, newLength) =
+ if length == capacity then
+ newElems(offset) = elem
+ ((offset + 1) % capacity, length)
+ else
+ newElems(length) = elem
+ (offset, length + 1)
+ Capped1[B](capacity, newLength, newOffset, newElems)
+ end appended
+
+ inline def :+ [B >: A](elem: B): Capped1[B] = appended(elem)
+
+ def apply(i: Int): A = elems((i + offset) % capacity).asInstanceOf[A]
+
+ def iterator: Iterator[A] = new AbstractIterator[A]:
+ private var current = 0
+ def hasNext = current < self.length
+ def next(): A =
+ val elem = self(current)
+ current += 1
+ elem
+ end iterator
+
+ override def className = "Capped1"
+end Capped1
+~~~
+{% endtab %}
+{% endtabs %}
The above listing presents the first version of our capped collection
implementation. It will be refined later. The class `Capped1` has a
@@ -100,33 +149,37 @@ the `offset`.
These two methods, `appended` and `apply`, implement the specific
behavior of the `Capped1` collection type. In addition to them, we have
to implement `iterator` to make the generic collection operations
-(such as `foldLeft`, `count`, etc.) work on `Capped` collections.
+(such as `foldLeft`, `count`, etc.) work on `Capped1` collections.
Here we implement it by using indexed access.
Last, we override `className` to return the name of the collection,
-“Capped1”. This name is used by the `toString` operation.
+`“Capped1”`. This name is used by the `toString` operation.
Here are some interactions with the `Capped1` collection:
+{% tabs capped1_2 %}
+{% tab 'Scala 2 and 3' for=capped1_2 %}
~~~ scala
-scala> new Capped1(capacity = 4)
-res0: Capped1[Nothing] = Capped1()
+scala> val c0 = new Capped1(capacity = 4)
+val c0: Capped1[Nothing] = Capped1()
-scala> res0 :+ 1 :+ 2 :+ 3
-res1: Capped1[Int] = Capped1(1, 2, 3)
+scala> val c1 = c0 :+ 1 :+ 2 :+ 3
+val c1: Capped1[Int] = Capped1(1, 2, 3)
-scala> res1.length
-res2: Int = 3
+scala> c1.length
+val res2: Int = 3
-scala> res1.lastOption
-res3: Option[Int] = Some(3)
+scala> c1.lastOption
+val res3: Option[Int] = Some(3)
-scala> res1 :+ 4 :+ 5 :+ 6
-res4: Capped1[Int] = Capped1(3, 4, 5, 6)
+scala> val c2 = c1 :+ 4 :+ 5 :+ 6
+val c2: Capped1[Int] = Capped1(3, 4, 5, 6)
-scala> res4.take(3)
-res5: collection.immutable.Iterable[Int] = List(3, 4, 5)
+scala> val c3 = c2.take(3)
+val c3: collection.immutable.Iterable[Int] = List(3, 4, 5)
~~~
+{% endtab %}
+{% endtabs %}
You can see that if we try to grow the collection with more than four
elements, the first elements are dropped (see `res4`). The operations
@@ -144,7 +197,13 @@ question should be what needs to be done to change them? One way to do
this would be to override the `take` method in class `Capped1`, maybe like
this:
- def take(count: Int): Capped1 = …
+{% tabs take_signature %}
+{% tab 'Scala 2 and 3' for=take_signature %}
+```scala
+def take(count: Int): Capped1 = …
+```
+{% endtab %}
+{% endtabs %}
This would do the job for `take`. But what about `drop`, or `filter`, or
`init`? In fact there are over fifty methods on collections that return
@@ -155,6 +214,8 @@ effect, as shown in the next section.
### Second version of `Capped` class ###
+{% tabs capped2_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=capped2_1 %}
~~~ scala
import scala.collection._
@@ -191,6 +252,44 @@ class Capped2Factory(capacity: Int) extends IterableFactory[Capped2] {
}
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=capped2_1 %}
+~~~ scala
+class Capped2[A] private(val capacity: Int, val length: Int, offset: Int, elems: Array[Any])
+ extends immutable.Iterable[A],
+ IterableOps[A, Capped2, Capped2[A]]:
+ self =>
+
+ def this(capacity: Int) = // as before
+
+ def appended[B >: A](elem: B): Capped2[B] = // as before
+ inline def :+[B >: A](elem: B): Capped2[B] = // as before
+ def apply(i: Int): A = // as before
+
+ def iterator: Iterator[A] = // as before
+
+ override def className = "Capped2"
+ override val iterableFactory: IterableFactory[Capped2] = Capped2Factory(capacity)
+ override protected def fromSpecific(coll: IterableOnce[A]): Capped2[A] = iterableFactory.from(coll)
+ override protected def newSpecificBuilder: mutable.Builder[A, Capped2[A]] = iterableFactory.newBuilder
+ override def empty: Capped2[A] = iterableFactory.empty
+end Capped2
+
+class Capped2Factory(capacity: Int) extends IterableFactory[Capped2]:
+
+ def from[A](source: IterableOnce[A]): Capped2[A] =
+ (newBuilder[A] ++= source).result()
+
+ def empty[A]: Capped2[A] = Capped2[A](capacity)
+
+ def newBuilder[A]: mutable.Builder[A, Capped2[A]] =
+ new mutable.ImmutableBuilder[A, Capped2[A]](empty):
+ def addOne(elem: A): this.type =
+ elems = elems :+ elem; this
+end Capped2Factory
+~~~
+{% endtab %}
+{% endtabs %}
The Capped class needs to inherit not only from `Iterable`, but also
from its implementation trait `IterableOps`. This is shown in the
@@ -229,31 +328,35 @@ With the refined implementation of the [`Capped2` class](#second-version-of-capp
the transformation operations work now as expected, and the
`Capped2Factory` class provides seamless conversions from other collections:
+{% tabs capped2_2 %}
+{% tab 'Scala 2 and 3' for=capped2_2 %}
~~~ scala
scala> object Capped extends Capped2Factory(capacity = 4)
defined object Capped
scala> Capped(1, 2, 3)
-res0: Capped2[Int] = Capped2(1, 2, 3)
+val res0: Capped2[Int] = Capped2(1, 2, 3)
scala> res0.take(2)
-res1: Capped2[Int] = Capped2(1, 2)
+val res1: Capped2[Int] = Capped2(1, 2)
scala> res0.filter(x => x % 2 == 1)
-res2: Capped2[Int] = Capped2(1, 3)
+val res2: Capped2[Int] = Capped2(1, 3)
scala> res0.map(x => x * x)
-res3: Capped2[Int] = Capped2(1, 4, 9)
+val res3: Capped2[Int] = Capped2(1, 4, 9)
scala> List(1, 2, 3, 4, 5).to(Capped)
-res4: Capped2[Int] = Capped2(2, 3, 4, 5)
+val res4: Capped2[Int] = Capped2(2, 3, 4, 5)
~~~
+{% endtab %}
+{% endtabs %}
This implementation now behaves correctly, but we can still improve
a few things:
- since our collection is strict, we can take advantage
- of the better performance offered by
+ of the better performance offered by
strict implementations of transformation operations,
- since our `fromSpecific`, `newSpecificBuilder` and `empty`
operation just forward to the `iterableFactory` member,
@@ -262,6 +365,8 @@ a few things:
### Final version of `Capped` class ###
+{% tabs capped_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=capped_1 %}
~~~ scala
import scala.collection._
@@ -324,6 +429,69 @@ class CappedFactory(capacity: Int) extends IterableFactory[Capped] {
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=capped_1 %}
+~~~ scala
+import scala.collection.*
+
+final class Capped[A] private (val capacity: Int, val length: Int, offset: Int, elems: Array[Any])
+ extends immutable.Iterable[A],
+ IterableOps[A, Capped, Capped[A]],
+ IterableFactoryDefaults[A, Capped],
+ StrictOptimizedIterableOps[A, Capped, Capped[A]]:
+ self =>
+
+ def this(capacity: Int) =
+ this(capacity, length = 0, offset = 0, elems = Array.ofDim(capacity))
+
+ def appended[B >: A](elem: B): Capped[B] =
+ val newElems = Array.ofDim[Any](capacity)
+ Array.copy(elems, 0, newElems, 0, capacity)
+ val (newOffset, newLength) =
+ if length == capacity then
+ newElems(offset) = elem
+ ((offset + 1) % capacity, length)
+ else
+ newElems(length) = elem
+ (offset, length + 1)
+ Capped[B](capacity, newLength, newOffset, newElems)
+ end appended
+
+ inline def :+ [B >: A](elem: B): Capped[B] = appended(elem)
+
+ def apply(i: Int): A = elems((i + offset) % capacity).asInstanceOf[A]
+
+ def iterator: Iterator[A] = view.iterator
+
+ override def view: IndexedSeqView[A] = new IndexedSeqView[A]:
+ def length: Int = self.length
+ def apply(i: Int): A = self(i)
+
+ override def knownSize: Int = length
+
+ override def className = "Capped"
+
+ override val iterableFactory: IterableFactory[Capped] = new CappedFactory(capacity)
+
+end Capped
+
+class CappedFactory(capacity: Int) extends IterableFactory[Capped]:
+
+ def from[A](source: IterableOnce[A]): Capped[A] =
+ source match
+ case capped: Capped[?] if capped.capacity == capacity => capped.asInstanceOf[Capped[A]]
+ case _ => (newBuilder[A] ++= source).result()
+
+ def empty[A]: Capped[A] = Capped[A](capacity)
+
+ def newBuilder[A]: mutable.Builder[A, Capped[A]] =
+ new mutable.ImmutableBuilder[A, Capped[A]](empty):
+ def addOne(elem: A): this.type = { elems = elems :+ elem; this }
+
+end CappedFactory
+~~~
+{% endtab %}
+{% endtabs %}
That is it. The final [`Capped` class](#final-version-of-capped-class):
@@ -345,33 +513,58 @@ methods (such as `iterator` in our case), if any.
## RNA sequences ##
-To start with the second example, we define the four RNA Bases:
-
- abstract class Base
- case object A extends Base
- case object U extends Base
- case object G extends Base
- case object C extends Base
+To start with the second example, say you want to create a new immutable sequence type for RNA strands.
+These are sequences of bases A (adenine), U (uracil), G (guanine), and C
+(cytosine). The definitions for bases are set up as shown in the
+listing of RNA bases below:
- object Base {
- val fromInt: Int => Base = Array(A, U, G, C)
- val toInt: Base => Int = Map(A -> 0, U -> 1, G -> 2, C -> 3)
- }
-
-Say you want to create a new immutable sequence type for RNA strands, which are
-sequences of bases A (adenine), U (uracil), G (guanine), and C
-(cytosine). The definitions for bases are easily set up as shown in the
-listing of RNA bases above.
+{% tabs Base_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=Base_1 %}
+~~~ scala
+abstract class Base
+case object A extends Base
+case object U extends Base
+case object G extends Base
+case object C extends Base
+
+object Base {
+ val fromInt: Int => Base = Array(A, U, G, C)
+ val toInt: Base => Int = Map(A -> 0, U -> 1, G -> 2, C -> 3)
+}
+~~~
Every base is defined as a case object that inherits from a common
abstract class `Base`. The `Base` class has a companion object that
defines two functions that map between bases and the integers 0 to 3.
-You can see in the examples two different ways to use collections
+
+You can see in the above example two different ways to use collections
to implement these functions. The `toInt` function is implemented as a
`Map` from `Base` values to integers. The reverse function, `fromInt`, is
implemented as an array. This makes use of the fact that both maps and
arrays *are* functions because they inherit from the `Function1` trait.
+{% endtab %}
+{% tab 'Scala 3' for=Base_1 %}
+~~~ scala
+enum Base:
+ case A, U, G, C
+
+object Base:
+ val fromInt: Int => Base = values
+ val toInt: Base => Int = _.ordinal
+~~~
+
+Every base is defined as a case of the `Base` enum. `Base` has a companion object
+that defines two functions that map between bases and the integers 0 to 3.
+
+The `toInt` function is implemented by delegating to the `ordinal` method defined on `Base`,
+which is automatically defined because `Base` is an enum. Each enum case will have a unique `ordinal` value.
+The reverse function, `fromInt`, is implemented as an array. This makes use of the fact that
+arrays *are* functions because they inherit from the `Function1` trait.
+
+{% endtab %}
+{% endtabs %}
+
The next task is to define a class for strands of RNA. Conceptually, a
strand of RNA is simply a `Seq[Base]`. However, RNA strands can get
quite long, so it makes sense to invest some work in a compact
@@ -383,51 +576,104 @@ representation.
### First version of RNA strands class ###
- import collection.mutable
- import collection.immutable.{ IndexedSeq, IndexedSeqOps }
+{% tabs RNA1_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=RNA1_1 %}
+~~~ scala
+import collection.mutable
+import collection.immutable.{ IndexedSeq, IndexedSeqOps }
- final class RNA1 private (
- val groups: Array[Int],
- val length: Int
- ) extends IndexedSeq[Base]
- with IndexedSeqOps[Base, IndexedSeq, RNA1] {
+final class RNA1 private (
+ val groups: Array[Int],
+ val length: Int
+) extends IndexedSeq[Base]
+ with IndexedSeqOps[Base, IndexedSeq, RNA1] {
- import RNA1._
+ import RNA1._
- def apply(idx: Int): Base = {
- if (idx < 0 || length <= idx)
- throw new IndexOutOfBoundsException
- Base.fromInt(groups(idx / N) >> (idx % N * S) & M)
- }
+ def apply(idx: Int): Base = {
+ if (idx < 0 || length <= idx)
+ throw new IndexOutOfBoundsException
+ Base.fromInt(groups(idx / N) >> (idx % N * S) & M)
+ }
- override protected def fromSpecific(coll: IterableOnce[Base]): RNA1 =
- fromSeq(coll.iterator.toSeq)
- override protected def newSpecificBuilder: mutable.Builder[Base, RNA1] =
- iterableFactory.newBuilder[Base].mapResult(fromSeq)
- override def empty: RNA1 = fromSeq(Seq.empty)
- override def className = "RNA1"
- }
+ override protected def fromSpecific(coll: IterableOnce[Base]): RNA1 =
+ fromSeq(coll.iterator.toSeq)
+ override protected def newSpecificBuilder: mutable.Builder[Base, RNA1] =
+ iterableFactory.newBuilder[Base].mapResult(fromSeq)
+ override def empty: RNA1 = fromSeq(Seq.empty)
+ override def className = "RNA1"
+}
- object RNA1 {
+object RNA1 {
- // Number of bits necessary to represent group
- private val S = 2
+ // Number of bits necessary to represent group
+ private val S = 2
- // Number of groups that fit in an Int
- private val N = 32 / S
+ // Number of groups that fit in an Int
+ private val N = 32 / S
- // Bitmask to isolate a group
- private val M = (1 << S) - 1
+ // Bitmask to isolate a group
+ private val M = (1 << S) - 1
- def fromSeq(buf: collection.Seq[Base]): RNA1 = {
- val groups = new Array[Int]((buf.length + N - 1) / N)
- for (i <- 0 until buf.length)
- groups(i / N) |= Base.toInt(buf(i)) << (i % N * S)
- new RNA1(groups, buf.length)
- }
+ def fromSeq(buf: collection.Seq[Base]): RNA1 = {
+ val groups = new Array[Int]((buf.length + N - 1) / N)
+ for (i <- 0 until buf.length)
+ groups(i / N) |= Base.toInt(buf(i)) << (i % N * S)
+ new RNA1(groups, buf.length)
+ }
- def apply(bases: Base*) = fromSeq(bases)
- }
+ def apply(bases: Base*) = fromSeq(bases)
+}
+~~~
+{% endtab %}
+{% tab 'Scala 3' for=RNA1_1 %}
+~~~ scala
+import collection.mutable
+import collection.immutable.{ IndexedSeq, IndexedSeqOps }
+
+final class RNA1 private
+( val groups: Array[Int],
+ val length: Int
+) extends IndexedSeq[Base],
+ IndexedSeqOps[Base, IndexedSeq, RNA1]:
+
+ import RNA1.*
+
+ def apply(idx: Int): Base =
+ if idx < 0 || length <= idx then
+ throw IndexOutOfBoundsException()
+ Base.fromInt(groups(idx / N) >> (idx % N * S) & M)
+
+ override protected def fromSpecific(coll: IterableOnce[Base]): RNA1 =
+ fromSeq(coll.iterator.toSeq)
+ override protected def newSpecificBuilder: mutable.Builder[Base, RNA1] =
+ iterableFactory.newBuilder[Base].mapResult(fromSeq)
+ override def empty: RNA1 = fromSeq(Seq.empty)
+ override def className = "RNA1"
+end RNA1
+
+object RNA1:
+
+ // Number of bits necessary to represent group
+ private val S = 2
+
+ // Number of groups that fit in an Int
+ private val N = 32 / S
+
+ // Bitmask to isolate a group
+ private val M = (1 << S) - 1
+
+ def fromSeq(buf: collection.Seq[Base]): RNA1 =
+ val groups = new Array[Int]((buf.length + N - 1) / N)
+ for i <- 0 until buf.length do
+ groups(i / N) |= Base.toInt(buf(i)) << (i % N * S)
+ new RNA1(groups, buf.length)
+
+ def apply(bases: Base*) = fromSeq(bases)
+end RNA1
+~~~
+{% endtab %}
+{% endtabs %}
The [RNA strands class listing](#first-version-of-rna-strands-class) above
presents the first version of this
@@ -484,14 +730,22 @@ in the `RNA1` object. It takes a variable number of `Base` arguments and
simply forwards them as a sequence to `fromSeq`. Here are the two
creation schemes in action:
- scala> val xs = List(A, G, U, A)
- xs: List[Base] = List(A, G, U, A)
+{% tabs RNA1_2 %}
+{% tab 'Scala 2 and 3' for=RNA1_2 %}
+
+```scala
+scala> val xs = List(A, G, U, A)
+val xs: List[Base] = List(A, G, U, A)
+
+scala> RNA1.fromSeq(xs)
+val res1: RNA1 = RNA1(A, G, U, A)
- scala> RNA1.fromSeq(xs)
- res1: RNA1 = RNA1(A, G, U, A)
+scala> val rna1 = RNA1(A, U, G, G, C)
+val rna1: RNA1 = RNA1(A, U, G, G, C)
+```
- scala> val rna1 = RNA1(A, U, G, G, C)
- rna1: RNA1 = RNA1(A, U, G, G, C)
+{% endtab %}
+{% endtabs %}
Also note that the type parameters of the `IndexedSeqOps` trait that
we inherit from are: `Base`, `IndexedSeq` and `RNA1`. The first one
@@ -507,11 +761,19 @@ third one is `RNA1`. This means that operations like `map` or
Here is an example showing the usage of `take` and `filter`:
- scala> rna1.take(3)
- res5: RNA1 = RNA1(A, U, G)
+{% tabs RNA1_3 %}
+{% tab 'Scala 2 and 3' for=RNA1_3 %}
+
+```scala
+scala> val rna1_2 = rna1.take(3)
+val rna1_2: RNA1 = RNA1(A, U, G)
+
+scala> val rna1_3 = rna1.filter(_ != U)
+val rna1_3: RNA1 = RNA1(A, G, G, C)
+```
- scala> rna1.filter(_ != U)
- res6: RNA1 = RNA1(A, G, G, C)
+{% endtab %}
+{% endtabs %}
### Dealing with map and friends ###
@@ -523,14 +785,22 @@ methods be adapted to RNA strands? The desired behavior would be to get
back an RNA strand when mapping bases to bases or appending two RNA strands
with `++`:
- scala> val rna = RNA(A, U, G, G, C)
- rna: RNA = RNA(A, U, G, G, C)
+{% tabs RNA1_4 %}
+{% tab 'Scala 2 and 3' for=RNA1_4 %}
- scala> rna map { case A => U case b => b }
- res7: RNA = RNA(U, U, G, G, C)
+```scala
+scala> val rna = RNA(A, U, G, G, C)
+val rna: RNA = RNA(A, U, G, G, C)
- scala> rna ++ rna
- res8: RNA = RNA(A, U, G, G, C, A, U, G, G, C)
+scala> rna.map { case A => U case b => b }
+val res7: RNA = RNA(U, U, G, G, C)
+
+scala> rna ++ rna
+val res8: RNA = RNA(A, U, G, G, C, A, U, G, G, C)
+```
+
+{% endtab %}
+{% endtabs %}
On the other hand, mapping bases to some other type over an RNA strand
cannot yield another RNA strand because the new elements have the
@@ -538,26 +808,42 @@ wrong type. It has to yield a sequence instead. In the same vein
appending elements that are not of type `Base` to an RNA strand can
yield a general sequence, but it cannot yield another RNA strand.
- scala> rna map Base.toInt
- res2: IndexedSeq[Int] = Vector(0, 1, 2, 2, 3)
+{% tabs RNA1_5 %}
+{% tab 'Scala 2 and 3' for=RNA1_5 %}
+
+```scala
+scala> rna.map(Base.toInt)
+val res2: IndexedSeq[Int] = Vector(0, 1, 2, 2, 3)
+
+scala> rna ++ List("missing", "data")
+val res3: IndexedSeq[java.lang.Object] =
+ Vector(A, U, G, G, C, missing, data)
+```
- scala> rna ++ List("missing", "data")
- res3: IndexedSeq[java.lang.Object] =
- Vector(A, U, G, G, C, missing, data)
+{% endtab %}
+{% endtabs %}
This is what you'd expect in the ideal case. But this is not what the
[`RNA1` class](#first-version-of-rna-strands-class) provides. In fact, all
examples will return instances of `Vector`, not just the last two. If you run
the first three commands above with instances of this class you obtain:
- scala> val rna1 = RNA1(A, U, G, G, C)
- rna1: RNA1 = RNA1(A, U, G, G, C)
+{% tabs RNA1_6 %}
+{% tab 'Scala 2 and 3' for=RNA1_6 %}
- scala> rna1 map { case A => U case b => b }
- res0: IndexedSeq[Base] = Vector(U, U, G, G, C)
+```scala
+scala> val rna1 = RNA1(A, U, G, G, C)
+val rna1: RNA1 = RNA1(A, U, G, G, C)
- scala> rna1 ++ rna1
- res1: IndexedSeq[Base] = Vector(A, U, G, G, C, A, U, G, G, C)
+scala> rna1.map { case A => U case b => b }
+val res0: IndexedSeq[Base] = Vector(U, U, G, G, C)
+
+scala> rna1 ++ rna1
+val res1: IndexedSeq[Base] = Vector(A, U, G, G, C, A, U, G, G, C)
+```
+
+{% endtab %}
+{% endtabs %}
So the result of `map` and `++` is never an RNA strand, even if the
element type of the generated collection is `Base`. To see how to do
@@ -566,7 +852,13 @@ method (or of `++`, which has a similar signature). The `map` method is
originally defined in class `scala.collection.IterableOps` with the
following signature:
- def map[B](f: A => B): CC[B]
+{% tabs map_signature %}
+{% tab 'Scala 2 and 3' for=map_signature %}
+```scala
+def map[B](f: A => B): CC[B]
+```
+{% endtab %}
+{% endtabs %}
Here `A` is the type of elements of the collection, and `CC` is the type
constructor passed as a second parameter to the `IterableOps` trait.
@@ -576,38 +868,84 @@ this is why we always get a `Vector` as a result.
### Second version of RNA strands class ###
- import scala.collection.{ View, mutable }
- import scala.collection.immutable.{ IndexedSeq, IndexedSeqOps }
-
- final class RNA2 private (val groups: Array[Int], val length: Int)
- extends IndexedSeq[Base] with IndexedSeqOps[Base, IndexedSeq, RNA2] {
-
- import RNA2._
-
- def apply(idx: Int): Base = // as before
- override protected def fromSpecific(coll: IterableOnce[Base]): RNA2 = // as before
- override protected def newSpecificBuilder: mutable.Builder[Base, RNA2] = // as before
-
- // Overloading of `appended`, `prepended`, `appendedAll`,
- // `prependedAll`, `map`, `flatMap` and `concat` to return an `RNA2`
- // when possible
- def concat(suffix: IterableOnce[Base]): RNA2 =
- fromSpecific(iterator ++ suffix.iterator)
- // symbolic alias for `concat`
- @inline final def ++ (suffix: IterableOnce[Base]): RNA2 = concat(suffix)
- def appended(base: Base): RNA2 =
- fromSpecific(new View.Append(this, base))
- def appendedAll(suffix: IterableOnce[Base]): RNA2 =
- concat(suffix)
- def prepended(base: Base): RNA2 =
- fromSpecific(new View.Prepend(base, this))
- def prependedAll(prefix: IterableOnce[Base]): RNA2 =
- fromSpecific(prefix.iterator ++ iterator)
- def map(f: Base => Base): RNA2 =
- fromSpecific(new View.Map(this, f))
- def flatMap(f: Base => IterableOnce[Base]): RNA2 =
- fromSpecific(new View.FlatMap(this, f))
- }
+{% tabs RNA2_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=RNA2_1 %}
+~~~ scala
+import scala.collection.{ View, mutable }
+import scala.collection.immutable.{ IndexedSeq, IndexedSeqOps }
+
+final class RNA2 private (val groups: Array[Int], val length: Int)
+ extends IndexedSeq[Base] with IndexedSeqOps[Base, IndexedSeq, RNA2] {
+
+ import RNA2._
+
+ def apply(idx: Int): Base = // as before
+ override protected def fromSpecific(coll: IterableOnce[Base]): RNA2 = // as before
+ override protected def newSpecificBuilder: mutable.Builder[Base, RNA2] = // as before
+ override def empty: RNA2 = // as before
+ override def className = "RNA2"
+
+ // Overloading of `appended`, `prepended`, `appendedAll`,
+ // `prependedAll`, `map`, `flatMap` and `concat` to return an `RNA2`
+ // when possible
+ def concat(suffix: IterableOnce[Base]): RNA2 =
+ fromSpecific(iterator ++ suffix.iterator)
+ // symbolic alias for `concat`
+ @inline final def ++ (suffix: IterableOnce[Base]): RNA2 = concat(suffix)
+ def appended(base: Base): RNA2 =
+ fromSpecific(new View.Appended(this, base))
+ def appendedAll(suffix: IterableOnce[Base]): RNA2 =
+ concat(suffix)
+ def prepended(base: Base): RNA2 =
+ fromSpecific(new View.Prepended(base, this))
+ def prependedAll(prefix: IterableOnce[Base]): RNA2 =
+ fromSpecific(prefix.iterator ++ iterator)
+ def map(f: Base => Base): RNA2 =
+ fromSpecific(new View.Map(this, f))
+ def flatMap(f: Base => IterableOnce[Base]): RNA2 =
+ fromSpecific(new View.FlatMap(this, f))
+}
+~~~
+{% endtab %}
+{% tab 'Scala 3' for=RNA2_1 %}
+~~~ scala
+import scala.collection.{ View, mutable }
+import scala.collection.immutable.{ IndexedSeq, IndexedSeqOps }
+
+final class RNA2 private (val groups: Array[Int], val length: Int)
+ extends IndexedSeq[Base], IndexedSeqOps[Base, IndexedSeq, RNA2]:
+
+ import RNA2.*
+
+ def apply(idx: Int): Base = // as before
+ override protected def fromSpecific(coll: IterableOnce[Base]): RNA2 = // as before
+ override protected def newSpecificBuilder: mutable.Builder[Base, RNA2] = // as before
+ override def empty: RNA2 = // as before
+ override def className = "RNA2"
+
+ // Overloading of `appended`, `prepended`, `appendedAll`,
+ // `prependedAll`, `map`, `flatMap` and `concat` to return an `RNA2`
+ // when possible
+ def concat(suffix: IterableOnce[Base]): RNA2 =
+ fromSpecific(iterator ++ suffix.iterator)
+ // symbolic alias for `concat`
+ inline final def ++ (suffix: IterableOnce[Base]): RNA2 = concat(suffix)
+ def appended(base: Base): RNA2 =
+ fromSpecific(View.Appended(this, base))
+ def appendedAll(suffix: IterableOnce[Base]): RNA2 =
+ concat(suffix)
+ def prepended(base: Base): RNA2 =
+ fromSpecific(View.Prepended(base, this))
+ def prependedAll(prefix: IterableOnce[Base]): RNA2 =
+ fromSpecific(prefix.iterator ++ iterator)
+ def map(f: Base => Base): RNA2 =
+ fromSpecific(View.Map(this, f))
+ def flatMap(f: Base => IterableOnce[Base]): RNA2 =
+ fromSpecific(View.FlatMap(this, f))
+end RNA2
+~~~
+{% endtab %}
+{% endtabs %}
To address this shortcoming, you need to overload the methods that
return an `IndexedSeq[B]` for the case where `B` is known to be `Base`,
@@ -622,9 +960,11 @@ collection is strict, we could take advantage of the better performance offered
in transformation operations.
Also, if we try to convert an `Iterable[Base]` into an `RNA2` it fails:
-~~~
+{% tabs RNA2_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=RNA2_2 %}
+~~~scala
scala> val bases: Iterable[Base] = List(A, U, C, C)
-bases: Iterable[Base] = List(A, U, C, C)
+val bases: Iterable[Base] = List(A, U, C, C)
scala> bases.to(RNA2)
^
@@ -632,9 +972,28 @@ scala> bases.to(RNA2)
found : RNA2.type
required: scala.collection.Factory[Base,?]
~~~
+{% endtab %}
+{% tab 'Scala 3' for=RNA2_2 %}
+~~~scala
+scala> val bases: Iterable[Base] = List(A, U, C, C)
+val bases: Iterable[Base] = List(A, U, C, C)
+
+scala> bases.to(RNA2)
+-- [E007] Type Mismatch Error: -------------------------------------------------
+1 |bases.to(RNA2)
+ | ^^^^
+ | Found: RNA2.type
+ | Required: scala.collection.Factory[Base, Any]
+ |
+ | longer explanation available when compiling with `-explain`
+~~~
+{% endtab %}
+{% endtabs %}
### Final version of RNA strands class ###
+{% tabs RNA_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=RNA_1 %}
~~~ scala
import scala.collection.{ AbstractIterator, SpecificIterableFactory, StrictOptimizedSeqOps, View, mutable }
import scala.collection.immutable.{ IndexedSeq, IndexedSeqOps }
@@ -723,6 +1082,94 @@ object RNA extends SpecificIterableFactory[Base, RNA] {
}
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=RNA_1 %}
+~~~ scala
+import scala.collection.{ AbstractIterator, SpecificIterableFactory, StrictOptimizedSeqOps, View, mutable }
+import scala.collection.immutable.{ IndexedSeq, IndexedSeqOps }
+
+final class RNA private
+( val groups: Array[Int],
+ val length: Int
+) extends IndexedSeq[Base],
+ IndexedSeqOps[Base, IndexedSeq, RNA],
+ StrictOptimizedSeqOps[Base, IndexedSeq, RNA]:
+ rna =>
+
+ import RNA.*
+
+ // Mandatory implementation of `apply` in `IndexedSeqOps`
+ def apply(idx: Int): Base =
+ if idx < 0 || length <= idx then
+ throw new IndexOutOfBoundsException
+ Base.fromInt(groups(idx / N) >> (idx % N * S) & M)
+
+ // Mandatory overrides of `fromSpecific`, `newSpecificBuilder`,
+ // and `empty`, from `IterableOps`
+ override protected def fromSpecific(coll: IterableOnce[Base]): RNA =
+ RNA.fromSpecific(coll)
+ override protected def newSpecificBuilder: mutable.Builder[Base, RNA] =
+ RNA.newBuilder
+ override def empty: RNA = RNA.empty
+
+ // Overloading of `appended`, `prepended`, `appendedAll`, `prependedAll`,
+ // `map`, `flatMap` and `concat` to return an `RNA` when possible
+ def concat(suffix: IterableOnce[Base]): RNA =
+ strictOptimizedConcat(suffix, newSpecificBuilder)
+ inline final def ++ (suffix: IterableOnce[Base]): RNA = concat(suffix)
+ def appended(base: Base): RNA =
+ (newSpecificBuilder ++= this += base).result()
+ def appendedAll(suffix: Iterable[Base]): RNA =
+ strictOptimizedConcat(suffix, newSpecificBuilder)
+ def prepended(base: Base): RNA =
+ (newSpecificBuilder += base ++= this).result()
+ def prependedAll(prefix: Iterable[Base]): RNA =
+ (newSpecificBuilder ++= prefix ++= this).result()
+ def map(f: Base => Base): RNA =
+ strictOptimizedMap(newSpecificBuilder, f)
+ def flatMap(f: Base => IterableOnce[Base]): RNA =
+ strictOptimizedFlatMap(newSpecificBuilder, f)
+
+ // Optional re-implementation of iterator,
+ // to make it more efficient.
+ override def iterator: Iterator[Base] = new AbstractIterator[Base]:
+ private var i = 0
+ private var b = 0
+ def hasNext: Boolean = i < rna.length
+ def next(): Base =
+ b = if i % N == 0 then groups(i / N) else b >>> S
+ i += 1
+ Base.fromInt(b & M)
+
+ override def className = "RNA"
+end RNA
+
+object RNA extends SpecificIterableFactory[Base, RNA]:
+
+ private val S = 2 // number of bits in group
+ private val M = (1 << S) - 1 // bitmask to isolate a group
+ private val N = 32 / S // number of groups in an Int
+
+ def fromSeq(buf: collection.Seq[Base]): RNA =
+ val groups = new Array[Int]((buf.length + N - 1) / N)
+ for i <- 0 until buf.length do
+ groups(i / N) |= Base.toInt(buf(i)) << (i % N * S)
+ new RNA(groups, buf.length)
+
+ // Mandatory factory methods: `empty`, `newBuilder`
+ // and `fromSpecific`
+ def empty: RNA = fromSeq(Seq.empty)
+
+ def newBuilder: mutable.Builder[Base, RNA] =
+ mutable.ArrayBuffer.newBuilder[Base].mapResult(fromSeq)
+
+ def fromSpecific(it: IterableOnce[Base]): RNA = it match
+ case seq: collection.Seq[Base] => fromSeq(seq)
+ case _ => fromSeq(mutable.ArrayBuffer.from(it))
+end RNA
+~~~
+{% endtab %}
+{% endtabs %}
The final [`RNA` class](#final-version-of-rna-strands-class):
@@ -771,7 +1218,7 @@ storing the strings "abc", "abd", "al", "all" and "xy" would look
like this:
A sample patricia trie:
-
+
To find the node corresponding to the string "abc" in this trie,
simply follow the subtree labeled "a", proceed from there to the
@@ -793,17 +1240,35 @@ of a map that's implemented as a Patricia trie. We call the map a
selects a submap of all keys starting with a given prefix. We'll first
define a prefix map with the keys shown in the running example:
- scala> val m = PrefixMap("abc" -> 0, "abd" -> 1, "al" -> 2,
- "all" -> 3, "xy" -> 4)
- m: PrefixMap[Int] = PrefixMap((abc,0), (abd,1), (al,2), (all,3), (xy,4))
+{% tabs prefixMap_1 %}
+{% tab 'Scala 2 and 3' for=prefixMap_1 %}
+
+```scala
+scala> val m = PrefixMap("abc" -> 0, "abd" -> 1, "al" -> 2,
+ "all" -> 3, "xy" -> 4)
+val m: PrefixMap[Int] = PrefixMap((abc,0), (abd,1), (al,2), (all,3), (xy,4))
+```
+
+{% endtab %}
+{% endtabs %}
Then calling `withPrefix` on `m` will yield another prefix map:
- scala> m withPrefix "a"
- res14: PrefixMap[Int] = PrefixMap((bc,0), (bd,1), (l,2), (ll,3))
+{% tabs prefixMap_2 %}
+{% tab 'Scala 2 and 3' for=prefixMap_2 %}
+
+```scala
+scala> m.withPrefix("a")
+val res14: PrefixMap[Int] = PrefixMap((bc,0), (bd,1), (l,2), (ll,3))
+```
+
+{% endtab %}
+{% endtabs %}
### Patricia trie implementation ###
+{% tabs prefixMap_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=prefixMap_3 %}
~~~ scala
import scala.collection._
import scala.collection.mutable.{ GrowableBuilder, Builder }
@@ -818,18 +1283,18 @@ class PrefixMap[A]
def get(s: String): Option[A] =
if (s.isEmpty) value
- else suffixes get (s(0)) flatMap (_.get(s substring 1))
+ else suffixes.get(s(0)).flatMap(_.get(s.substring(1)))
def withPrefix(s: String): PrefixMap[A] =
if (s.isEmpty) this
else {
val leading = s(0)
- suffixes get leading match {
+ suffixes.get(leading) match {
case None =>
suffixes = suffixes + (leading -> empty)
case _ =>
}
- suffixes(leading) withPrefix (s substring 1)
+ suffixes(leading).withPrefix(s.substring(1))
}
def iterator: Iterator[(String, A)] =
@@ -844,7 +1309,7 @@ class PrefixMap[A]
def subtractOne(s: String): this.type = {
if (s.isEmpty) { val prev = value; value = None; prev }
- else suffixes get (s(0)) flatMap (_.remove(s substring 1))
+ else suffixes.get(s(0)).flatMap(_.remove(s.substring(1)))
this
}
@@ -864,7 +1329,7 @@ class PrefixMap[A]
// Members declared in scala.collection.IterableOps
override protected def fromSpecific(coll: IterableOnce[(String, A)]): PrefixMap[A] = PrefixMap.from(coll)
override protected def newSpecificBuilder: mutable.Builder[(String, A), PrefixMap[A]] = PrefixMap.newBuilder
-
+
override def className = "PrefixMap"
}
@@ -892,6 +1357,91 @@ object PrefixMap {
}
~~~
+{% endtab %}
+{% tab 'Scala 3' for=prefixMap_3 %}
+~~~ scala
+import scala.collection.*
+import scala.collection.mutable.{ GrowableBuilder, Builder }
+
+class PrefixMap[A]
+ extends mutable.Map[String, A],
+ mutable.MapOps[String, A, mutable.Map, PrefixMap[A]],
+ StrictOptimizedIterableOps[(String, A), mutable.Iterable, PrefixMap[A]]:
+
+ private var suffixes: immutable.Map[Char, PrefixMap[A]] = immutable.Map.empty
+ private var value: Option[A] = None
+
+ def get(s: String): Option[A] =
+ if s.isEmpty then value
+ else suffixes.get(s(0)).flatMap(_.get(s.substring(1)))
+
+ def withPrefix(s: String): PrefixMap[A] =
+ if s.isEmpty then this
+ else
+ val leading = s(0)
+ suffixes.get(leading) match
+ case None =>
+ suffixes = suffixes + (leading -> empty)
+ case _ =>
+ suffixes(leading).withPrefix(s.substring(1))
+
+ def iterator: Iterator[(String, A)] =
+ (for v <- value.iterator yield ("", v)) ++
+ (for (chr, m) <- suffixes.iterator
+ (s, v) <- m.iterator yield (chr +: s, v))
+
+ def addOne(kv: (String, A)): this.type =
+ withPrefix(kv._1).value = Some(kv._2)
+ this
+
+ def subtractOne(s: String): this.type =
+ if s.isEmpty then { val prev = value; value = None; prev }
+ else suffixes.get(s(0)).flatMap(_.remove(s.substring(1)))
+ this
+
+ // Overloading of transformation methods that should return a PrefixMap
+ def map[B](f: ((String, A)) => (String, B)): PrefixMap[B] =
+ strictOptimizedMap(PrefixMap.newBuilder, f)
+ def flatMap[B](f: ((String, A)) => IterableOnce[(String, B)]): PrefixMap[B] =
+ strictOptimizedFlatMap(PrefixMap.newBuilder, f)
+
+ // Override `concat` and `empty` methods to refine their return type
+ override def concat[B >: A](suffix: IterableOnce[(String, B)]): PrefixMap[B] =
+ strictOptimizedConcat(suffix, PrefixMap.newBuilder)
+ override def empty: PrefixMap[A] = PrefixMap()
+
+ // Members declared in scala.collection.mutable.Clearable
+ override def clear(): Unit = suffixes = immutable.Map.empty
+ // Members declared in scala.collection.IterableOps
+ override protected def fromSpecific(coll: IterableOnce[(String, A)]): PrefixMap[A] = PrefixMap.from(coll)
+ override protected def newSpecificBuilder: mutable.Builder[(String, A), PrefixMap[A]] = PrefixMap.newBuilder
+
+ override def className = "PrefixMap"
+end PrefixMap
+
+object PrefixMap:
+ def empty[A] = new PrefixMap[A]
+
+ def from[A](source: IterableOnce[(String, A)]): PrefixMap[A] =
+ source match
+ case pm: PrefixMap[A @unchecked] => pm
+ case _ => (newBuilder ++= source).result()
+
+ def apply[A](kvs: (String, A)*): PrefixMap[A] = from(kvs)
+
+ def newBuilder[A]: mutable.Builder[(String, A), PrefixMap[A]] =
+ mutable.GrowableBuilder[(String, A), PrefixMap[A]](empty)
+
+ import scala.language.implicitConversions
+
+ implicit def toFactory[A](self: this.type): Factory[(String, A), PrefixMap[A]] =
+ new Factory[(String, A), PrefixMap[A]]:
+ def fromSpecific(it: IterableOnce[(String, A)]): PrefixMap[A] = self.from(it)
+ def newBuilder: mutable.Builder[(String, A), PrefixMap[A]] = self.newBuilder
+end PrefixMap
+~~~
+{% endtab %}
+{% endtabs %}
The previous listing shows the definition of `PrefixMap`. The map has
keys of type `String` and the values are of parametric type `A`. It extends
@@ -968,7 +1518,7 @@ However, in all these cases, to build the right kind of collection
you need to start with an empty collection of that kind. This is
provided by the `empty` method, which simply returns a fresh `PrefixMap`.
-We'll now turn to the companion object `PrefixMap`. In fact it is not
+We'll now turn to the companion object `PrefixMap`. In fact, it is not
strictly necessary to define this companion object, as class `PrefixMap`
can stand well on its own. The main purpose of object `PrefixMap` is to
define some convenience factory methods. It also defines an implicit
@@ -980,15 +1530,23 @@ can not because a `Factory` fixes the type of collection elements,
whereas `PrefixMap` has a polymorphic type of values).
The two convenience methods are `empty` and `apply`. The same methods are
-present for all other collections in Scala's collection framework so
+present for all other collections in Scala's collection framework, so
it makes sense to define them here, too. With the two methods, you can
write `PrefixMap` literals like you do for any other collection:
- scala> PrefixMap("hello" -> 5, "hi" -> 2)
- res0: PrefixMap[Int] = PrefixMap(hello -> 5, hi -> 2)
+{% tabs prefixMap_4 %}
+{% tab 'Scala 2 and 3' for=prefixMap_4 %}
+
+```scala
+scala> PrefixMap("hello" -> 5, "hi" -> 2)
+val res0: PrefixMap[Int] = PrefixMap(hello -> 5, hi -> 2)
+
+scala> res0 += "foo" -> 3
+val res1: res0.type = PrefixMap(hello -> 5, hi -> 2, foo -> 3)
+```
- scala> res0 += "foo" -> 3
- res1: res0.type = PrefixMap(hello -> 5, hi -> 2, foo -> 3)
+{% endtab %}
+{% endtabs %}
## Summary ##
diff --git a/_overviews/core/futures.md b/_overviews/core/futures.md
index c8ceef7257..9f01a43710 100644
--- a/_overviews/core/futures.md
+++ b/_overviews/core/futures.md
@@ -14,7 +14,8 @@ permalink: /overviews/core/:title.html
## Introduction
Futures provide a way to reason about performing many operations
-in parallel-- in an efficient and non-blocking way.
+in parallel -- in an efficient and non-blocking way.
+
A [`Future`](https://www.scala-lang.org/api/current/scala/concurrent/Future.html)
is a placeholder object for a value that may not yet exist.
Generally, the value of the Future is supplied concurrently and can subsequently be used.
@@ -40,18 +41,34 @@ environment to resize itself if necessary to guarantee progress.
A typical future looks like this:
+{% tabs futures-00 %}
+{% tab 'Scala 2 and 3' for=futures-00 %}
val inverseFuture: Future[Matrix] = Future {
fatMatrix.inverse() // non-blocking long lasting computation
}(executionContext)
+{% endtab %}
+{% endtabs %}
Or with the more idiomatic:
+{% tabs futures-01 class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=futures-01 %}
implicit val ec: ExecutionContext = ...
val inverseFuture : Future[Matrix] = Future {
fatMatrix.inverse()
} // ec is implicitly passed
+{% endtab %}
+
+{% tab 'Scala 3' for=futures-01 %}
+ given ExecutionContext = ...
+ val inverseFuture : Future[Matrix] = Future {
+ fatMatrix.inverse()
+ } // execution context is implicitly passed
+{% endtab %}
+{% endtabs %}
Both code snippets delegate the execution of `fatMatrix.inverse()` to an `ExecutionContext` and embody the result of the computation in `inverseFuture`.
@@ -80,11 +97,11 @@ only if each blocking call is wrapped inside a `blocking` call (more on that bel
Otherwise, there is a risk that the thread pool in the global execution context is starved,
and no computation can proceed.
-By default the `ExecutionContext.global` sets the parallelism level of its underlying fork-join pool to the number of available processors
+By default, the `ExecutionContext.global` sets the parallelism level of its underlying fork-join pool to the number of available processors
([Runtime.availableProcessors](https://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#availableProcessors%28%29)).
This configuration can be overridden by setting one (or more) of the following VM attributes:
- * scala.concurrent.context.minThreads - defaults to `Runtime.availableProcessors`
+ * scala.concurrent.context.minThreads - defaults to `1`
* scala.concurrent.context.numThreads - can be a number or a multiplier (N) in the form 'xN' ; defaults to `Runtime.availableProcessors`
* scala.concurrent.context.maxThreads - defaults to `Runtime.availableProcessors`
@@ -93,7 +110,10 @@ The parallelism level will be set to `numThreads` as long as it remains within `
As stated above the `ForkJoinPool` can increase the number of threads beyond its `parallelismLevel` in the presence of blocking computation.
As explained in the `ForkJoinPool` API, this is only possible if the pool is explicitly notified:
- import scala.concurrent.Future
+{% tabs futures-02 class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=futures-02 %}
+ import scala.concurrent.{ Future, ExecutionContext }
import scala.concurrent.forkjoin._
// the following is equivalent to `implicit val ec = ExecutionContext.global`
@@ -118,10 +138,40 @@ As explained in the `ForkJoinPool` API, this is only possible if the pool is exp
}
)
}
+{% endtab %}
+{% tab 'Scala 3' for=futures-02 %}
+ import scala.concurrent.{ Future, ExecutionContext }
+ import scala.concurrent.forkjoin.*
+
+ // the following is equivalent to `given ExecutionContext = ExecutionContext.global`
+ import ExecutionContext.Implicits.global
+
+ Future {
+ ForkJoinPool.managedBlock(
+ new ManagedBlocker {
+ var done = false
+
+ def block(): Boolean =
+ try
+ myLock.lock()
+ // ...
+ finally
+ done = true
+ true
+
+ def isReleasable: Boolean = done
+ }
+ )
+ }
+{% endtab %}
+
+{% endtabs %}
Fortunately the concurrent package provides a convenient way for doing so:
+{% tabs blocking %}
+{% tab 'Scala 2 and 3' for=blocking %}
import scala.concurrent.Future
import scala.concurrent.blocking
@@ -131,26 +181,43 @@ Fortunately the concurrent package provides a convenient way for doing so:
// ...
}
}
+{% endtab %}
+{% endtabs %}
Note that `blocking` is a general construct that will be discussed more in depth [below](#blocking-inside-a-future).
-Last but not least, you must remember that the `ForkJoinPool` is not designed for long lasting blocking operations.
+Last but not least, you must remember that the `ForkJoinPool` is not designed for long-lasting blocking operations.
Even when notified with `blocking` the pool might not spawn new workers as you would expect,
and when new workers are created they can be as many as 32767.
To give you an idea, the following code will use 32000 threads:
+{% tabs futures-03 class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=futures-03 %}
implicit val ec = ExecutionContext.global
- for( i <- 1 to 32000 ) {
+ for (i <- 1 to 32000) {
Future {
blocking {
Thread.sleep(999999)
}
}
}
+{% endtab %}
+{% tab 'Scala 3' for=futures-03 %}
+ given ExecutionContext = ExecutionContext.global
+ for i <- 1 to 32000 do
+ Future {
+ blocking {
+ Thread.sleep(999999)
+ }
+ }
+{% endtab %}
+
+{% endtabs %}
-If you need to wrap long lasting blocking operations we recommend using a dedicated `ExecutionContext`, for instance by wrapping a Java `Executor`.
+If you need to wrap long-lasting blocking operations we recommend using a dedicated `ExecutionContext`, for instance by wrapping a Java `Executor`.
### Adapting a Java Executor
@@ -158,26 +225,43 @@ If you need to wrap long lasting blocking operations we recommend using a dedica
Using the `ExecutionContext.fromExecutor` method you can wrap a Java `Executor` into an `ExecutionContext`.
For instance:
+{% tabs executor class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=executor %}
ExecutionContext.fromExecutor(new ThreadPoolExecutor( /* your configuration */ ))
+{% endtab %}
+{% tab 'Scala 3' for=executor %}
+ ExecutionContext.fromExecutor(ThreadPoolExecutor( /* your configuration */ ))
+{% endtab %}
+
+{% endtabs %}
### Synchronous Execution Context
One might be tempted to have an `ExecutionContext` that runs computations within the current thread:
+{% tabs bad-example %}
+{% tab 'Scala 2 and 3' for=bad-example %}
val currentThreadExecutionContext = ExecutionContext.fromExecutor(
new Executor {
// Do not do this!
- def execute(runnable: Runnable) { runnable.run() }
+ def execute(runnable: Runnable) = runnable.run()
})
+{% endtab %}
+{% endtabs %}
This should be avoided as it introduces non-determinism in the execution of your future.
+{% tabs bad-example-2 %}
+{% tab 'Scala 2 and 3' for=bad-example-2 %}
Future {
doSomething
}(ExecutionContext.global).map {
doSomethingElse
}(currentThreadExecutionContext)
+{% endtab %}
+{% endtabs %}
The `doSomethingElse` call might either execute in `doSomething`'s thread or in the main thread, and therefore be either asynchronous or synchronous.
As explained [here](https://blog.ometer.com/2011/07/24/callbacks-synchronous-and-asynchronous/) a callback should not be both.
@@ -200,7 +284,7 @@ Completion can take one of two forms:
A `Future` has an important property that it may only be assigned
once.
Once a `Future` object is given a value or an exception, it becomes
-in effect immutable-- it can never be overwritten.
+in effect immutable -- it can never be overwritten.
The simplest way to create a future object is to invoke the `Future.apply`
method which starts an asynchronous computation and returns a
@@ -219,6 +303,9 @@ popular social network to obtain a list of friends for a given user.
We will open a new session and then send
a request to obtain a list of friends of a particular user:
+{% tabs futures-04 class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=futures-04 %}
import scala.concurrent._
import ExecutionContext.Implicits.global
@@ -226,6 +313,17 @@ a request to obtain a list of friends of a particular user:
val f: Future[List[Friend]] = Future {
session.getFriends()
}
+{% endtab %}
+{% tab 'Scala 3' for=futures-04 %}
+ import scala.concurrent.*
+ import ExecutionContext.Implicits.global
+
+ val session = socialNetwork.createSessionFor("user", credentials)
+ val f: Future[List[Friend]] = Future {
+ session.getFriends()
+ }
+{% endtab %}
+{% endtabs %}
Above, we first import the contents of the `scala.concurrent` package
to make the type `Future` visible.
@@ -238,8 +336,8 @@ To obtain the list of friends of a user, a request
has to be sent over a network, which can take a long time.
This is illustrated with the call to the method `getFriends` that returns `List[Friend]`.
To better utilize the CPU until the response arrives, we should not
-block the rest of the program-- this computation should be scheduled
-asynchronously. The `Future.apply` method does exactly that-- it performs
+block the rest of the program -- this computation should be scheduled
+asynchronously. The `Future.apply` method does exactly that -- it performs
the specified computation block concurrently, in this case sending
a request to the server and waiting for a response.
@@ -251,10 +349,14 @@ the following example, the `session` value is incorrectly
initialized, so the computation in the `Future` block will throw a `NullPointerException`.
This future `f` is then failed with this exception instead of being completed successfully:
+{% tabs futures-04b %}
+{% tab 'Scala 2 and 3' for=futures-04b %}
val session = null
val f: Future[List[Friend]] = Future {
- session.getFriends
+ session.getFriends()
}
+{% endtab %}
+{% endtabs %}
The line `import ExecutionContext.Implicits.global` above imports
the default global execution context.
@@ -270,16 +372,20 @@ Our example was based on a hypothetical social network API where
the computation consists of sending a network request and waiting
for a response.
It is fair to offer an example involving an asynchronous computation
-which you can try out of the box. Assume you have a text file and
+which you can try out of the box. Assume you have a text file, and
you want to find the position of the first occurrence of a particular keyword.
This computation may involve blocking while the file contents
are being retrieved from the disk, so it makes sense to perform it
concurrently with the rest of the computation.
+{% tabs futures-04c %}
+{% tab 'Scala 2 and 3' for=futures-04c %}
val firstOccurrence: Future[Int] = Future {
val source = scala.io.Source.fromFile("myText.txt")
source.toSeq.indexOfSlice("myKeyword")
}
+{% endtab %}
+{% endtabs %}
### Callbacks
@@ -291,7 +397,7 @@ We are often interested in the result of the computation, not just its
side-effects.
In many future implementations, once the client of the future becomes interested
-in its result, it has to block its own computation and wait until the future is completed--
+in its result, it has to block its own computation and wait until the future is completed --
only then can it use the value of the future to continue its own computation.
Although this is allowed by the Scala `Future` API as we will show later,
from a performance point of view a better way to do it is in a completely
@@ -323,32 +429,63 @@ value is a `Throwable`.
Coming back to our social network example, let's assume we want to
fetch a list of our own recent posts and render them to the screen.
We do so by calling a method `getRecentPosts` which returns
-a `List[String]`-- a list of recent textual posts:
+a `List[String]` -- a list of recent textual posts:
+{% tabs futures-05 class=tabs-scala-version %}
+{% tab 'Scala 2' for=futures-05 %}
import scala.util.{Success, Failure}
val f: Future[List[String]] = Future {
- session.getRecentPosts
+ session.getRecentPosts()
}
- f onComplete {
+ f.onComplete {
case Success(posts) => for (post <- posts) println(post)
case Failure(t) => println("An error has occurred: " + t.getMessage)
}
+{% endtab %}
+{% tab 'Scala 3' for=futures-05 %}
+ import scala.util.{Success, Failure}
+
+ val f: Future[List[String]] = Future {
+ session.getRecentPosts()
+ }
+
+ f.onComplete {
+ case Success(posts) => for post <- posts do println(post)
+ case Failure(t) => println("An error has occurred: " + t.getMessage)
+ }
+{% endtab %}
+{% endtabs %}
The `onComplete` method is general in the sense that it allows the
client to handle the result of both failed and successful future
computations. In the case where only successful results need to be
handled, the `foreach` callback can be used:
+{% tabs futures-06 class=tabs-scala-version %}
+{% tab 'Scala 2' for=futures-06 %}
val f: Future[List[String]] = Future {
- session.getRecentPosts
+ session.getRecentPosts()
}
- f foreach { posts =>
- for (post <- posts) println(post)
+ for {
+ posts <- f
+ post <- posts
+ } println(post)
+{% endtab %}
+{% tab 'Scala 3' for=futures-06 %}
+ val f: Future[List[String]] = Future {
+ session.getRecentPosts()
}
+ for
+ posts <- f
+ post <- posts
+ do println(post)
+{% endtab %}
+{% endtabs %}
+
`Future`s provide a clean way of handling only failed results using
the `failed` projection which converts a `Failure[Throwable]` to a
`Success[Throwable]`. An example of doing this is provided in the
@@ -358,15 +495,19 @@ Coming back to the previous example with searching for the first
occurrence of a keyword, you might want to print the position
of the keyword to the screen:
+{% tabs futures-oncomplete %}
+{% tab 'Scala 2 and 3' for=futures-oncomplete %}
val firstOccurrence: Future[Int] = Future {
val source = scala.io.Source.fromFile("myText.txt")
source.toSeq.indexOfSlice("myKeyword")
}
- firstOccurrence onComplete {
+ firstOccurrence.onComplete {
case Success(idx) => println("The keyword first appears at position: " + idx)
case Failure(t) => println("Could not process file: " + t.getMessage)
}
+{% endtab %}
+{% endtabs %}
The `onComplete` and `foreach` methods both have result type `Unit`, which
@@ -393,19 +534,23 @@ This means that in the following example the variable `totalA` may not be set
to the correct number of lower case and upper case `a` characters from the computed
text.
+{% tabs volatile %}
+{% tab 'Scala 2 and 3' for=volatile %}
@volatile var totalA = 0
val text = Future {
"na" * 16 + "BATMAN!!!"
}
- text foreach { txt =>
+ text.foreach { txt =>
totalA += txt.count(_ == 'a')
}
- text foreach { txt =>
+ text.foreach { txt =>
totalA += txt.count(_ == 'A')
}
+{% endtab %}
+{% endtabs %}
Above, the two callbacks may execute one after the other, in
which case the variable `totalA` holds the expected value `18`.
@@ -434,10 +579,10 @@ callbacks may be executed concurrently with one another.
However, a particular `ExecutionContext` implementation may result
in a well-defined order.
-5. In the event that some of the callbacks throw an exception, the
+5. In the event that some callbacks throw an exception, the
other callbacks are executed regardless.
-6. In the event that some of the callbacks never complete (e.g. the
+6. In the event that some callbacks never complete (e.g. the
callback contains an infinite loop), the other callbacks may not be
executed at all. In these cases, a potentially blocking callback must
use the `blocking` construct (see below).
@@ -456,25 +601,42 @@ interfacing with a currency trading service. Suppose we want to buy US
dollars, but only when it's profitable. We first show how this could
be done using callbacks:
+{% tabs futures-07 class=tabs-scala-version %}
+{% tab 'Scala 2' for=futures-07 %}
val rateQuote = Future {
connection.getCurrentValue(USD)
}
- rateQuote foreach { quote =>
+ for (quote <- rateQuote) {
val purchase = Future {
if (isProfitable(quote)) connection.buy(amount, quote)
else throw new Exception("not profitable")
}
- purchase foreach { amount =>
+ for (amount <- purchase)
println("Purchased " + amount + " USD")
- }
}
+{% endtab %}
+{% tab 'Scala 3' for=futures-07 %}
+ val rateQuote = Future {
+ connection.getCurrentValue(USD)
+ }
+
+ for quote <- rateQuote do
+ val purchase = Future {
+ if isProfitable(quote) then connection.buy(amount, quote)
+ else throw Exception("not profitable")
+ }
+
+ for amount <- purchase do
+ println("Purchased " + amount + " USD")
+{% endtab %}
+{% endtabs %}
We start by creating a future `rateQuote` which gets the current exchange
rate.
After this value is obtained from the server and the future successfully
-completed, the computation proceeds in the `foreach` callback and we are
+completed, the computation proceeds in the `foreach` callback, and we are
ready to decide whether to buy or not.
We therefore create another future `purchase` which makes a decision to buy only if it's profitable
to do so, and then sends a request.
@@ -489,7 +651,7 @@ some other currency. We would have to repeat this pattern within the
to reason about.
Second, the `purchase` future is not in the scope with the rest of
-the code-- it can only be acted upon from within the `foreach`
+the code -- it can only be acted upon from within the `foreach`
callback. This means that other parts of the application do not
see the `purchase` future and cannot register another `foreach`
callback to it, for example, to sell some other currency.
@@ -504,18 +666,36 @@ about mapping collections.
Let's rewrite the previous example using the `map` combinator:
+{% tabs futures-08 class=tabs-scala-version %}
+{% tab 'Scala 2' for=futures-08 %}
val rateQuote = Future {
connection.getCurrentValue(USD)
}
- val purchase = rateQuote map { quote =>
+ val purchase = rateQuote.map { quote =>
if (isProfitable(quote)) connection.buy(amount, quote)
else throw new Exception("not profitable")
}
- purchase foreach { amount =>
+ purchase.foreach { amount =>
println("Purchased " + amount + " USD")
}
+{% endtab %}
+{% tab 'Scala 3' for=futures-08 %}
+ val rateQuote = Future {
+ connection.getCurrentValue(USD)
+ }
+
+ val purchase = rateQuote.map { quote =>
+ if isProfitable(quote) then connection.buy(amount, quote)
+ else throw Exception("not profitable")
+ }
+
+ purchase.foreach { amount =>
+ println("Purchased " + amount + " USD")
+ }
+{% endtab %}
+{% endtabs %}
By using `map` on `rateQuote` we have eliminated one `foreach` callback and,
more importantly, the nesting.
@@ -544,11 +724,13 @@ combinators. The `flatMap` method takes a function that maps the value
to a new future `g`, and then returns a future which is completed once
`g` is completed.
-Lets assume that we want to exchange US dollars for Swiss francs
+Let's assume that we want to exchange US dollars for Swiss francs
(CHF). We have to fetch quotes for both currencies, and then decide on
buying based on both quotes.
Here is an example of `flatMap` and `withFilter` usage within for-comprehensions:
+{% tabs futures-09 class=tabs-scala-version %}
+{% tab 'Scala 2' for=futures-09 %}
val usdQuote = Future { connection.getCurrentValue(USD) }
val chfQuote = Future { connection.getCurrentValue(CHF) }
@@ -561,20 +743,40 @@ Here is an example of `flatMap` and `withFilter` usage within for-comprehensions
purchase foreach { amount =>
println("Purchased " + amount + " CHF")
}
+{% endtab %}
+{% tab 'Scala 3' for=futures-09 %}
+ val usdQuote = Future { connection.getCurrentValue(USD) }
+ val chfQuote = Future { connection.getCurrentValue(CHF) }
+
+ val purchase = for
+ usd <- usdQuote
+ chf <- chfQuote
+ if isProfitable(usd, chf)
+ yield connection.buy(amount, chf)
+
+ purchase.foreach { amount =>
+ println("Purchased " + amount + " CHF")
+ }
+{% endtab %}
+{% endtabs %}
The `purchase` future is completed only once both `usdQuote`
-and `chfQuote` are completed-- it depends on the values
+and `chfQuote` are completed -- it depends on the values
of both these futures so its own computation cannot begin
earlier.
The for-comprehension above is translated into:
- val purchase = usdQuote flatMap {
+{% tabs for-translation %}
+{% tab 'Scala 2 and 3' for=for-translation %}
+ val purchase = usdQuote.flatMap {
usd =>
- chfQuote
- .withFilter(chf => isProfitable(usd, chf))
- .map(chf => connection.buy(amount, chf))
+ chfQuote
+ .withFilter(chf => isProfitable(usd, chf))
+ .map(chf => connection.buy(amount, chf))
}
+{% endtab %}
+{% endtabs %}
which is a bit harder to grasp than the for-comprehension, but
we analyze it to better understand the `flatMap` operation.
@@ -611,11 +813,15 @@ amount. The `connection.buy` method takes an `amount` to buy and the expected
future to contain `0` instead of the exception, we use the `recover`
combinator:
- val purchase: Future[Int] = rateQuote map {
+{% tabs recover %}
+{% tab 'Scala 2 and 3' for=recover %}
+ val purchase: Future[Int] = rateQuote.map {
quote => connection.buy(amount, quote)
- } recover {
+ }.recover {
case QuoteChangedException() => 0
}
+{% endtab %}
+{% endtabs %}
The `recover` combinator creates a new future which holds the same
result as the original future if it completed successfully. If it did
@@ -640,20 +846,24 @@ the exception from this future, as in the following example which
tries to print US dollar value, but prints the Swiss franc value in
the case it fails to obtain the dollar value:
+{% tabs fallback-to %}
+{% tab 'Scala 2 and 3' for=fallback-to %}
val usdQuote = Future {
connection.getCurrentValue(USD)
- } map {
+ }.map {
usd => "Value: " + usd + "$"
}
val chfQuote = Future {
connection.getCurrentValue(CHF)
- } map {
+ }.map {
chf => "Value: " + chf + "CHF"
}
- val anyQuote = usdQuote fallbackTo chfQuote
+ val anyQuote = usdQuote.fallbackTo(chfQuote)
- anyQuote foreach { println(_) }
+ anyQuote.foreach { println(_) }
+{% endtab %}
+{% endtabs %}
The `andThen` combinator is used purely for side-effecting purposes.
It returns a new future with exactly the same result as the current
@@ -665,17 +875,34 @@ multiple `andThen` calls are ordered, as in the following example
which stores the recent posts from a social network to a mutable set
and then renders all the posts to the screen:
- val allPosts = mutable.Set[String]()
+{% tabs futures-10 class=tabs-scala-version %}
+{% tab 'Scala 2' for=futures-10 %}
+ val allPosts = mutable.Set[String]()
- Future {
- session.getRecentPosts
- } andThen {
- case Success(posts) => allPosts ++= posts
- } andThen {
- case _ =>
- clearAll()
- for (post <- allPosts) render(post)
- }
+ Future {
+ session.getRecentPosts()
+ }.andThen {
+ case Success(posts) => allPosts ++= posts
+ }.andThen {
+ case _ =>
+ clearAll()
+ for (post <- allPosts) render(post)
+ }
+{% endtab %}
+{% tab 'Scala 3' for=futures-10 %}
+ val allPosts = mutable.Set[String]()
+
+ Future {
+ session.getRecentPosts()
+ }.andThen {
+ case Success(posts) => allPosts ++= posts
+ }.andThen {
+ case _ =>
+ clearAll()
+ for post <- allPosts do render(post)
+ }
+{% endtab %}
+{% endtabs %}
In summary, the combinators on futures are purely functional.
Every combinator returns a new future which is related to the
@@ -691,10 +918,20 @@ futures also have projections. If the original future fails, the
fails with a `NoSuchElementException`. The following is an example
which prints the exception to the screen:
+{% tabs futures-11 class=tabs-scala-version %}
+{% tab 'Scala 2' for=futures-11 %}
val f = Future {
2 / 0
}
for (exc <- f.failed) println(exc)
+{% endtab %}
+{% tab 'Scala 3' for=futures-11 %}
+ val f = Future {
+ 2 / 0
+ }
+ for exc <- f.failed do println(exc)
+{% endtab %}
+{% endtabs %}
The for-comprehension in this example is translated to:
@@ -704,10 +941,20 @@ Because `f` is unsuccessful here, the closure is registered to
the `foreach` callback on a newly-successful `Future[Throwable]`.
The following example does not print anything to the screen:
+{% tabs futures-12 class=tabs-scala-version %}
+{% tab 'Scala 2' for=futures-12 %}
val g = Future {
4 / 2
}
for (exc <- g.failed) println(exc)
+{% endtab %}
+{% tab 'Scala 3' for=futures-12 %}
+ val g = Future {
+ 4 / 2
+ }
+ for exc <- g.failed do println(exc)
+{% endtab %}
+{% endtabs %}
+{% tabs install-cs-setup-tabs class=platform-os-options %}
+
+
+{% tab macOS for=install-cs-setup-tabs %}
+Run the following command in your terminal, following the on-screen instructions:
+{% include code-snippet.html language='bash' codeSnippet=site.data.setup-scala.macOS-brew %}
+{% altDetails cs-setup-macos-nobrew "Alternatively, if you don't use Homebrew:" %}
+ On the Apple Silicon (M1, M2, …) architecture:
+ {% include code-snippet.html language='bash' codeSnippet=site.data.setup-scala.macOS-arm64 %}
+ Otherwise, on the x86-64 architecture:
+ {% include code-snippet.html language='bash' codeSnippet=site.data.setup-scala.macOS-x86-64 %}
+{% endaltDetails %}
+{% endtab %}
+
+
+
+{% tab Linux for=install-cs-setup-tabs %}
+ Run the following command in your terminal, following the on-screen instructions.
+
+ On the x86-64 architecture:
+ {% include code-snippet.html language='bash' codeSnippet=site.data.setup-scala.linux-x86-64 %}
+ Otherwise, on the ARM64 architecture:
+ {% include code-snippet.html language='bash' codeSnippet=site.data.setup-scala.linux-arm64 %}
+{% endtab %}
+
+
+
+{% tab Windows for=install-cs-setup-tabs %}
+ Download and execute [the Scala installer for Windows]({{site.data.setup-scala.windows-link}})
+ based on Coursier, and follow the on-screen instructions.
+{% endtab %}
+
+
+
+{% tab Other for=install-cs-setup-tabs defaultTab %}
+
+ Follow the documentation from Coursier on
+ [how to install and run `cs setup`](https://get-coursier.io/docs/cli-installation).
+{% endtab %}
+
+
+{% endtabs %}
+
+
+> You may need to restart your terminal, log out,
+> or reboot in order for the changes to take effect.
+{: .help-info}
+
+
+{% altDetails testing-your-setup 'Testing your setup' %}
+Check your setup with the command `scala -version`, which should output:
+```bash
+$ scala -version
+Scala code runner version: 1.4.3
+Scala version (default): {{site.scala-3-version}}
+```
+{% endaltDetails %}
+
+
+
+Along with managing JVMs, `cs setup` also installs useful command-line tools:
+
+| Commands | Description |
+|----------|-------------|
+| `scalac` | the Scala compiler |
+| `scala`, `scala-cli` | [Scala CLI](https://scala-cli.virtuslab.org), interactive toolkit for Scala |
+| `sbt`, `sbtn` | The [sbt](https://www.scala-sbt.org/) build tool |
+| `amm` | [Ammonite](https://ammonite.io/) is an enhanced REPL |
+| `scalafmt` | [Scalafmt](https://scalameta.org/scalafmt/) is the Scala code formatter |
+
+For more information about `cs`, read
+[coursier-cli documentation](https://get-coursier.io/docs/cli-overview).
+
+> `cs setup` installs the Scala 3 compiler and runner by default (the `scalac` and
+> `scala` commands, respectively). Whether you intend to use Scala 2 or 3,
+> this is usually not an issue because most projects use a build tool that will
+> use the correct version of Scala irrespective of the one installed "globally".
+> Nevertheless, you can always launch a specific version of Scala using
+> ```
+> $ cs launch scala:{{ site.scala-version }}
+> $ cs launch scalac:{{ site.scala-version }}
+> ```
+> If you prefer Scala 2 to be run by default, you can force that version to be installed with:
+> ```
+> $ cs install scala:{{ site.scala-version }} scalac:{{ site.scala-version }}
+> ```
+
+### ...or manually
+
+You only need two tools to compile, run, test, and package a Scala project: Java 8 or 11,
+and Scala CLI.
+To install them manually:
+
+1. if you don't have Java 8 or 11 installed, download
+ Java from [Oracle Java 8](https://www.oracle.com/java/technologies/javase-jdk8-downloads.html), [Oracle Java 11](https://www.oracle.com/java/technologies/javase-jdk11-downloads.html),
+ or [AdoptOpenJDK 8/11](https://adoptopenjdk.net/). Refer to [JDK Compatibility](/overviews/jdk-compatibility/overview.html) for Scala/Java compatibility detail.
+1. Install [Scala CLI](https://scala-cli.virtuslab.org/install)
+
+## Using the Scala CLI
+
+In a directory of your choice, which we will call ``, create a file named `hello.scala` with the following code:
+```scala
+//> using scala {{site.scala-3-version}}
+
+@main
+def hello(): Unit =
+ println("Hello, World!")
+```
+
+You can define a method with the `def` keyword and mark it as a "main" method with the `@main` annotation, designating it as
+the entry point in program execution. The method's type is `Unit`, which means it does not return a value. `Unit`
+can be thought of as an analogue to the `void` keyword found in other languages. The `println` method will print the `"Hello, World!"`
+string to standard output.
+
+To run the program, execute `scala run hello.scala` command from a terminal, within the `` directory. The file will be compiled and executed, with console output
+similar to following:
+```
+$ scala run hello.scala
+Compiling project (Scala {{site.scala-3-version}}, JVM (20))
+Compiled project (Scala {{site.scala-3-version}}, JVM (20))
+Hello, World!
+```
+
+### Handling command-line arguments
+
+Rewrite the `hello.scala` file so that the program greets the person running it.
+```scala
+//> using scala {{site.scala-3-version}}
+
+@main
+def hello(name: String): Unit =
+ println(s"Hello, $name!")
+```
+
+The `name` argument is expected to be provided when executing the program, and if it's not found, the execution will fail.
+The `println` method receives an interpolated string, as indicated by the `s` letter preceding its content. `$name` will be substituted by
+the content of the `name` argument.
+
+To pass the arguments when executing the program, put them after `--`:
+```
+$ scala run hello.scala -- Gabriel
+Compiling project (Scala {{site.scala-3-version}}, JVM (20))
+Compiled project (Scala {{site.scala-3-version}}, JVM (20))
+Hello, Gabriel!
+```
+
+You can read more about [main methods](/scala3/book/methods-main-methods.html) and [string interpolation](/scala3/book/string-interpolation.html) in the Scala Book.
+
+### Adding dependencies
+
+We now write a program that will count the files and directories present in its working directory.
+We use the [os-lib](https://github.com/com-lihaoyi/os-lib) library from the [Scala toolkit](/toolkit/introduction.html)
+for that purpose. A dependency on the library can be added with the `//> using` directive. Put the following code in `counter.scala`.
+```scala
+//> using scala {{site.scala-3-version}}
+//> using dep "com.lihaoyi::os-lib:0.11.4"
+
+@main
+def countFiles(): Unit =
+ val paths = os.list(os.pwd)
+ println(paths.length)
+```
+
+In the code above, `os.pwd` returns the current working directory. We pass it to `os.list`, which returns a sequence
+of paths directly within the directory passed as an argument. We use a `val` to declare an immutable value, in this example storing the
+sequence of paths.
+
+Execute the program. The dependency will be automatically downloaded. The execution should result in a similar output:
+```
+$ scala run counter.scala
+Compiling project (Scala {{site.scala-3-version}}, JVM (20))
+Compiled project (Scala {{site.scala-3-version}}, JVM (20))
+4
+```
+The printed number should be 4: `hello.scala`, `counter.scala` and two hidden directories created automatically when a program is executed:
+`.bsp` containing information about project used by IDEs, and `.scala-build` containing the results of compilation.
+
+As it turns out, the `os-lib` library is a part of Scala Toolkit, a collection of libraries recommended for tasks like testing,
+operating system interaction or handling JSONs. You can read more about the libraries included in the toolkit [here](/toolkit/introduction.html).
+To include the toolkit libraries, use the `//> using toolkit 0.5.0` directive:
+```scala
+//> using scala {{site.scala-3-version}}
+//> using toolkit 0.5.0
+
+@main
+def countFiles(): Unit =
+ val paths = os.list(os.pwd)
+ println(paths.length)
+```
+
+This program is identical to the one above. However, other toolkit libraries will also be available to use, should you need them.
+
+### Using the REPL
+
+You can execute code interactively using the REPL provided by the `scala` command. Execute `scala` in the console without any arguments.
+```
+$ scala
+Welcome to Scala {{site.scala-3-version}} (20-ea, Java OpenJDK 64-Bit Server VM).
+Type in expressions for evaluation. Or try :help.
+
+scala>
+```
+
+Write a line of code to be executed and press enter.
+```
+scala> println("Hello, World!")
+Hello, World!
+
+scala>
+```
+
+The result will be printed immediately after executing the line. You can declare values:
+```
+scala> val i = 1
+val i: Int = 1
+
+scala>
+```
+
+A new value of type `Int` has been created. If you provide an expression that can be evaluated, its result will be stored in an automatically created value.
+```
+scala> i + 3
+val res0: Int = 4
+
+scala>
+```
+You can exit the REPL with `:exit`.
+
+## Using an IDE
+
+> You can read a short summary of Scala IDEs on [a dedicated page](/getting-started/scala-ides.html).
+
+Let's use an IDE to open the code we wrote above. The most popular ones are [IntelliJ](https://www.jetbrains.com/idea/) and
+[VSCode](https://scalameta.org/metals/docs/editors/vscode).
+They both offer rich IDE features, but you can still use [many other editors](https://scalameta.org/metals/docs/editors/overview.html).
+
+### Prepare the project
+
+First, remove all the using directives, and put them in a single file `project.scala` in the `` directory.
+This makes it easier to import as a project in an IDE:
+
+```scala
+//> using scala {{site.scala-3-version}}
+//> using toolkit 0.5.0
+```
+
+> Optionally, you can re-initialise the necessary IDE files from within the `` directory with the command `scala setup-ide .`, but these files will already exist if you have previously run the project with the Scala CLI `run` command.
+
+### Using IntelliJ
+
+1. Download and install [IntelliJ Community Edition](https://www.jetbrains.com/help/idea/installation-guide.html)
+1. Install the Scala plugin by following [the instructions on how to install IntelliJ plugins](https://www.jetbrains.com/help/idea/discover-intellij-idea-for-scala.html)
+1. Open the `` directory, which should be imported automatically as a BSP project.
+
+### Using VSCode with Metals
+
+1. Download [VSCode](https://code.visualstudio.com/Download)
+1. Install the Metals extension from [the Marketplace](https://marketplace.visualstudio.com/items?itemName=scalameta.metals)
+1. Next, open the `` directory in VSCode. Metals should activate and begin importing the project automatically.
+
+### Play with the source code
+
+View these three files in your IDE:
+
+- _project.scala_
+- _hello.scala_
+- _counter.scala_
+
+You should notice the benefits of an IDE, such as syntax highlighting, and smart code interactions.
+For example you can place the cursor over any part of the code, such as `os.pwd` in _counter.scala_ and documentation for the method will appear.
+
+When you run your project in the next step, the configuration in _project.scala_ will be used to run the code in the other source files.
+
+### Run the code
+
+If you’re comfortable using your IDE, you can run the code in _counter.scala_ from your IDE.
+Attached to the `countFiles` method should be a prompt button. Click it to run the method. This should run without issue.
+The `hello` method in _hello.scala_ needs arguments however, so will require extra configuration via the IDE to provide the argument.
+
+Otherwise, you can run either application from the IDE's built-in terminal as described in above sections.
+
+## Next steps
+
+Now that you have tasted a little bit of Scala, you can further explore the language itself, consider checking out:
+
+* [The Scala Book](/scala3/book/introduction.html) (see the Scala 2 version [here](/overviews/scala-book/introduction.html)), which provides a set of short lessons introducing Scala’s main features.
+* [The Tour of Scala](/tour/tour-of-scala.html) for bite-sized introductions to Scala's features.
+* [Learning Courses](/online-courses.html), which includes online interactive tutorials and courses.
+* [Our list of some popular Scala books](/books.html).
+
+There are also other tutorials for other build-tools you can use with Scala:
+* [Getting Started with Scala and sbt](/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.html)
+* [Using Scala and Maven](/tutorials/scala-with-maven.html)
+
+## Getting Help
+There are a multitude of mailing lists and real-time chat rooms in case you want to quickly connect with other Scala users. Check out our [community](https://scala-lang.org/community/) page for a list of these resources, and for where to reach out for help.
diff --git a/_getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.md b/_overviews/getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.md
similarity index 89%
rename from _getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.md
rename to _overviews/getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.md
index d1eab7d4ae..6dc397f089 100644
--- a/_getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.md
+++ b/_overviews/getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.md
@@ -2,7 +2,7 @@
title: Building a Scala Project with IntelliJ and sbt
layout: singlepage-overview
partof: building-a-scala-project-with-intellij-and-sbt
-languages: [ja]
+languages: [ja, ru, uk]
disqus: true
previous-page: getting-started/intellij-track/getting-started-with-scala-in-intellij
next-page: testing-scala-in-intellij-with-scalatest
@@ -54,16 +54,15 @@ but here's a glance at what everything is for:
1. On the **Project** panel on the left, expand `SbtExampleProject` => `src`
=> `main`
1. Right-click `scala` and select **New** => **Package**
-1. Name the package `example` and click **OK**.
-1. Right-click the package `example` and select **New** => **Scala class**.
-1. Name the class `Main` and change the **Kind** to `object`.
+1. Name the package `example` and click **OK** (or just press the Enter or Return key).
+1. Right-click the package `example` and select **New** => **Scala class** (if you don't see this option, right-click the `SbtExampleProject`, click **Add Frameworks Support**, select **Scala** and proceed)
+1. Name the class `Main` and change the **Kind** to `Object`.
1. Change the code in the class to the following:
```
-object Main extends App {
+@main def run() =
val ages = Seq(42, 75, 29, 64)
println(s"The oldest person is ${ages.max}")
-}
```
Note: IntelliJ has its own implementation of the Scala compiler, and sometimes your
@@ -105,6 +104,7 @@ Continue to the next tutorial in the _getting started with IntelliJ_ series, and
**or**
+* [The Scala Book](/scala3/book/introduction.html), which provides a set of short lessons introducing Scala’s main features.
+* [The Tour of Scala](/tour/tour-of-scala.html) for bite-sized introductions to Scala's features.
- Continue learning Scala interactively online on
[Scala Exercises](https://www.scala-exercises.org/scala_tutorial).
-- Learn about Scala's features in bite-sized pieces by stepping through our [Tour of Scala]({{ site.baseurl }}/tour/tour-of-scala.html).
diff --git a/_getting-started/intellij-track/getting-started-with-scala-in-intellij.md b/_overviews/getting-started/intellij-track/getting-started-with-scala-in-intellij.md
similarity index 61%
rename from _getting-started/intellij-track/getting-started-with-scala-in-intellij.md
rename to _overviews/getting-started/intellij-track/getting-started-with-scala-in-intellij.md
index 2e24d76826..8bbd163a00 100644
--- a/_getting-started/intellij-track/getting-started-with-scala-in-intellij.md
+++ b/_overviews/getting-started/intellij-track/getting-started-with-scala-in-intellij.md
@@ -2,7 +2,7 @@
title: Getting Started with Scala in IntelliJ
layout: singlepage-overview
partof: getting-started-with-scala-in-intellij
-languages: [ja]
+languages: [ja, ru, uk]
disqus: true
next-page: building-a-scala-project-with-intellij-and-sbt
@@ -13,36 +13,40 @@ In this tutorial, we'll see how to build a minimal Scala project using IntelliJ
IDE with the Scala plugin. In this guide, IntelliJ will download Scala for you.
## Installation
-1. Make sure you have the Java 8 JDK (also known as 1.8)
- * Run `javac -version` on the command line and make sure you see
- `javac 1.8.___`
- * If you don't have version 1.8 or higher, [install the JDK](https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
-1. Next, download and install [IntelliJ Community Edition](https://www.jetbrains.com/idea/download/)
+1. Make sure you have the Java 8 JDK (also known as 1.8) or newer:
+ * run `javac -version` on the command line to check the Java version,
+ * if you don't have version 1.8 or higher, [install the JDK](https://www.oracle.com/java/technologies/downloads/).
+1. Next, download and install [IntelliJ Community Edition](https://www.jetbrains.com/idea/download/).
1. Then, after starting up IntelliJ, you can download and install the Scala plugin by following the instructions on
-[how to install IntelliJ plugins](https://www.jetbrains.com/help/idea/installing-updating-and-uninstalling-repository-plugins.html) (search for "Scala" in the plugins menu.)
+[how to install IntelliJ plugins](https://www.jetbrains.com/help/idea/managing-plugins.html) (search for "Scala" in the plugins menu.)
When we create the project, we'll install the latest version of Scala.
Note: If you want to open an existing Scala project, you can click **Open**
when you start IntelliJ.
## Creating the Project
-1. Open up IntelliJ and click **File** => **New** => **Project**
-1. On the left panel, select Scala. On the right panel, select IDEA.
-1. Name the project **HelloWorld**
+1. Open up IntelliJ and click **File** => **New** => **Project**.
+1. Name the project **HelloWorld**.
+1. Select **Scala** from the **Language** list.
+1. Select **IntelliJ** from the **Build system** list.
1. Assuming this is your first time creating a Scala project with IntelliJ,
you'll need to install a Scala SDK. To the right of the Scala SDK field,
click the **Create** button.
1. Select the highest version number (e.g. {{ site.scala-version }}) and click **Download**. This might
take a few minutes but subsequent projects can use the same SDK.
-1. Once the SDK is created and you're back to the "New Project" window click **Finish**.
+1. Once the SDK is created, and you're back to the "New Project" window, click **Create**.
## Writing code
1. On the **Project** pane on the left, right-click `src` and select
-**New** => **Scala class**. If you don't see **Scala class**, right-click on **HelloWorld** and click on **Add Framework Support...**, select **Scala** and proceed. If you see **Error: library is not specified**, you can either click download button, or select the library path manually.
+**New** => **Scala class**. If you don't see **Scala class**, right-click on **HelloWorld** and click on **Add Framework Support...**, select **Scala** and proceed. If you see **Error: library is not specified**, you can either click download button, or select the library path manually. If you only see **Scala Worksheet** try expanding the `src` folder and its `main` subfolder, and right-click on the `scala` folder.
1. Name the class `Hello` and change the **Kind** to `object`.
-1. Change the code in the class to the following:
+1. Change the code in the file to the following:
+
+{% tabs hello-world-entry-point class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=hello-world-entry-point %}
```
object Hello extends App {
@@ -50,10 +54,42 @@ object Hello extends App {
}
```
+{% endtab %}
+
+{% tab 'Scala 3' for=hello-world-entry-point %}
+
+```
+@main def hello(): Unit =
+ println("Hello, World!")
+```
+
+In Scala 3, you can remove the object `Hello` and define a top-level method
+`hello` instead, which you annotate with `@main`.
+
+{% endtab %}
+
+{% endtabs %}
+
## Running it
+
+{% tabs hello-world-run class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=hello-world-run %}
+
* Right click on `Hello` in your code and select **Run 'Hello'**.
* You're done!
+{% endtab %}
+
+{% tab 'Scala 3' for=hello-world-run %}
+
+* Right click on `hello` in your code and select **Run 'hello'**.
+* You're done!
+
+{% endtab %}
+
+{% endtabs %}
+
## Experimenting with Scala
A good way to try out code samples is with Scala Worksheets
@@ -62,14 +98,18 @@ A good way to try out code samples is with Scala Worksheets
2. Name your new Scala worksheet "Mathematician".
3. Enter the following code into the worksheet:
+{% tabs square %}
+{% tab 'Scala 2 and 3' for=square %}
```
-def square(x: Int) = x * x
+def square(x: Int): Int = x * x
square(2)
```
+{% endtab %}
+{% endtabs %}
As you change your code, you'll notice that it gets evaluated
-in the right pane. If you do not see a right pane, right click on your Scala worksheet in the Project pane, and click on Evaluate Worksheet.
+in the right pane. If you do not see a right pane, right-click on your Scala worksheet in the Project pane, and click on Evaluate Worksheet.
## Next Steps
diff --git a/_getting-started/intellij-track/testing-scala-in-intellij-with-scalatest.md b/_overviews/getting-started/intellij-track/testing-scala-in-intellij-with-scalatest.md
similarity index 83%
rename from _getting-started/intellij-track/testing-scala-in-intellij-with-scalatest.md
rename to _overviews/getting-started/intellij-track/testing-scala-in-intellij-with-scalatest.md
index 77d0b3341a..8a51eca2e0 100644
--- a/_getting-started/intellij-track/testing-scala-in-intellij-with-scalatest.md
+++ b/_overviews/getting-started/intellij-track/testing-scala-in-intellij-with-scalatest.md
@@ -2,7 +2,7 @@
title: Testing Scala in IntelliJ with ScalaTest
layout: singlepage-overview
partof: testing-scala-in-intellij-with-scalatest
-languages: [ja]
+languages: [ja, ru, uk]
disqus: true
previous-page: building-a-scala-project-with-intellij-and-sbt
@@ -20,37 +20,34 @@ This assumes you know [how to build a project in IntelliJ](building-a-scala-proj
1. Add the ScalaTest dependency:
1. Add the ScalaTest dependency to your `build.sbt` file:
```
- libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.8" % Test
+ libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.19" % Test
```
1. If you get a notification "build.sbt was changed", select **auto-import**.
1. These two actions will cause `sbt` to download the ScalaTest library.
- 1. Wait for the `sbt` sync to finish; otherwise, `FunSuite` and `test()` will be
+ 1. Wait for the `sbt` sync to finish; otherwise, `AnyFunSuite` and `test()` will be
unrecognized.
1. On the project pane on the left, expand `src` => `main`.
1. Right-click on `scala` and select **New** => **Scala class**.
-1. Call it `CubeCalculator`, change the **Kind** to `object`, and click **OK**.
+1. Call it `CubeCalculator`, change the **Kind** to `object`, and hit enter or double-click on `object`.
1. Replace the code with the following:
```
- object CubeCalculator extends App {
- def cube(x: Int) = {
+ object CubeCalculator:
+ def cube(x: Int) =
x * x * x
- }
- }
```
## Creating a test
1. On the project pane on the left, expand `src` => `test`.
1. Right-click on `scala` and select **New** => **Scala class**.
-1. Name the class `CubeCalculatorTest` and click **OK**.
+1. Name the class `CubeCalculatorTest` and hit enter or double-click on `class`.
1. Replace the code with the following:
```
- import org.scalatest.FunSuite
+ import org.scalatest.funsuite.AnyFunSuite
- class CubeCalculatorTest extends FunSuite {
+ class CubeCalculatorTest extends AnyFunSuite:
test("CubeCalculator.cube") {
assert(CubeCalculator.cube(3) === 27)
}
- }
```
1. In the source code, right-click `CubeCalculatorTest` and select
**Run 'CubeCalculatorTest'**.
@@ -60,9 +57,9 @@ This assumes you know [how to build a project in IntelliJ](building-a-scala-proj
Let's go over this line by line:
* `class CubeCalculatorTest` means we are testing the object `CubeCalculator`
-* `extends FunSuite` lets us use functionality of ScalaTest's FunSuite class
+* `extends AnyFunSuite` lets us use functionality of ScalaTest's AnyFunSuite class
such as the `test` function
-* `test` is function that comes from the FunSuite library that collects
+* `test` is a function that comes from the FunSuite library that collects
results from assertions within the function body.
* `"CubeCalculator.cube"` is a name for the test. You can call it anything but
one convention is "ClassName.methodName".
diff --git a/_getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.md b/_overviews/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.md
similarity index 78%
rename from _getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.md
rename to _overviews/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.md
index 5c7bc37325..11c90825ea 100644
--- a/_getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.md
+++ b/_overviews/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.md
@@ -2,7 +2,7 @@
title: Getting Started with Scala and sbt on the Command Line
layout: singlepage-overview
partof: getting-started-with-scala-and-sbt-on-the-command-line
-languages: [ja]
+languages: [ja, ru, uk]
disqus: true
next-page: testing-scala-with-sbt-on-the-command-line
@@ -26,6 +26,10 @@ We assume you know how to use a terminal.
* [Linux](https://www.scala-sbt.org/1.x/docs/Installing-sbt-on-Linux.html)
## Create the project
+
+{% tabs sbt-welcome-1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=sbt-welcome-1 %}
+
1. `cd` to an empty folder.
1. Run the following command `sbt new scala/hello-world.g8`.
This pulls the 'hello-world' template from GitHub.
@@ -34,6 +38,21 @@ It will also create a `target` folder, which you can ignore.
create a project called "hello-world".
1. Let's take a look at what just got generated:
+{% endtab %}
+{% tab 'Scala 3' for=sbt-welcome-1 %}
+
+1. `cd` to an empty folder.
+1. Run the following command `sbt new scala/scala3.g8`.
+This pulls the 'scala3' template from GitHub.
+It will also create a `target` folder, which you can ignore.
+1. When prompted, name the application `hello-world`. This will
+create a project called "hello-world".
+1. Let's take a look at what just got generated:
+
+{% endtab %}
+{% endtabs %}
+
+
```
- hello-world
- project (sbt uses this to install and manage plugins and dependencies)
@@ -69,18 +88,22 @@ extra functionality to our apps.
1. Open up `build.sbt` and add the following line:
```
-libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2"
+libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "2.1.1"
```
Here, `libraryDependencies` is a set of dependencies, and by using `+=`,
we're adding the [scala-parser-combinators](https://github.com/scala/scala-parser-combinators) dependency to the set of dependencies that sbt will go
and fetch when it starts up. Now, in any Scala file, you can import classes,
-objects, etc, from scala-parser-combinators with a regular import.
+objects, etc, from `scala-parser-combinators` with a regular import.
You can find more published libraries on
[Scaladex](https://index.scala-lang.org/), the Scala library index, where you
can also copy the above dependency information for pasting into your `build.sbt`
file.
+> **Note for Java Libraries:** For a regular Java library, you should only use one percent (`%`) between the
+> organization name and artifact name. Double percent (`%%`) is a specialisation for Scala libraries.
+> You can learn more about the reason for this in the [sbt documentation][sbt-docs-lib-dependencies].
+
## Next steps
Continue to the next tutorial in the _getting started with sbt_ series, and learn about [testing Scala code with sbt in the command line](testing-scala-with-sbt-on-the-command-line.html).
@@ -90,3 +113,5 @@ Continue to the next tutorial in the _getting started with sbt_ series, and lear
- Continue learning Scala interactively online on
[Scala Exercises](https://www.scala-exercises.org/scala_tutorial).
- Learn about Scala's features in bite-sized pieces by stepping through our [Tour of Scala]({{ site.baseurl }}/tour/tour-of-scala.html).
+
+[sbt-docs-lib-dependencies]: https://www.scala-sbt.org/1.x/docs/Library-Dependencies.html#Getting+the+right+Scala+version+with
diff --git a/_getting-started/sbt-track/testing-scala-with-sbt-on-the-command-line.md b/_overviews/getting-started/sbt-track/testing-scala-with-sbt-on-the-command-line.md
similarity index 90%
rename from _getting-started/sbt-track/testing-scala-with-sbt-on-the-command-line.md
rename to _overviews/getting-started/sbt-track/testing-scala-with-sbt-on-the-command-line.md
index 345324c990..9a446b1c76 100644
--- a/_getting-started/sbt-track/testing-scala-with-sbt-on-the-command-line.md
+++ b/_overviews/getting-started/sbt-track/testing-scala-with-sbt-on-the-command-line.md
@@ -2,7 +2,7 @@
title: Testing Scala with sbt and ScalaTest on the Command Line
layout: singlepage-overview
partof: testing-scala-with-sbt-on-the-command-line
-languages: [ja]
+languages: [ja, ru, uk]
disqus: true
previous-page: getting-started-with-scala-and-sbt-on-the-command-line
@@ -11,7 +11,7 @@ redirect_from: "/getting-started-sbt-track/testing-scala-with-sbt-on-the-command
There are multiple libraries and testing methodologies for Scala,
but in this tutorial, we'll demonstrate one popular option from the ScalaTest framework
-called [FunSuite](https://www.scalatest.org/getting_started_with_fun_suite).
+called [AnyFunSuite](https://www.scalatest.org/scaladoc/3.2.2/org/scalatest/funsuite/AnyFunSuite.html).
We assume you know [how to create a Scala project with sbt](getting-started-with-scala-and-sbt-on-the-command-line.html).
## Setup
@@ -46,9 +46,9 @@ sbt test
named after the object we're testing.
```
- import org.scalatest.FunSuite
+ import org.scalatest.funsuite.AnyFunSuite
- class CubeCalculatorTest extends FunSuite {
+ class CubeCalculatorTest extends AnyFunSuite {
test("CubeCalculator.cube") {
assert(CubeCalculator.cube(3) === 27)
}
@@ -58,9 +58,9 @@ named after the object we're testing.
Let's go over this line by line.
* `class CubeCalculatorTest` means we are testing the object `CubeCalculator`
-* `extends FunSuite` lets us use functionality of ScalaTest's FunSuite class
+* `extends AnyFunSuite` lets us use functionality of ScalaTest's AnyFunSuite class
such as the `test` function
-* `test` is function that comes from FunSuite that collects
+* `test` is function that comes from AnyFunSuite that collects
results from assertions within the function body.
* `"CubeCalculator.cube"` is a name for the test. You can call it anything but
one convention is "ClassName.methodName".
@@ -72,9 +72,9 @@ indeed 27. The `===` is part of ScalaTest and provides clean error messages.
1. Add another test block with its own `assert` statement that checks for the cube of `0`.
```
- import org.scalatest.FunSuite
+ import org.scalatest.funsuite.AnyFunSuite
- class CubeCalculatorTest extends FunSuite {
+ class CubeCalculatorTest extends AnyFunSuite {
test("CubeCalculator.cube 3 should be 27") {
assert(CubeCalculator.cube(3) === 27)
}
diff --git a/_overviews/getting-started/scala-ides.md b/_overviews/getting-started/scala-ides.md
new file mode 100644
index 0000000000..9f210d4b1e
--- /dev/null
+++ b/_overviews/getting-started/scala-ides.md
@@ -0,0 +1,55 @@
+---
+layout: singlepage-overview
+title: Scala IDEs
+
+partof: scala-ides
+
+permalink: /getting-started/:title.html
+
+keywords:
+- Scala
+- IDE
+- JetBrains
+- IntelliJ
+- VSCode
+- Metals
+---
+
+It's of course possible to write Scala code in any editor and compile and run the code from the command line. But most developers prefer to use an IDE (Integrated Development Environment), especially for coding anything beyond simple exercises.
+
+The following IDEs are available for Scala:
+
+## IntelliJ IDEA + Scala plugin
+
+[https://jetbrains.com/scala](https://jetbrains.com/scala)
+
+
+
+IntelliJ IDEA is a cross-platform IDE developed by JetBrains that provides a consistent experience for a wide range of programming languages and technologies. It also supports Scala through the IntelliJ Scala Plugin, which is being developed at JetBrains. First, install IntelliJ IDEA Community Edition (unless you don't already use the Ultimate edition) and then add the IntelliJ Scala Plugin.
+
+IntelliJ IDEA and Scala Plugin will assist you in virtually every part of a Scala software developer's work. Use it if you like a solid integrated experience, sane default settings, and tested solutions.
+
+For more information, check out our tutorial [Getting Started with Scala in IntelliJ](/getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.html)
+
+## Visual Studio Code + Metals
+
+[https://scalameta.org/metals](https://scalameta.org/metals)
+
+
+
+Visual Studio Code, commonly called VS Code, is a source code editor from Microsoft. To add Scala support, you install an extension called Metals.
+
+(Why "Metals"? Because the underlying technologies are Scalameta and LSP ([Language Server Protocol](https://microsoft.github.io/language-server-protocol/)), and "Meta" + "LS" equals "Metals".)
+
+In contrast to IntelliJ IDEA + Scala Plugin, VS Code + Metals is aimed at people who like to get feedback and code intelligence straight from the compiler, which enables them to also try out experimental Scala features.
+
+## Your favorite editor + Metals
+
+Metals is most commonly used with VS Code, but it's also available for the following popular editors:
+
+* Emacs
+* Vim
+* Sublime Text
+* Helix
+
+as documented [here](https://scalameta.org/metals/docs/#editor-support).
diff --git a/_overviews/index.md b/_overviews/index.md
index 32a2fcbb7f..53ad207975 100644
--- a/_overviews/index.md
+++ b/_overviews/index.md
@@ -2,8 +2,11 @@
layout: overviews
partof: overviews
title: Guides and Overviews
-languages: [ja, zh-cn, ru]
+languages: [ja, zh-cn, ru, uk]
permalink: /overviews/:title.html
+redirect_from:
+ - /scala3/guides.html
+ - /guides.html
---
diff --git a/_overviews/jdk-compatibility/overview.md b/_overviews/jdk-compatibility/overview.md
index 09c2ef46cc..c42ee96090 100644
--- a/_overviews/jdk-compatibility/overview.md
+++ b/_overviews/jdk-compatibility/overview.md
@@ -4,41 +4,67 @@ title: JDK Compatibility
permalink: /overviews/jdk-compatibility/overview.html
---
-Scala's primary platform is the Java Virtual Machine (JVM). (Other supported platforms: [Scala.js](https://www.scala-js.org/), [Scala Native](https://scala-native.readthedocs.io/).)
+Scala's primary platform is the Java Virtual Machine (JVM). (Other supported platforms: [Scala.js](https://www.scala-js.org/), [Scala Native](https://scala-native.org/).)
Sometimes new JVM and JDK (Java Development Kit) versions require us to update Scala to remain compatible.
-## Version compatibility table
+## Scala compatibility table
-| JDK version | Minimum Scala versions | Recommended Scala versions |
-|:-----------:|:---------------------------------|:-----------------------------------------------------------|
-| 13, 14 | 2.13.2, 2.12.11 | 2.13.3, 2.12.12 |
-| 12 | 2.13.1, 2.12.9 | 2.13.3, 2.12.12 |
-| 11 | 2.13.0, 2.12.4, 2.11.12 | 2.13.3, 2.12.12, 2.11.12 |
-| 8 | 2.13.0, 2.12.0, 2.11.0, 2.10.2 | 2.13.3, 2.12.12, 2.11.12, 2.10.7 |
-| 6, 7 | 2.11.0, 2.10.0 | 2.11.12, 2.10.7 |
+Minimum Scala versions:
-Even when a version combination isn't listed as supported, most features may still work. (But Scala 2.12+ definitely doesn't work at all on JDK 6 or 7.)
+| JDK | 3 | 3 LTS | 2.13 | 2.12 | 2.11 |
+|:-----------:|:--------:|:--------:|:---------:|:---------:|:----------:|
+| 25 (ea) | 3.7.1 | 3.3.6 | 2.13.17* | 2.12.21* | |
+| 24 | 3.6.4 | 3.3.6 | 2.13.16 | 2.12.21* | |
+| 23 | 3.6.2 | 3.3.5 | 2.13.15 | 2.12.20 | |
+| 22 | 3.4.0 | 3.3.4 | 2.13.13 | 2.12.19 | |
+| 21 (LTS) | 3.4.0 | 3.3.1 | 2.13.11 | 2.12.18 | |
+| 17 (LTS) | 3.0.0 | 3.3.0 | 2.13.6 | 2.12.15 | |
+| 11 (LTS) | 3.0.0 | 3.3.0 | 2.13.0 | 2.12.4 | 2.11.12 |
+| 8 (LTS) | 3.0.0 | 3.3.0 | 2.13.0 | 2.12.0 | 2.11.0 |
-In general, Scala works on JDK 11+, including GraalVM, but it probably won't take special advantage of features that were added after JDK 8. See [below](#jdk-11-compatibility-notes).
+\* = forthcoming; support available in [nightly builds](https://stackoverflow.com/q/40622878/86485)
-Lightbend offers [commercial support](https://www.lightbend.com/lightbend-platform-subscription) for Scala. The linked page includes contact information for inquiring about supported and recommended versions.
+Even when a version combination isn't listed as supported, most features might still work.
+
+Using the latest patch version of your chosen Scala version line is always recommended.
+
+Akka offers [commercial support](https://akka.io/pricing) for Scala 2. The linked page includes contact information for inquiring about supported and recommended versions.
+
+## Tooling compatibility table
+
+Minimum working versions:
+
+| JDK | scala-cli | sbt | mill |
+|:-----------:|:----------:|:---------:|:-----------|
+| 23 | 1.4.1 | 1.9.0 | 0.11.8 |
+| 21 (LTS) | 1.0.0 | 1.9.0 | 0.11.5 |
+| 17 (LTS) | 1.0.0 | 1.6.0 | 0.7.0 |
+| 11 (LTS) | 1.0.0 | 1.1.0 | 0.1.5 |
+| 8 (LTS) | 1.0.0 | 1.0.0 | 0.1.0 |
+
+Even when a version combination isn't listed as supported, most features might still work.
+
+Using a different build tool, such as Gradle or Maven? We invite pull
+requests adding additional columns to this table.
## Running versus compiling
-We generally recommend JDK 8 or 11 for *compiling* Scala code. Since the JVM tends to be backward compatible, it is usually safe to use a newer JVM for *running* your code, especially if you are not using JVM features designated "experimental" or "unsafe".
+JDK 8, 11, 17, and 21 are all reasonable choices both for *compiling* and *running* Scala code.
+
+Since the JVM is normally backwards compatible, it is usually safe to use a newer JVM for *running* your code than the one it was compiled on, especially if you are not using JVM features designated "experimental" or "unsafe".
-If you compile on JDK 11+ but have users on JDK 8, additional care is needed to avoid using APIs and features that don't exist in 8. Therefore, compiling on 8 may be the safer choice. Some Scala developers use JDK 11+ for their daily work but do release builds on JDK 8.
+JDK 8 remains in use at some shops (as of 2023), but usage is declining and some projects are dropping support. If you compile on JDK 11+ but want to allow your users to stay on 8, additional care is needed to avoid using APIs and features that don't exist in 8. (For this reason, some Scala developers use a newer JDK for their daily work but do release builds on JDK 8.)
## Long Term Support (LTS) versions
After Java 8, Oracle introduced the concept of LTS versions of the JDK. These versions will remain supported (by Oracle, and likely by the rest of the ecosystem, including Scala) for longer than the versions in between. See .
-JDK 8 and 11 are LTS versions. The next LTS version will be JDK 17, planned for September 2021.
+JDK 8, 11, 17, and 21 are LTS versions. (The next LTS version will be 25.)
-Scala provides experimental support for running the Scala compiler on non-LTS versions of the JDK. The current LTS versions are normally tested in our CI matrix and by the Scala community build. We may also test non-LTS versions, but any issues found there are considered lower priority, and will not be considered release blockers. (Lightbend may be able to offer faster resolution of issues like this under commercial support.)
+Scala provides experimental support for running the Scala compiler on non-LTS versions of the JDK. The current LTS versions are normally tested in our CI matrix and by the Scala community build. We may also test non-LTS versions, but any issues found there are considered lower priority, and will not be considered release blockers. (The Scala team at Akka may be able to offer faster resolution of issues like this under commercial support.)
-As already mentioned, Scala code compiled on JDK 8 should run without problems in later JVMs. We will give higher priority to bugs that break this property. (For example, in the 2.13.x series we intend to provide support for JPMS module access checks, to ensure your code won't incur `LinkageErrors` due to module access violations.)
+As already mentioned, Scala code compiled on JDK 8 should run without problems in later JVMs. We will give higher priority to bugs that break this property. (For example, in 2.13.x we might eventually provide support for JPMS module access checks, to ensure your code won't incur `LinkageErrors` due to module access violations.)
## JDK vendors and distributions
@@ -46,41 +72,88 @@ In almost every case, you're free to use the JDK and JVM of your choice.
JDK 8 users typically use the Oracle JDK or some flavor of OpenJDK.
-Most JDK 11+ users are using either OpenJDK or GraalVM.
+Most JDK 11+ users are using OpenJDK, or GraalVM which runs in the context of OpenJDK. GraalVM performs well on the Scala benchmarks, and it benefits from GraalVM runtime and runs faster too.
-OpenJDK comes in various flavors, offered by different providers. We build and test Scala using [AdoptOpenJDK](https://adoptopenjdk.net) in particular, but the differences are unlikely to matter to most users.
+OpenJDK comes in various flavors, offered by different providers. We build and test Scala using [Temurin](https://adoptium.net) primarily, but the differences are unlikely to matter to most users.
## JDK 11 compatibility notes
-Although the table above jumps from 8 to 11, JDK 9 and 10 will probably also work wherever 11 does. But unlike 9 and 10, 11 is an LTS release, so 11 is what we actually test on and recommend.
+The Scala test suite and Scala community build are green on JDK 11.
-The Scala compiler does not enforce the restrictions of the Java Platform Module System, which means that code that typechecks may incur linkage errors at runtime. Scala 2.13.x will eventually provide [rudimentary support](https://github.com/scala/scala/pull/7218) for this (perhaps only in nightlies built on JDK 11).
+In general, Scala works on JDK 11+, including GraalVM, but may not take special advantage of features that were added after JDK 8.
-For sbt users, JDK 11 support requires minimum sbt version 1.1.0. sbt 1.3.9 or newer is recommended. (If you are still on the 0.13.x series, use 0.13.18.)
+For example, the Scala compiler does not enforce the restrictions of the Java Platform Module System, which means that code that typechecks may incur linkage errors at runtime. Scala 2.13.x will eventually provide [rudimentary support](https://github.com/scala/scala/pull/7218) for this (perhaps only in nightlies built on JDK 11).
-To track progress on JDK 11 related issues, watch:
+To track progress on JDK 11 related issues in Scala, watch:
* the ["Support JDK 11"](https://github.com/scala/scala-dev/issues/139 "scala/scala-dev #139") issue
* the [jdk11 label](https://github.com/scala/bug/labels/jdk11) in scala/bug
-To help with testing on JDK 11, see [scala/scala-dev#559](https://github.com/scala/scala-dev/issues/559).
+## JDK 17 compatibility notes
+
+JDK 17 is an LTS release.
+
+Scala 2.13.6+ and 2.12.15+ support JDK 17.
+
+The Scala test suite and Scala community build are green on JDK 17.
+
+For sbt users, sbt 1.6.0-RC1 is the first version to support JDK 17, but in practice sbt 1.5.5 may also work. (It will print a warning on startup about `TrapExit` that you can ignore.)
+
+For possible Scala issues, see the [jdk11](https://github.com/scala/bug/labels/jdk11) and [jdk17](https://github.com/scala/bug/labels/jdk17) labels in the Scala 2 bug tracker.
+
+## JDK 21 compatibility notes
+
+JDK 21 is an LTS release.
+
+Scala 3.3.1+, 2.13.11+, and 2.12.18+ support JDK 21.
+
+The Scala test suite and Scala 2.13 community build are green on JDK 21.
+
+For sbt users, sbt 1.9.0 is the first version to support JDK 21.
+
+For possible Scala issues, see the [jdk11](https://github.com/scala/bug/labels/jdk11), [jdk17](https://github.com/scala/bug/labels/jdk17), and [jdk21](https://github.com/scala/bug/labels/jdk21) labels in the Scala 2 bug tracker.
+
+## JDK 22 compatibility notes
+
+JDK 22 is non-LTS.
+
+Scala 2.13.13+, 2.12.19+, 3.3.4+, and 3.6.2+ support JDK 22.
+
+For possible Scala 2 issues, see the [jdk11](https://github.com/scala/bug/labels/jdk11), [jdk17](https://github.com/scala/bug/labels/jdk17), and [jdk21](https://github.com/scala/bug/labels/jdk21) labels in the Scala 2 bug tracker.
+
+## JDK 23 compatibility notes
+
+JDK 23 is non-LTS.
+
+Scala 2.13.15+, Scala 2.12.20+, and Scala 3.6.2+ support JDK 23.
+
+We are working on adding JDK 23 support to Scala 3.3.x.
+(Support may be available in nightly builds and/or release candidates.)
+
+For possible Scala 2 issues, see the [jdk11](https://github.com/scala/bug/labels/jdk11), [jdk17](https://github.com/scala/bug/labels/jdk17), and [jdk21](https://github.com/scala/bug/labels/jdk21) labels in the Scala 2 bug tracker.
+
+## JDK 24 compatibility notes
-## JDK 12, 13, and 14 compatibility notes
+JDK 24 will be non-LTS.
-JDK 14 was released in March 2020. But 12, 13, and 14 are not LTS releases, so the remarks above about non-LTS releases apply. The next LTS release will be JDK 17.
+Scala 2.13.16+ supports, and Scala 2.12.21 (forthcoming) will support, JDK 24. We are also working on adding JDK 24 support to Scala 3. (Support may be available in nightly builds and/or release candidates.)
-JDK 12, 13, and 14 are expected to work wherever JDK 11 does. The Scala community build now runs on JDK 14 (as well as 11 and 8).
+For possible Scala 2 issues, see the [jdk11](https://github.com/scala/bug/labels/jdk11), [jdk17](https://github.com/scala/bug/labels/jdk17), and [jdk21](https://github.com/scala/bug/labels/jdk21) labels in the Scala 2 bug tracker.
-As of March 2020, the [jdk12](https://github.com/scala/bug/labels/jdk12) and [jdk13](https://github.com/scala/bug/labels/jdk13) labels in scala/bug have no open bugs. New issues will likely be reported against the newer non-LTS [jdk14 label](https://github.com/scala/bug/labels/jdk14) or the LTS [jdk11 label](https://github.com/scala/bug/labels/jdk11).
+## GraalVM Native Image compatibility notes
-As far as we know, 12, 13, and 14 are similar to 11 with respect to Scala compatibility.
+There are several records of successfully using Scala with [GraalVM](https://www.graalvm.org) Native Image (i.e., ahead of time compiler) to produce directly executable binaries.
+Beware that, even using solely the Scala standard library, Native Image compilation have some heavy requirements in terms of [reflective access](https://www.graalvm.org/reference-manual/native-image/metadata/), and it very likely require additional configuration steps to be performed.
-## JDK 15
+A few sbt plugins are offering support for GraalVM Native Image compilation:
-As of September 2020, JDK 15 is in release candidate phase ([reference](https://openjdk.java.net/projects/jdk/15/)). We don't have any compatibility information yet.
+- [sbt-native-packager](https://www.scala-sbt.org/sbt-native-packager/formats/graalvm-native-image.html)
+- [sbt-native-image](https://github.com/scalameta/sbt-native-image)
## Scala 3
-The Scala 3.0.x series will support JDK 8, as well as 11 and beyond.
+At present, both Scala 3 LTS and Scala Next support JDK 8, as well as 11 and beyond.
-As Scala and the JVM continue to evolve, some eventual Scala 3.x version may drop support for JDK 8, in order to better take advantage of new JVM features. It isn't clear yet what the new minimum supported version might become.
+As per [this blog post](https://www.scala-lang.org/news/next-scala-lts.html),
+a forthcoming Scala 3 LTS version will drop JDK 8 support and may drop
+11 as well. Stay tuned.
diff --git a/_overviews/macros/annotations.md b/_overviews/macros/annotations.md
index 103f65dc90..7300704010 100644
--- a/_overviews/macros/annotations.md
+++ b/_overviews/macros/annotations.md
@@ -57,8 +57,8 @@ results have to be wrapped in a `Block` for the lack of better notion in the ref
At this point you might be wondering. A single annottee and a single result is understandable, but what is the many-to-many
mapping supposed to mean? There are several rules guiding the process:
-1. If a class is annotated and it has a companion, then both are passed into the macro. (But not vice versa - if an object
- is annotated and it has a companion class, only the object itself is expanded).
+1. If a class is annotated, and it has a companion, then both are passed into the macro. (But not vice versa - if an object
+ is annotated, and it has a companion class, only the object itself is expanded).
1. If a parameter of a class, method or type member is annotated, then it expands its owner. First comes the annottee,
then the owner and then its companion as specified by the previous rule.
1. Annottees can expand into whatever number of trees of any flavor, and the compiler will then transparently
@@ -109,8 +109,8 @@ at a later point in the future).
In the spirit of Scala macros, macro annotations are as untyped as possible to stay flexible and
as typed as possible to remain useful. On the one hand, macro annottees are untyped, so that we can change their signatures (e.g. lists
of class members). But on the other hand, the thing about all flavors of Scala macros is integration with the typechecker, and
-macro annotations are not an exceptions. During expansion we can have all the type information that's possible to have
-(e.g. we can reflect against the surrounding program or perform type checks / implicit lookups in the enclosing context).
+macro annotations are not an exceptions. During expansion, we can have all the type information that's possible to have
+(e.g. we can reflect against the surrounding program or perform type checks / implicit lookup in the enclosing context).
## Blackbox vs whitebox
diff --git a/_overviews/macros/blackbox-whitebox.md b/_overviews/macros/blackbox-whitebox.md
index 07c13f2aa2..d29cd6b16d 100644
--- a/_overviews/macros/blackbox-whitebox.md
+++ b/_overviews/macros/blackbox-whitebox.md
@@ -19,7 +19,7 @@ Separation of macros into blackbox ones and whitebox ones is a feature of Scala
With macros becoming a part of the official Scala 2.10 release, programmers in research and industry have found creative ways of using macros to address all sorts of problems, far extending our original expectations.
-In fact, macros became an important part of our ecosystem so quickly that just a couple months after the release of Scala 2.10, when macros were introduced in experimental capacity, we had a Scala language team meeting and decided to standardize macros and make them a full-fledged feature of Scala by 2.12.
+In fact, macros became an important part of our ecosystem so quickly that just a couple of months after the release of Scala 2.10, when macros were introduced in experimental capacity, we had a Scala language team meeting and decided to standardize macros and make them a full-fledged feature of Scala by 2.12.
UPDATE It turned out that it was not that simple to stabilize macros by Scala 2.12. Our research into that has resulted in establishing a new metaprogramming foundation for Scala, called [scala.meta](https://scalameta.org), whose first beta is expected to be released simultaneously with Scala 2.12 and might later be included in future versions of Scala. In the meanwhile, Scala 2.12 is not going to see any changes to reflection and macros - everything is going to stay experimental as it was in Scala 2.10 and Scala 2.11, and no features are going to be removed. However, even though circumstances under which this document has been written have changed, the information still remains relevant, so please continue reading.
@@ -30,13 +30,13 @@ comprehensibility.
## Blackbox and whitebox macros
-However sometimes def macros transcend the notion of "just a regular method". For example, it is possible for a macro expansion to yield an expression of a type that is more specific than the return type of a macro. In Scala 2.10, such expansion will retain its precise type as highlighted in the ["Static return type of Scala macros"](https://stackoverflow.com/questions/13669974/static-return-type-of-scala-macros) article at Stack Overflow.
+However, sometimes def macros transcend the notion of "just a regular method". For example, it is possible for a macro expansion to yield an expression of a type that is more specific than the return type of macro. In Scala 2.10, such expansion will retain its precise type as highlighted in the ["Static return type of Scala macros"](https://stackoverflow.com/questions/13669974/static-return-type-of-scala-macros) article at Stack Overflow.
-This curious feature provides additional flexibility, enabling [fake type providers](https://meta.plasm.us/posts/2013/07/11/fake-type-providers-part-2/), [extended vanilla materialization](/sips/source-locations.html), [fundep materialization]({{ site.baseurl }}/overviews/macros/implicits.html#fundep-materialization) and [extractor macros](https://github.com/scala/scala/commit/84a335916556cb0fe939d1c51f27d80d9cf980dc), but it also sacrifices clarity - both for humans and for machines.
+This curious feature provides additional flexibility, enabling [fake type providers](https://meta.plasm.us/posts/2013/07/11/fake-type-providers-part-2/), [extended vanilla materialization](https://github.com/scala/improvement-proposals/pull/18), [fundep materialization]({{ site.baseurl }}/overviews/macros/implicits.html#fundep-materialization) and [extractor macros](https://github.com/scala/scala/commit/84a335916556cb0fe939d1c51f27d80d9cf980dc), but it also sacrifices clarity - both for humans and for machines.
To concretize the crucial distinction between macros that behave just like normal methods and macros that refine their return types, we introduce the notions of blackbox macros and whitebox macros. Macros that faithfully follow their type signatures are called **blackbox macros** as their implementations are irrelevant to understanding their behaviour (could be treated as black boxes). Macros that can't have precise signatures in Scala's type system are called **whitebox macros** (whitebox def macros do have signatures, but these signatures are only approximations).
-We recognize the importance of both blackbox and whitebox macros, however we feel more confidence in blackbox macros, because they are easier to explain, specify and support. Therefore our plans to standardize macros only include blackbox macros. Later on, we might also include whitebox macros into our plans, but it's too early to tell.
+We recognize the importance of both blackbox and whitebox macros, however we feel more confidence in blackbox macros, because they are easier to explain, specify and support. Therefore, our plans to standardize macros only include blackbox macros. Later on, we might also include whitebox macros into our plans, but it's too early to tell.
## Codifying the distinction
@@ -48,7 +48,7 @@ Blackbox def macros are treated differently from def macros of Scala 2.10. The f
1. When an application of a blackbox macro expands into tree `x`, the expansion is wrapped into a type ascription `(x: T)`, where `T` is the declared return type of the blackbox macro with type arguments and path dependencies applied in consistency with the particular macro application being expanded. This invalidates blackbox macros as an implementation vehicle of [type providers](https://meta.plasm.us/posts/2013/07/11/fake-type-providers-part-2/).
1. When an application of a blackbox macro still has undetermined type parameters after Scala's type inference algorithm has finished working, these type parameters are inferred forcedly, in exactly the same manner as type inference happens for normal methods. This makes it impossible for blackbox macros to influence type inference, prohibiting [fundep materialization]({{ site.baseurl }}/overviews/macros/implicits.html#fundep-materialization).
-1. When an application of a blackbox macro is used as an implicit candidate, no expansion is performed until the macro is selected as the result of the implicit search. This makes it impossible to [dynamically calculate availability of implicit macros]({{ site.baseurl }}/sips/source-locations.html).
+1. When an application of a blackbox macro is used as an implicit candidate, no expansion is performed until the macro is selected as the result of the implicit search. This makes it impossible to [dynamically calculate availability of implicit macros](https://github.com/scala/improvement-proposals/pull/18).
1. When an application of a blackbox macro is used as an extractor in a pattern match, it triggers an unconditional compiler error, preventing customizations of pattern matching implemented with macros.
Whitebox def macros work exactly like def macros used to work in Scala 2.10. No restrictions of any kind get applied, so everything that could be done with macros in 2.10 should be possible in 2.11 and 2.12.
diff --git a/_overviews/macros/bundles.md b/_overviews/macros/bundles.md
index 57f380b7f6..255b504391 100644
--- a/_overviews/macros/bundles.md
+++ b/_overviews/macros/bundles.md
@@ -18,7 +18,7 @@ Macro bundles are a feature of Scala 2.11.x and Scala 2.12.x. Macro bundles are
## Macro bundles
In Scala 2.10.x, macro implementations are represented with functions. Once the compiler sees an application of a macro definition,
-it calls the macro implementation - as simple as that. However practice shows that just functions are often not enough due to the
+it calls the macro implementation - as simple as that. However, practice shows that just functions are often not enough due to the
following reasons:
1. Being limited to functions makes modularizing complex macros awkward. It's quite typical to see macro logic concentrate in helper
diff --git a/_overviews/macros/implicits.md b/_overviews/macros/implicits.md
index 1f660d6ec9..04852d0f2d 100644
--- a/_overviews/macros/implicits.md
+++ b/_overviews/macros/implicits.md
@@ -140,7 +140,7 @@ macro, which synthesizes `Iso[C, L]`, scalac will helpfully infer `L` as `Nothin
As demonstrated by [https://github.com/scala/scala/pull/2499](https://github.com/scala/scala/pull/2499), the solution to the outlined
problem is extremely simple and elegant.
-In 2.10 we don't allow macro applications to expand until all their type arguments are inferred. However we don't have to do that.
+In 2.10 we don't allow macro applications to expand until all their type arguments are inferred. However, we don't have to do that.
The typechecker can infer as much as it possibly can (e.g. in the running example `C` will be inferred to `Foo` and
`L` will remain uninferred) and then stop. After that we expand the macro and then proceed with type inference using the type of the
expansion to help the typechecker with previously undetermined type arguments. This is how it's implemented in Scala 2.11.0.
diff --git a/_overviews/macros/overview.md b/_overviews/macros/overview.md
index 87cf64ee8b..c66b1c6d48 100644
--- a/_overviews/macros/overview.md
+++ b/_overviews/macros/overview.md
@@ -223,15 +223,15 @@ The walkthrough in this guide uses the simplest possible command-line compilatio
* Macros needs scala-reflect.jar in library dependencies.
* The separate compilation restriction requires macros to be placed in a separate project.
-### Using macros with Scala IDE or Intellij IDEA
+### Using macros with Intellij IDEA
-Both in Scala IDE and in Intellij IDEA macros are known to work fine, given they are moved to a separate project.
+In Intellij IDEA, macros are known to work fine, given they are moved to a separate project.
### Debugging macros
Debugging macros (i.e. the logic that drives macro expansion) is fairly straightforward. Since macros are expanded within the compiler, all that you need is to run the compiler under a debugger. To do that, you need to: 1) add all (!) the libraries from the lib directory in your Scala home (which include such jar files as `scala-library.jar`, `scala-reflect.jar` and `scala-compiler.jar`) to the classpath of your debug configuration, 2) set `scala.tools.nsc.Main` as an entry point, 3) provide the `-Dscala.usejavacp=true` system property for the JVM (very important!), 4) set command-line arguments for the compiler as `-cp Test.scala`, where `Test.scala` stands for a test file containing macro invocations to be expanded. After all that is done, you should be able to put a breakpoint inside your macro implementation and launch the debugger.
-What really requires special support in tools is debugging the results of macro expansion (i.e. the code that is generated by a macro). Since this code is never written out manually, you cannot set breakpoints there, and you won't be able to step through it. Scala IDE and Intellij IDEA teams will probably add support for this in their debuggers at some point, but for now the only way to debug macro expansions are diagnostic prints: `-Ymacro-debug-lite` (as described below), which prints out the code emitted by macros, and println to trace the execution of the generated code.
+What really requires special support in tools is debugging the results of macro expansion (i.e. the code that is generated by a macro). Since this code is never written out manually, you cannot set breakpoints there, and you won't be able to step through it. The Intellij IDEA team will probably add support for this in their debugger at some point, but for now the only way to debug macro expansions are diagnostic prints: `-Ymacro-debug-lite` (as described below), which prints out the code emitted by macros, and println to trace the execution of the generated code.
### Inspecting generated code
diff --git a/_overviews/macros/paradise.md b/_overviews/macros/paradise.md
index 14e61dd9a5..72637b0854 100644
--- a/_overviews/macros/paradise.md
+++ b/_overviews/macros/paradise.md
@@ -20,7 +20,7 @@ Macro paradise is a plugin for several versions of Scala compilers.
It is designed to reliably work with production releases of scalac,
making latest macro developments available way before they end up in future versions Scala.
Refer to the roadmap for [the list of supported features and versions](roadmap.html)
-and visit [the paradise announcement](https://scalamacros.org/news/2013/08/07/roadmap-for-macro-paradise.html)
+and visit [the paradise announcement](https://github.com/scalamacros/scalamacros.github.com/blob/5904f7ef88a439c668204b4bf262835e89fb13cb/news/_posts/2013-08-07-roadmap-for-macro-paradise.html)
to learn more about our support guarantees.
~/210x $ scalac -Xplugin:paradise_*.jar -Xshow-phases
@@ -35,7 +35,7 @@ to learn more about our support guarantees.
Some features in macro paradise bring a compile-time dependency on the macro paradise plugin,
some features do not, however none of those features need macro paradise at runtime.
-Proceed to the [the feature list](roadmap.html) document for more information.
+Proceed to [the feature list](roadmap.html) document for more information.
Consult [https://github.com/scalamacros/sbt-example-paradise](https://github.com/scalamacros/sbt-example-paradise)
for an end-to-end example, but in a nutshell working with macro paradise is as easy as adding the following two lines
diff --git a/_overviews/macros/typemacros.md b/_overviews/macros/typemacros.md
index 691b2f5e83..773819fa6d 100644
--- a/_overviews/macros/typemacros.md
+++ b/_overviews/macros/typemacros.md
@@ -12,7 +12,7 @@ permalink: /overviews/macros/:title.html
Type macros used to be available in previous versions of ["Macro Paradise"](paradise.html),
but are not supported anymore in macro paradise 2.0.
-Visit [the paradise 2.0 announcement](https://scalamacros.org/news/2013/08/05/macro-paradise-2.0.0-snapshot.html)
+Visit [the paradise 2.0 announcement](https://github.com/scalamacros/scalamacros.github.com/blob/5904f7ef88a439c668204b4bf262835e89fb13cb/news/_posts/2013-08-05-macro-paradise-2.0.0-snapshot.html)
for an explanation and suggested migration strategy.
## Intuition
@@ -84,7 +84,7 @@ In Scala programs type macros can appear in one of five possible roles: type rol
To put it in a nutshell, expansion of a type macro replace the usage of a type macro with a tree it returns. To find out whether an expansion makes sense, mentally replace some usage of a macro with its expansion and check whether the resulting program is correct.
-For example, a type macro used as `TM(2)(3)` in `class C extends TM(2)(3)` can expand into `Apply(Ident(TypeName("B")), List(Literal(Constant(2))))`, because that would result in `class C extends B(2)`. However the same expansion wouldn't make sense if `TM(2)(3)` was used as a type in `def x: TM(2)(3) = ???`, because `def x: B(2) = ???` (given that `B` itself is not a type macro; if it is, it will be recursively expanded and the result of the expansion will determine validity of the program).
+For example, a type macro used as `TM(2)(3)` in `class C extends TM(2)(3)` can expand into `Apply(Ident(TypeName("B")), List(Literal(Constant(2))))`, because that would result in `class C extends B(2)`. However, the same expansion wouldn't make sense if `TM(2)(3)` was used as a type in `def x: TM(2)(3) = ???`, because `def x: B(2) = ???` (given that `B` itself is not a type macro; if it is, it will be recursively expanded and the result of the expansion will determine validity of the program).
## Tips and tricks
diff --git a/_overviews/macros/typeproviders.md b/_overviews/macros/typeproviders.md
index 175126eab1..1e90c17003 100644
--- a/_overviews/macros/typeproviders.md
+++ b/_overviews/macros/typeproviders.md
@@ -85,7 +85,7 @@ captures the essence of the generated classes, providing a statically typed inte
This approach to type providers is quite neat, because it can be used with production versions of Scala, however
it has performance problems caused by the fact that Scala emits reflective calls when compiling accesses to members
-of structural types. There are several strategies of dealing with that, but this margin is too narrow to contain them
+of structural types. There are several strategies of dealing with that, but this margin is too narrow to contain them,
so I refer you to an amazing blog series by Travis Brown for details: [post 1](https://meta.plasm.us/posts/2013/06/19/macro-supported-dsls-for-schema-bindings/), [post 2](https://meta.plasm.us/posts/2013/07/11/fake-type-providers-part-2/), [post 3](https://meta.plasm.us/posts/2013/07/12/vampire-methods-for-structural-types/).
## Public type providers
diff --git a/_overviews/macros/untypedmacros.md b/_overviews/macros/untypedmacros.md
index cfceefb78c..cccb85729b 100644
--- a/_overviews/macros/untypedmacros.md
+++ b/_overviews/macros/untypedmacros.md
@@ -12,13 +12,13 @@ permalink: /overviews/macros/:title.html
Untyped macros used to be available in previous versions of ["Macro Paradise"](paradise.html),
but are not supported anymore in macro paradise 2.0.
-Visit [the paradise 2.0 announcement](https://scalamacros.org/news/2013/08/05/macro-paradise-2.0.0-snapshot.html)
+Visit [the paradise 2.0 announcement](https://github.com/scalamacros/scalamacros.github.com/blob/5904f7ef88a439c668204b4bf262835e89fb13cb/news/_posts/2013-08-05-macro-paradise-2.0.0-snapshot.html)
for an explanation and suggested migration strategy.
## Intuition
Being statically typed is great, but sometimes that is too much of a burden. Take for example, the latest experiment of Alois Cochard with
-implementing enums using type macros - the so called [Enum Paradise](https://github.com/aloiscochard/enum-paradise). Here's how Alois has
+implementing enums using type macros - the so-called [Enum Paradise](https://github.com/aloiscochard/enum-paradise). Here's how Alois has
to write his type macro, which synthesizes an enumeration module from a lightweight spec:
object Days extends Enum('Monday, 'Tuesday, 'Wednesday...)
@@ -56,9 +56,9 @@ of the linked JIRA issue. Untyped macros make the full power of textual abstract
unit test provides details on this matter.
If a macro has one or more untyped parameters, then when typing its expansions, the typechecker will do nothing to its arguments
-and will pass them to the macro untyped. Even if some of the parameters do have type annotations, they will currently be ignored. This
+and will pass them to the macro untyped. Even if some parameters do have type annotations, they will currently be ignored. This
is something we plan on improving: [SI-6971](https://issues.scala-lang.org/browse/SI-6971). Since arguments aren't typechecked, you
-also won't having implicits resolved and type arguments inferred (however, you can do both with `c.typeCheck` and `c.inferImplicitValue`).
+also won't have implicits resolved and type arguments inferred (however, you can do both with `c.typeCheck` and `c.inferImplicitValue`).
Explicitly provided type arguments will be passed to the macro as is. If type arguments aren't provided, they will be inferred as much as
possible without typechecking the value arguments and passed to the macro in that state. Note that type arguments still get typechecked, but
@@ -69,6 +69,6 @@ the first typecheck of a def macro expansion is performed against the return typ
against the expected type of the expandee. More information can be found at Stack Overflow: [Static return type of Scala macros](https://stackoverflow.com/questions/13669974/static-return-type-of-scala-macros). Type macros never underwent the first typecheck, so
nothing changes for them (and you won't be able to specify any return type for a type macro to begin with).
-Finally the untyped macros patch enables using `c.Tree` instead of `c.Expr[T]` everywhere in signatures of macro implementations.
+Finally, the untyped macros patch enables using `c.Tree` instead of `c.Expr[T]` everywhere in signatures of macro implementations.
Both for parameters and return types, all four combinations of untyped/typed in macro def and tree/expr in macro impl are supported.
Check our unit tests for more information: test/files/run/macro-untyped-conformance.
diff --git a/_overviews/macros/usecases.md b/_overviews/macros/usecases.md
index 335d3f6bd5..eed399f3b1 100644
--- a/_overviews/macros/usecases.md
+++ b/_overviews/macros/usecases.md
@@ -19,12 +19,12 @@ to the realm of possible. Both commercial and research users of Scala use macros
At EPFL we are leveraging macros to power our research. Lightbend also employs macros in a number of projects.
Macros are also popular in the community and have already given rise to a number of interesting applications.
-The recent talk ["What Are Macros Good For?"](https://scalamacros.org/paperstalks/2014-02-04-WhatAreMacrosGoodFor.pdf)
+The recent talk ["What Are Macros Good For?"](https://github.com/scalamacros/scalamacros.github.com/blob/5904f7ef88a439c668204b4bf262835e89fb13cb/paperstalks/2014-02-04-WhatAreMacrosGoodFor.pdf)
describes and systemizes uses that macros found among Scala 2.10 users. The thesis of the talk is that macros are good for
code generation, static checking and DSLs, illustrated with a number of examples from research and industry.
We have also published a paper in the Scala'13 workshop,
-["Scala Macros: Let Our Powers Combine!"](https://scalamacros.org/paperstalks/2013-04-22-LetOurPowersCombine.pdf),
+["Scala Macros: Let Our Powers Combine!"](https://github.com/scalamacros/scalamacros.github.com/blob/5904f7ef88a439c668204b4bf262835e89fb13cb/paperstalks/2013-04-22-LetOurPowersCombine.pdf),
covering the state of the art of macrology in Scala 2.10 from a more academic point of view.
In the paper we show how the rich syntax and static types of Scala synergize with macros and
explore how macros enable new and unique ways to use pre-existing language features.
diff --git a/_overviews/parallel-collections/architecture.md b/_overviews/parallel-collections/architecture.md
index 2b64486f63..f98b628210 100644
--- a/_overviews/parallel-collections/architecture.md
+++ b/_overviews/parallel-collections/architecture.md
@@ -87,13 +87,13 @@ Scala's parallel collection's draws much inspiration from the design of
Scala's (sequential) collections library-- as a matter of fact, it mirrors the
regular collections framework's corresponding traits, as shown below.
-[]({{ site.baseurl }}/resources/images/parallel-collections-hierarchy.png)
+[]({{ site.baseurl }}/resources/images/parallel-collections-hierarchy.png)
Hierarchy of Scala's Collections and Parallel Collections Libraries
The goal is of course to integrate parallel collections as tightly as possible
-with sequential collections, so as to allow for straightforward substitution
+with sequential collections, to allow for straightforward substitution
of sequential and parallel collections.
In order to be able to have a reference to a collection which may be either
diff --git a/_overviews/parallel-collections/concrete-parallel-collections.md b/_overviews/parallel-collections/concrete-parallel-collections.md
index 2885e72bc9..428f142918 100644
--- a/_overviews/parallel-collections/concrete-parallel-collections.md
+++ b/_overviews/parallel-collections/concrete-parallel-collections.md
@@ -84,10 +84,10 @@ is an ordered sequence of elements equally spaced apart. A parallel range is
created in a similar way as the sequential
[Range](https://www.scala-lang.org/api/{{ site.scala-212-version }}/scala/collection/immutable/Range.html):
- scala> 1 to 3 par
+ scala> (1 to 3).par
res0: scala.collection.parallel.immutable.ParRange = ParRange(1, 2, 3)
- scala> 15 to 5 by -2 par
+ scala> (15 to 5 by -2).par
res1: scala.collection.parallel.immutable.ParRange = ParRange(15, 13, 11, 9, 7, 5)
Just as sequential ranges have no builders, parallel ranges have no
@@ -146,7 +146,7 @@ and
scala> val phs = scala.collection.parallel.immutable.ParHashSet(1 until 1000: _*)
phs: scala.collection.parallel.immutable.ParHashSet[Int] = ParSet(645, 892, 69, 809, 629, 365, 138, 760, 101, 479,...
- scala> phs map { x => x * x } sum
+ scala> phs.map(x => x * x).sum
res0: Int = 332833500
Similar to parallel hash tables, parallel hash trie
diff --git a/_overviews/parallel-collections/custom-parallel-collections.md b/_overviews/parallel-collections/custom-parallel-collections.md
index 7ea4330c62..88307d3910 100644
--- a/_overviews/parallel-collections/custom-parallel-collections.md
+++ b/_overviews/parallel-collections/custom-parallel-collections.md
@@ -72,10 +72,10 @@ Finally, methods `split` and `psplit` are used to create splitters which
traverse subsets of the elements of the current splitter. Method `split` has
the contract that it returns a sequence of splitters which traverse disjoint,
non-overlapping subsets of elements that the current splitter traverses, none
-of which is empty. If the current splitter has 1 or less elements, then
+of which is empty. If the current splitter has 1 or fewer elements, then
`split` just returns a sequence of this splitter. Method `psplit` has to
return a sequence of splitters which traverse exactly as many elements as
-specified by the `sizes` parameter. If the `sizes` parameter specifies less
+specified by the `sizes` parameter. If the `sizes` parameter specifies fewer
elements than the current splitter, then an additional splitter with the rest
of the elements is appended at the end. If the `sizes` parameter requires more
elements than there are remaining in the current splitter, it will append an
@@ -112,9 +112,9 @@ may be suboptimal - producing a string again from the vector after filtering may
## Parallel collections with combiners
-Lets say we want to `filter` the characters of the parallel string, to get rid
+Let's say we want to `filter` the characters of the parallel string, to get rid
of commas for example. As noted above, calling `filter` produces a parallel
-vector and we want to obtain a parallel string (since some interface in the
+vector, and we want to obtain a parallel string (since some interface in the
API might require a sequential string).
To avoid this, we have to write a combiner for the parallel string collection.
@@ -134,7 +134,7 @@ is internally used by `filter`.
protected[this] override def newCombiner: Combiner[Char, ParString] = new ParStringCombiner
Next we define the `ParStringCombiner` class. Combiners are subtypes of
-builders and they introduce an additional method called `combine`, which takes
+builders, and they introduce an additional method called `combine`, which takes
another combiner as an argument and returns a new combiner which contains the
elements of both the current and the argument combiner. The current and the
argument combiner are invalidated after calling `combine`. If the argument is
@@ -195,7 +195,7 @@ live with this sequential bottleneck.
There are no predefined recipes-- it depends on the data-structure at
hand, and usually requires a bit of ingenuity on the implementer's
-part. However there are a few approaches usually taken:
+part. However, there are a few approaches usually taken:
1. Concatenation and merge. Some data-structures have efficient
implementations (usually logarithmic) of these operations.
diff --git a/_overviews/parallel-collections/overview.md b/_overviews/parallel-collections/overview.md
index 11fab887a6..1ced205636 100644
--- a/_overviews/parallel-collections/overview.md
+++ b/_overviews/parallel-collections/overview.md
@@ -12,10 +12,12 @@ permalink: /overviews/parallel-collections/:title.html
**Aleksandar Prokopec, Heather Miller**
+If you're using Scala 2.13+ and want to use Scala's parallel collections, you'll have to import a separate module, as described [here](https://github.com/scala/scala-parallel-collections).
+
## Motivation
Amidst the shift in recent years by processor manufacturers from single to
-multi-core architectures, academia and industry alike have conceded that
+multicore architectures, academia and industry alike have conceded that
_Popular Parallel Programming_ remains a formidable challenge.
Parallel collections were included in the Scala standard library in an effort
@@ -63,7 +65,7 @@ from Scala's (sequential) collection library, including:
In addition to a common architecture, Scala's parallel collections library
additionally shares _extensibility_ with the sequential collections library.
That is, like normal sequential collections, users can integrate their own
-collection types and automatically inherit all of the predefined (parallel)
+collection types and automatically inherit all the predefined (parallel)
operations available on the other parallel collections in the standard
library.
@@ -153,13 +155,13 @@ sections of this guide.
While the parallel collections abstraction feels very much the same as normal
sequential collections, it's important to note that its semantics differs,
-especially with regards to side-effects and non-associative operations.
+especially in regard to side-effects and non-associative operations.
In order to see how this is the case, first, we visualize _how_ operations are
performed in parallel. Conceptually, Scala's parallel collections framework
parallelizes an operation on a parallel collection by recursively "splitting"
a given collection, applying an operation on each partition of the collection
-in parallel, and re-"combining" all of the results that were completed in
+in parallel, and re-"combining" all the results that were completed in
parallel.
These concurrent, and "out-of-order" semantics of parallel collections lead to
@@ -174,7 +176,7 @@ Given the _concurrent_ execution semantics of the parallel collections
framework, operations performed on a collection which cause side-effects
should generally be avoided, in order to maintain determinism. A simple
example is by using an accessor method, like `foreach` to increment a `var`
-declared outside of the closure which is passed to `foreach`.
+declared outside the closure which is passed to `foreach`.
scala> var sum = 0
sum: Int = 0
diff --git a/_overviews/parallel-collections/performance.md b/_overviews/parallel-collections/performance.md
index d5780b05c5..2f7aa27f2f 100644
--- a/_overviews/parallel-collections/performance.md
+++ b/_overviews/parallel-collections/performance.md
@@ -45,7 +45,7 @@ garbage collections.
One common cause of a performance deterioration is also boxing and unboxing
that happens implicitly when passing a primitive type as an argument to a
generic method. At runtime, primitive types are converted to objects which
-represent them, so that they could be passed to a method with a generic type
+represent them, so that they could be passed to a method with a type
parameter. This induces extra allocations and is slower, also producing
additional garbage on the heap.
@@ -81,7 +81,7 @@ For proper benchmark examples, you can see the source code inside [Scala library
This is a question commonly asked. The answer is somewhat involved.
-The size of the collection at which the parallelization pays of really
+The size of the collection at which the parallelization pays off really
depends on many factors. Some of them, but not all, include:
- Machine architecture. Different CPU types have different
@@ -122,6 +122,6 @@ depends on many factors. Some of them, but not all, include:
2. [Dynamic compilation and performance measurement, Brian Goetz][2]
3. [Scala library benchmarks][3]
- [1]: https://www.ibm.com/developerworks/java/library/j-jtp02225/index.html "flawed-benchmark"
- [2]: https://www.ibm.com/developerworks/library/j-jtp12214/ "dynamic-compilation"
+ [1]: https://web.archive.org/web/20210305174819/https://www.ibm.com/developerworks/java/library/j-jtp02225/index.html "flawed-benchmark"
+ [2]: https://web.archive.org/web/20210228055617/http://www.ibm.com/developerworks/library/j-jtp12214/ "dynamic-compilation"
[3]: https://github.com/scala/scala/tree/2.12.x/test/benchmarks
diff --git a/_overviews/plugins/index.md b/_overviews/plugins/index.md
index 13f1666a2d..0b1ea54d55 100644
--- a/_overviews/plugins/index.md
+++ b/_overviews/plugins/index.md
@@ -17,6 +17,13 @@ compiler. It does not go into depth on how to make your plugin
actually do something useful, but just shows the basics needed to
write a plugin and hook it into the Scala compiler.
+## You can read, but you can also watch TV
+
+The contents of this guide overlaps substantially with Seth Tisue's
+talk "Scala Compiler Plugins 101" ([32 minute video](https://www.youtube.com/watch?v=h5NZjuxS5Qo)).
+Although the talk is from April 2018, nearly all of the information
+in it still applies (as of November 2020).
+
## When to write a plugin
Plugins let you modify the behavior of the Scala compiler without
@@ -28,25 +35,23 @@ You should not actually need to modify the Scala compiler very
frequently, because Scala's light, flexible syntax will frequently
allow you to provide a better solution using a clever library.
-There are some times, though, where a compiler modification is the
+There are some cases, though, where a compiler modification is the
best choice even for Scala. Popular compiler plugins (as of 2018)
include:
- Alternate compiler back ends such as [Scala.js](https://www.scala-js.org), [Scala Native](http://scala-native.org), and
[Fortify SCA for Scala](https://developer.lightbend.com/docs/fortify/current/).
- Linters such as [Wartremover](https://www.wartremover.org) and [Scapegoat](https://github.com/sksamuel/scapegoat).
-- Plugins that support reformatting and other changes
- to source code, such as [scalafix](https://scalacenter.github.io/scalafix/) and [scalafmt](https://scalameta.org/scalafmt/) (which are
- built on the [semanticdb](https://scalameta.org/docs/semanticdb/guide.html) and [scalahost](https://github.com/Duhemm/scalahost) compiler plugins).
- Plugins that alter Scala's syntax, such as [kind-projector](https://github.com/typelevel/kind-projector).
- Plugins that alter Scala's behavior around errors and warnings,
- such as [silencer](https://github.com/ghik/silencer).
+ such as [silencer](https://github.com/ghik/silencer), [splain](https://github.com/tek/splain) and [clippy](https://scala-clippy.org/).
- Plugins that analyze the structure of source code, such as
- [Sculpt](https://github.com/lightbend/scala-sculpt) and [acyclic](https://github.com/lihaoyi/acyclic).
+ [Sculpt](https://github.com/lightbend/scala-sculpt), [acyclic](https://github.com/lihaoyi/acyclic) and [graph-buddy](https://github.com/VirtusLab/graphbuddy).
- Plugins that instrument user code to collect information,
such as the code coverage tool [scoverage](https://github.com/scoverage/scalac-scoverage-plugin).
-- Plugins that add metaprogramming facilities to Scala,
- such as [Macro Paradise](https://github.com/scalamacros/paradise).
+- Plugins that enable tooling. One such plugin is [semanticdb](https://scalameta.org/docs/semanticdb/guide.html), which enables [scalafix](https://scalacenter.github.io/scalafix/) (a well-known refactoring and linting tool) to do its work. Another one is [Macro Paradise](https://github.com/scalamacros/paradise) (only needed for Scala 2.12).
+- Plugins that modify existing Scala constructs in user code,
+ such as [better-monadic-for](https://github.com/oleg-py/better-monadic-for) and [better-tostring](https://github.com/polyvariant/better-tostring).
- Plugins that add entirely new constructs to Scala by
restructuring user code, such as [scala-continuations](https://github.com/scala/scala-continuations).
@@ -68,6 +73,7 @@ All of this is then packaged in a JAR file.
To use the plugin, a user adds the JAR file to their compile-time
classpath and enables it by invoking `scalac` with `-Xplugin:...`.
+(Some build tools provide shortcuts for this; see below.)
All of this will be described in more detail below.
@@ -147,6 +153,12 @@ aspects of note.
desire on the given compilation unit. Usually this involves
examining the trees within the unit and doing some transformation on
the tree.
+- The pattern match inside the body of `apply` shows one way of
+ detecting certain tree shapes in user code.
+ (Quasiquotes are another way.) `Apply` denotes a method call,
+ and `Select` denotes the "selection" of a member, such as `a.b`.
+ The details of tree processing are out of scope for this document,
+ but see "Going further", below, for links to further documentation.
The `runsAfter` method gives the plugin author control over when the
phase is executed. As seen above, it is expected to return a list of
@@ -187,6 +199,11 @@ with that file plus your compiled code:
cp scalac-plugin.xml classes
(cd classes; jar cf ../divbyzero.jar .)
+That's how it works with no build tool. If you are using sbt to build
+your plugin, then the XML file goes in `src/main/resources`.
+
+## Using a plugin with scalac
+
Now you can use your plugin with `scalac` by adding the `-Xplugin:`
option:
@@ -196,23 +213,76 @@ option:
^
one error found
+## Publishing your plugin
+
When you are happy with how the plugin behaves, you may wish to
publish the JAR to a Maven or Ivy repository where it can be resolved
-by a build tool.
+by a build tool. (For testing purposes, you can also publish it to
+your local machine only. In sbt, this is accomplished with
+`publishLocal`.)
-sbt, for example, provides an `addCompilerPlugin` method you can
+In most respects, compiler plugins are ordinary Scala libraries,
+so publishing a plugin is like publishing any library.
+See the [Library Author Guide]({{site.baseurl}}/overviews/contributors/index.html)
+and/or your build tool's documentation on publishing.
+
+## Using a plugin from sbt
+
+To make it convenient for end users to use your plugin once it has
+been published, sbt provides an `addCompilerPlugin` method you can
call in your build definition, e.g.:
- addCompilerPlugin("org.divbyzero" % "divbyzero" % "1.0")
+ addCompilerPlugin("org.divbyzero" %% "divbyzero" % "1.0")
+
+`addCompilerPlugin` performs multiple actions. It adds the JAR to the
+classpath (the compilation classpath only, not the runtime classpath)
+via `libraryDependencies`, and it also customizes `scalacOptions` to
+enable the plugin using `-Xplugin`.
+
+For more details, see [Compiler Plugin
+Support](https://www.scala-sbt.org/1.x/docs/Compiler-Plugins.html) in
+the sbt manual.
+
+## Using your plugin in Mill
-Note however that `addCompilerPlugin` only adds the JAR to the
-compilation classpath; it doesn't actually enable the plugin. To
-do that, you must customize `scalacOptions` to include the appropriate
-`-Xplugin` call. To shield users from having to know this, it's
-relatively common for compiler plugin authors to also write an
-accompanying sbt plugin that takes of customizing the classpath and
-compiler options appropriately. Then using your plugin only requires
-adding an `addSbtPlugin(...)` call to `project/plugins.sbt`.
+To use a scalac compiler plugin in your Mill project, you can override
+the `scalacPluginIvyDeps` target to add your plugins dependency coordinates.
+
+Plugin options can be specified in `scalacOptions`.
+
+Example:
+
+```scala
+// build.sc
+import mill._, mill.scalalib._
+
+object foo extends ScalaModule {
+ // Add the compiler plugin divbyzero in version 1.0
+ def scalacPluginIvyDeps = Agg(ivy"org.divbyzero:::divbyzero:1.0")
+ // Enable the `verbose` option of the divbyzero plugin
+ def scalacOptions = Seq("-P:divbyzero:verbose:true")
+ // other settings
+ // ...
+}
+
+```
+
+Please notice, that compiler plugins are typically bound to the full
+version of the compiler, hence you have to use the `:::` (instead of
+normal `::`) between the organization and the artifact name,
+to declare your dependency.
+
+For more information about plugin usage in Mill, please refer to the
+[Mill documentation for Scala compiler plugins](https://mill-build.org/mill/Scala_Module_Config.html#_scala_compiler_plugins).
+
+## Developing compiler plugins with an IDE
+
+Internally, the use of path-dependent types in the Scala compiler
+may confuse some IDEs such as IntelliJ. Correct plugin code may
+sometimes be highlighted as erroneous. The IDE is usually still
+useful under these circumstances, but remember to take its feedback
+with a grain of salt. If the error highlighting is distracting,
+the IDE may have a setting where you can disable it.
## Useful compiler options
@@ -317,9 +387,12 @@ behavior other than to print out its option.
## Going further
For the details on how to make your plugin accomplish some task, you
-must consult other documentation on compiler internals (such as the
-documentation on [Symbols, Trees, and Types]({{site.baseurl
-}}/overviews/reflection/symbols-trees-types.html).
+must consult other documentation on compiler internals. Relevant
+documents include:
+
+* [Symbols, Trees, and Types]({{site.baseurl}}/overviews/reflection/symbols-trees-types.html) is the single most important reference about the data structures used inside the compiler.
+* [Quasiquotes]({{site.baseurl}}/overviews/quasiquotes/intro.html) are useful for pattern matching on ASTs.
+ * The [syntax summary]({{site.baseurl}}/overviews/quasiquotes/syntax-summary.html) in the quasiquotes guide is a useful concordance between user-level syntax and AST node types.
It's also useful to look at other plugins and to study existing phases
within the compiler source code.
diff --git a/_overviews/quasiquotes/expression-details.md b/_overviews/quasiquotes/expression-details.md
index 62e810697d..6ef424fac1 100644
--- a/_overviews/quasiquotes/expression-details.md
+++ b/_overviews/quasiquotes/expression-details.md
@@ -16,7 +16,7 @@ permalink: /overviews/quasiquotes/:title.html
1. `Val`s, `Var`s and `Def`s without the right-hand side have it set to `q""`.
2. Abstract type definitions without bounds have them set to `q""`.
-3. `Try` expressions without a finally clause have it set to `q""`.
+3. `Try` expressions without a `finally` clause have it set to `q""`.
4. `Case` clauses without guards have them set to `q""`.
The default `toString` formats `q""` as ``.
@@ -58,13 +58,13 @@ During deconstruction you can use [unlifting]({{ site.baseurl }}/overviews/quasi
scala> val q"${x: Int}" = q"1"
x: Int = 1
-Similarly it would work with all the literal types except `Null`. (see [standard unliftables]({{ site.baseurl }}/overviews/quasiquotes/unlifting.html#standard-unliftables))
+Similarly, it would work with all the literal types except `Null`. (see [standard unliftables]({{ site.baseurl }}/overviews/quasiquotes/unlifting.html#standard-unliftables))
## Identifier and Selection
Identifiers and member selections are two fundamental primitives that let you refer to other definitions. A combination of two of them is also known as a `RefTree`.
-Each term identifier is defined by its name and whether or not it is backquoted:
+Each term identifier is defined by its name and whether it is backquoted:
scala> val name = TermName("Foo")
name: universe.TermName = Foo
@@ -90,7 +90,7 @@ Apart from matching on identifiers with a given name, you can also extract their
Name ascription is important here because without it you'll get a pattern that is equivalent to regular pattern variable binding.
-Similarly you can create and extract member selections:
+Similarly, you can create and extract member selections:
scala> val member = TermName("bar")
member: universe.TermName = bar
@@ -112,7 +112,7 @@ This tree supports following variations:
So an unqualified `q"this"` is equivalent to `q"${tpnme.EMPTY}.this"`.
-Similarly for `super` we have:
+Similarly, for `super` we have:
scala> val q"$name.super[$qual].$field" = q"super.foo"
name: universe.TypeName =
@@ -145,7 +145,7 @@ This can be accomplished with the following:
type arguments: List(Int), value arguments: List(1, 2)
type arguments: List(), value arguments: List(scala.Symbol("a"), scala.Symbol("b"))
-As you can see, we were able to match both calls regardless as to whether or not a specific type application exists. This happens because the type application matcher extracts the empty list of type arguments if the tree is not an actual type application, making it possible to handle both situations uniformly.
+As you can see, we were able to match both calls regardless of whether a specific type application exists. This happens because the type application matcher extracts the empty list of type arguments if the tree is not an actual type application, making it possible to handle both situations uniformly.
It is recommended to always include type applications when you match on a function with type arguments, as they will be inserted by the compiler during type checking, even if the user didn't write them explicitly:
@@ -175,7 +175,7 @@ Here we might get one, or two subsequent value applications:
scala> val q"g(...$argss)" = q"g"
argss: List[List[universe.Tree]] = List()
-Therefore it's recommended to use more specific patterns that check that ensure the extracted `argss` is not empty.
+Therefore, it's recommended to use more specific patterns that check that ensure the extracted `argss` is not empty.
Similarly to type arguments, implicit value arguments are automatically inferred during type checking:
@@ -244,7 +244,7 @@ The *throw* expression is used to throw a throwable:
## Ascription
-Ascriptions let users annotate the type of an intermediate expression:
+Ascriptions let users annotate the type of intermediate expression:
scala> val ascribed = q"(1 + 1): Int"
ascribed: universe.Typed = (1.$plus(1): Int)
@@ -469,7 +469,7 @@ There are three ways to create anonymous function:
scala> val f3 = q"(a: Int) => a + 1"
anon3: universe.Function = ((a: Int) => a.$plus(1))
-The first one uses the placeholder syntax. The second one names the function parameter but still relies on type inference to infer its type. An the last one explicitly defines the function parameter. Due to an implementation restriction, the second notation can only be used in parentheses or inside another expression. If you leave them out the you must specify the parameter types.
+The first one uses the placeholder syntax. The second one names the function parameter but still relies on type inference to infer its type. An the last one explicitly defines the function parameter. Due to an implementation restriction, the second notation can only be used in parentheses or inside another expression. If you leave them out then you must specify the parameter types.
Parameters are represented as [Vals]({{ site.baseurl }}/overviews/quasiquotes/definition-details.html#val-and-var-definitions). If you want to programmatically create a `val` that should have its type inferred you need to use the [empty type]({{ site.baseurl }}/overviews/quasiquotes/type-details.html#empty-type):
@@ -576,7 +576,7 @@ Each enumerator in the comprehension can be expressed with the `fq"..."` interpo
scala> val `for-yield` = q"for (..$enums) yield y"
for-yield: universe.Tree
-Similarly one can deconstruct the `for-yield` back into a list of enumerators and body:
+Similarly, one can deconstruct the `for-yield` back into a list of enumerators and body:
scala> val q"for (..$enums) yield $body" = `for-yield`
enums: List[universe.Tree] = List(`<-`((x @ _), xs), `if`(x.$greater(0)), (y @ _) = x.$times(2))
@@ -609,10 +609,10 @@ Selectors are extracted as pattern trees that are syntactically similar to selec
1. Simple identifier selectors are represented as pattern bindings: `pq"bar"`
2. Renaming selectors are represented as thin arrow patterns: `pq"baz -> boo"`
-3. Unimport selectors are represented as thin arrows with a wildcard right hand side: `pq"poison -> _"`
+3. Unimport selectors are represented as thin arrows with a wildcard right-hand side: `pq"poison -> _"`
4. The wildcard selector is represented as a wildcard pattern: `pq"_"`
-Similarly one construct imports back from a programmatically created list of selectors:
+Similarly, one construct imports back from a programmatically created list of selectors:
scala> val ref = q"a.b"
scala> val sels = List(pq"foo -> _", pq"_")
diff --git a/_overviews/quasiquotes/hygiene.md b/_overviews/quasiquotes/hygiene.md
index 1523655696..f08a9145de 100644
--- a/_overviews/quasiquotes/hygiene.md
+++ b/_overviews/quasiquotes/hygiene.md
@@ -12,7 +12,7 @@ permalink: /overviews/quasiquotes/:title.html
The notion of hygiene has been widely popularized by macro research in Scheme. A code generator is called hygienic if it ensures the absence of name clashes between regular and generated code, preventing accidental capture of identifiers. As numerous experience reports show, hygiene is of great importance to code generation, because name binding problems are often non-obvious and lack of hygiene might manifest itself in subtle ways.
-Sophisticated macro systems such as Racket's have mechanisms that make macros hygienic without any effort from macro writers. In Scala we don't have automatic hygiene - both of our codegen facilities (compile-time codegen with macros and runtime codegen with toolboxes) require programmers to handle hygiene manually. You must know how to work around the absence of hygiene, which is what this section is about.
+Sophisticated macro systems such as Racket's have mechanisms that make macros hygienic without any effort from macro writers. In Scala, we don't have automatic hygiene - both of our codegen facilities (compile-time codegen with macros and runtime codegen with toolboxes) require programmers to handle hygiene manually. You must know how to work around the absence of hygiene, which is what this section is about.
Preventing name clashes between regular and generated code means two things. First, we must ensure that, regardless of the context in which we put generated code, its meaning will not change (*referential transparency*). Second, we must make certain that regardless of the context in which we splice regular code, its meaning will not change (often called *hygiene in the narrow sense*). Let's see what can be done to this end on a series of examples.
@@ -56,7 +56,7 @@ Here we can see that the unqualified reference to `Map` does not respect our cus
MyMacro(2)
}
-If we compile both the macro and it's usage, we'll see that `println` will not be called when the application runs. This will happen because, after macro expansion, `Test.scala` will look like:
+If we compile both the macro, and it's usage, we'll see that `println` will not be called when the application runs. This will happen because, after macro expansion, `Test.scala` will look like:
// Expanded Test.scala
package example
diff --git a/_overviews/quasiquotes/intro.md b/_overviews/quasiquotes/intro.md
index 4ffba9e912..de31e4f162 100644
--- a/_overviews/quasiquotes/intro.md
+++ b/_overviews/quasiquotes/intro.md
@@ -90,7 +90,7 @@ Similarly, patterns and expressions are also not equivalent:
It's extremely important to use the right interpolator for the job in order to construct a valid syntax tree.
-Additionally there are two auxiliary interpolators that let you work with minor areas of scala syntax:
+Additionally, there are two auxiliary interpolators that let you work with minor areas of scala syntax:
| Used for
----|-------------------------------------
diff --git a/_overviews/quasiquotes/lifting.md b/_overviews/quasiquotes/lifting.md
index b0f2f54910..e218eca1cf 100644
--- a/_overviews/quasiquotes/lifting.md
+++ b/_overviews/quasiquotes/lifting.md
@@ -24,7 +24,7 @@ This code runs successfully because `Int` is considered to be `Liftable` by defa
def apply(value: T): Tree
}
-Whenever there is an implicit value of `Liftable[T]` available, one can unquote `T` in quasiquotes. This design pattern is known as a *type class*. You can read more about it in ["Type Classes as Objects and Implicits"](https://ropas.snu.ac.kr/~bruno/papers/TypeClasses.pdf).
+Whenever there is an implicit value of `Liftable[T]` available, one can unquote `T` in quasiquotes. This design pattern is known as a *type class*. You can read more about it in ["Type Classes as Objects and Implicits"](https://infoscience.epfl.ch/record/150280/files/TypeClasses.pdf).
A number of data types that are supported natively by quasiquotes will never trigger the usage of a `Liftable` representation, even if it\'s available: subtypes of `Tree`, `Symbol`, `Name`, `Modifiers` and `FlagSet`.
diff --git a/_overviews/quasiquotes/setup.md b/_overviews/quasiquotes/setup.md
index b121d666d6..155ee8a32b 100644
--- a/_overviews/quasiquotes/setup.md
+++ b/_overviews/quasiquotes/setup.md
@@ -18,9 +18,9 @@ All examples and code snippets in this guide are run under in 2.11 REPL with one
scala> val universe: scala.reflect.runtime.universe.type = scala.reflect.runtime.universe
scala> import universe._
-A wildcard import from a universe (be it a runtime reflection universe like here or a compile-time universe provided in macros) is all that's needed to use quasiquotes. All of the examples will assume that import.
+A wildcard import from a universe (be it a runtime reflection universe like here or a compile-time universe provided in macros) is all that's needed to use quasiquotes. All the examples will assume that import.
-Additionally some examples that use `ToolBox` API will need a few more lines to get things rolling:
+Additionally, some examples that use `ToolBox` API will need a few more lines to get things rolling:
scala> import scala.reflect.runtime.currentMirror
scala> import scala.tools.reflect.ToolBox
diff --git a/_overviews/quasiquotes/syntax-summary.md b/_overviews/quasiquotes/syntax-summary.md
index f38d08bf8c..2fd706a83a 100644
--- a/_overviews/quasiquotes/syntax-summary.md
+++ b/_overviews/quasiquotes/syntax-summary.md
@@ -120,7 +120,7 @@ permalink: /overviews/quasiquotes/:title.html
| Quasiquote | Type
------------------------------|-----------------------------------------------------------------------------------------------------------------------------|-----------
[Val][401] | `q"$mods val $tname: $tpt = $expr"` or `q"$mods val $pat = $expr"` | ValDef
- [Var][401] | `q"$mods var $tname: $tpt = $expr"` or `q"$mods val $pat = $expr"` | ValDef
+ [Var][401] | `q"$mods var $tname: $tpt = $expr"` or `q"$mods var $pat = $expr"` | ValDef
[Val Pattern][403] | `q"$mods val $pat: $tpt = $expr"` | Tree
[Var Pattern][404] | `q"$mods var $pat: $tpt = $expr"` | Tree
[Method][403] | `q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr"` | DefDef
diff --git a/_overviews/quasiquotes/terminology.md b/_overviews/quasiquotes/terminology.md
index c68d1828ad..ce5cf7eded 100644
--- a/_overviews/quasiquotes/terminology.md
+++ b/_overviews/quasiquotes/terminology.md
@@ -10,7 +10,7 @@ permalink: /overviews/quasiquotes/:title.html
---
EXPERIMENTAL
-* **Quasiquote** (not quasi-quote) can refer to either the quasiquote library or any usage of one its [interpolators](intro.html#interpolators). The name is not hyphenated for the sake of consistency with implementations of the same concept in other languages (e.g. [Scheme and Racket](https://docs.racket-lang.org/reference/quasiquote.html), [Haskell](https://www.haskell.org/haskellwiki/Quasiquotation))
+* **Quasiquote** (not quasi-quote) can refer to either the quasiquote library or any usage of one of its [interpolators](intro.html#interpolators). The name is not hyphenated for the sake of consistency with implementations of the same concept in other languages (e.g. [Scheme and Racket](https://docs.racket-lang.org/reference/quasiquote.html), [Haskell](https://wiki.haskell.org/Quasiquotation))
* **Tree** or **AST** (Abstract Syntax Tree) is a representation of a Scala program or a part of it through means of the Scala reflection API's Tree type.
* **Tree construction** refers to usages of quasiquotes as expressions to represent creation of new tree values.
* **Tree deconstruction** refers to usages of quasiquotes as patterns to structurally tear apart trees.
diff --git a/_overviews/quasiquotes/type-details.md b/_overviews/quasiquotes/type-details.md
index f67cd4e563..a3cd254d24 100644
--- a/_overviews/quasiquotes/type-details.md
+++ b/_overviews/quasiquotes/type-details.md
@@ -37,7 +37,7 @@ It is recommended to always ascribe the name as `TypeName` when you work with ty
## Singleton Type
-A singleton type is a way to express a type of a term definition that is being referenced:
+A singleton type is a way to express a type of term definition that is being referenced:
scala> val singleton = tq"foo.bar.type".sr
singleton: String = SingletonTypeTree(Select(Ident(TermName("foo")), TermName("bar")))
@@ -124,7 +124,7 @@ A compound type lets users express a combination of a number of types with an op
parents: List[universe.Tree] = List(A, B, C)
defns: List[universe.Tree] = List()
-Braces after parents are required to signal that this type is a compound type, even if there are no refinements and we just want to extract a sequence of types combined with the `with` keyword.
+Braces after parents are required to signal that this type is a compound type, even if there are no refinements, and we just want to extract a sequence of types combined with the `with` keyword.
On the other side of the spectrum are pure refinements without explicit parents (a.k.a. structural types):
diff --git a/_overviews/quasiquotes/unlifting.md b/_overviews/quasiquotes/unlifting.md
index e23f2d7152..adb8d4ed41 100644
--- a/_overviews/quasiquotes/unlifting.md
+++ b/_overviews/quasiquotes/unlifting.md
@@ -65,7 +65,7 @@ Here one must pay attention to a few nuances:
1. Similarly to `Liftable`, `Unliftable` defines a helper `apply` function in
the companion object to simplify the creation of `Unliftable` instances. It
- take a type parameter `T` as well as a partial function `PartialFunction[Tree, T]`
+ takes a type parameter `T` as well as a partial function `PartialFunction[Tree, T]`
and returns an `Unliftable[T]`. At all inputs where a partial function is defined
it is expected to return an instance of `T` unconditionally.
diff --git a/_overviews/reflection/annotations-names-scopes.md b/_overviews/reflection/annotations-names-scopes.md
index 7bf66cafcf..a4d1bbcce0 100644
--- a/_overviews/reflection/annotations-names-scopes.md
+++ b/_overviews/reflection/annotations-names-scopes.md
@@ -58,7 +58,7 @@ represent different kinds of Java annotation arguments:
## Names
Names are simple wrappers for strings.
-[Name](https://www.scala-lang.org/api/current/scala-reflect/scala/reflect/api/Names$NameApi.html)
+[Name](https://www.scala-lang.org/api/2.x/scala-reflect/scala/reflect/api/Names$NameApi.html)
has two subtypes `TermName` and `TypeName` which distinguish names of terms (like
objects or members) and types (like classes, traits, and type members). A term
and a type of the same name can co-exist in the same object. In other words,
@@ -104,19 +104,19 @@ There are both
Some names, such as "package", exist both as a type name and a term name.
Standard names are made available through the `termNames` and `typeNames` members of
class `Universe`. For a complete specification of all standard names, see the
-[API documentation](https://www.scala-lang.org/api/current/scala-reflect/scala/reflect/api/StandardNames.html).
+[API documentation](https://www.scala-lang.org/api/2.x/scala-reflect/scala/reflect/api/StandardNames.html).
## Scopes
A scope object generally maps names to symbols available in a corresponding
lexical scope. Scopes can be nested. The base type exposed in the reflection
API, however, only exposes a minimal interface, representing a scope as an
-iterable of [Symbol](https://www.scala-lang.org/api/current/scala-reflect/scala/reflect/api/Symbols$Symbol.html)s.
+iterable of [Symbol](https://www.scala-lang.org/api/2.x/scala-reflect/scala/reflect/api/Symbols$Symbol.html)s.
Additional functionality is exposed in *member scopes* that are returned by
`members` and `decls` defined in
-[scala.reflect.api.Types#TypeApi](https://www.scala-lang.org/api/current/scala-reflect/scala/reflect/api/Types$TypeApi.html).
-[scala.reflect.api.Scopes#MemberScope](https://www.scala-lang.org/api/current/scala-reflect/scala/reflect/api/Scopes$MemberScope.html)
+[scala.reflect.api.Types#TypeApi](https://www.scala-lang.org/api/2.x/scala-reflect/scala/reflect/api/Types$TypeApi.html).
+[scala.reflect.api.Scopes#MemberScope](https://www.scala-lang.org/api/2.x/scala-reflect/scala/reflect/api/Scopes$MemberScope.html)
supports the `sorted` method, which sorts members *in declaration order*.
The following example returns a list of the symbols of all final members
@@ -129,7 +129,7 @@ of the `List` class, in declaration order:
In addition to type `scala.reflect.api.Trees#Tree`, the base type of abstract
syntax trees, typed trees can also be represented as instances of type
-[`scala.reflect.api.Exprs#Expr`](https://www.scala-lang.org/api/current/scala-reflect/scala/reflect/api/Exprs$Expr.html).
+[`scala.reflect.api.Exprs#Expr`](https://www.scala-lang.org/api/2.x/scala-reflect/scala/reflect/api/Exprs$Expr.html).
An `Expr` wraps
an abstract syntax tree and an internal type tag to provide access to the type
of the tree. `Expr`s are mainly used to simply and conveniently create typed
@@ -189,9 +189,9 @@ expressions are compile-time constants (see [section 6.24 of the Scala language
2. String literals - represented as instances of the string.
-3. References to classes, typically constructed with [scala.Predef#classOf](https://www.scala-lang.org/api/current/index.html#scala.Predef$@classOf[T]:Class[T]) - represented as [types](https://www.scala-lang.org/api/current/scala-reflect/scala/reflect/api/Types$Type.html).
+3. References to classes, typically constructed with [scala.Predef#classOf](https://www.scala-lang.org/api/current/index.html#scala.Predef$@classOf[T]:Class[T]) - represented as [types](https://www.scala-lang.org/api/2.x/scala-reflect/scala/reflect/api/Types$Type.html).
-4. References to Java enumeration values - represented as [symbols](https://www.scala-lang.org/api/current/scala-reflect/scala/reflect/api/Symbols$Symbol.html).
+4. References to Java enumeration values - represented as [symbols](https://www.scala-lang.org/api/2.x/scala-reflect/scala/reflect/api/Symbols$Symbol.html).
Constant expressions are used to represent
@@ -287,8 +287,8 @@ Example:
## Printers
Utilities for nicely printing
-[`Trees`](https://www.scala-lang.org/api/current/scala-reflect/scala/reflect/api/Trees.html) and
-[`Types`](https://www.scala-lang.org/api/current/scala-reflect/scala/reflect/api/Types.html).
+[`Trees`](https://www.scala-lang.org/api/2.x/scala-reflect/scala/reflect/api/Trees.html) and
+[`Types`](https://www.scala-lang.org/api/2.x/scala-reflect/scala/reflect/api/Types.html).
### Printing Trees
@@ -408,7 +408,7 @@ additionally shows the unique identifiers of symbols, as well as their kind
## Positions
Positions (instances of the
-[Position](https://www.scala-lang.org/api/current/scala-reflect/scala/reflect/api/Position.html) trait)
+[Position](https://www.scala-lang.org/api/2.x/scala-reflect/scala/reflect/api/Position.html) trait)
are used to track the origin of symbols and tree nodes. They are commonly used when
displaying warnings and errors, to indicate the incorrect point in the
program. Positions indicate a column and line in a source file (the offset
diff --git a/_overviews/reflection/overview.md b/_overviews/reflection/overview.md
index 08dd5dcc58..d388e4016e 100644
--- a/_overviews/reflection/overview.md
+++ b/_overviews/reflection/overview.md
@@ -21,7 +21,7 @@ and logic programming paradigms.
While some languages are built around reflection as a guiding principle, many
languages progressively evolve their reflection abilities over time.
-Reflection involves the ability to **reify** (ie. make explicit) otherwise-implicit
+Reflection involves the ability to **reify** (i.e. make explicit) otherwise-implicit
elements of a program. These elements can be either static program elements
like classes, methods, or expressions, or dynamic elements like the current
continuation or execution events such as method invocations and field accesses.
@@ -130,7 +130,7 @@ available that are loaded by the current classloader, including class
The second step involves obtaining a `ClassMirror` for class `Person` using
the `reflectClass` method. The `ClassMirror` provides access to the
-constructor of class `Person`.
+constructor of class `Person`. (If this step causes an exception, the easy workaround is to use these flags when starting REPL. `scala -Yrepl-class-based:false`)
scala> val ctor = ru.typeOf[Person].decl(ru.termNames.CONSTRUCTOR).asMethod
ctor: scala.reflect.runtime.universe.MethodSymbol = constructor Person
@@ -262,7 +262,7 @@ precise runtime _types_ of these Scala objects. Scala runtime types carry
along all type info from compile-time, avoiding these types mismatches between
compile-time and run-time.
-Below, we use define a method which uses Scala reflection to get the runtime
+Below, we define a method which uses Scala reflection to get the runtime
types of its arguments, and then checks the subtyping relationship between the
two. If its first argument's type is a subtype of its second argument's type,
it returns `true`.
@@ -325,7 +325,7 @@ reflection, such as `Types`, `Trees`, and `Annotations`. For more details, see
the section of this guide on
[Universes]({{ site.baseurl}}/overviews/reflection/environment-universes-mirrors.html),
or the
-[Universes API docs](https://www.scala-lang.org/api/current/scala-reflect/scala/reflect/api/Universe.html)
+[Universes API docs](https://www.scala-lang.org/api/2.x/scala-reflect/scala/reflect/api/Universe.html)
in package `scala.reflect.api`.
To use most aspects of Scala reflection, including most code examples provided
@@ -345,5 +345,5 @@ different flavors of mirrors must be used.
For more details, see the section of this guide on
[Mirrors]({{ site.baseurl}}/overviews/reflection/environment-universes-mirrors.html),
or the
-[Mirrors API docs](https://www.scala-lang.org/api/current/scala-reflect/scala/reflect/api/Mirrors.html)
+[Mirrors API docs](https://www.scala-lang.org/api/2.x/scala-reflect/scala/reflect/api/Mirrors.html)
in package `scala.reflect.api`.
diff --git a/_overviews/reflection/symbols-trees-types.md b/_overviews/reflection/symbols-trees-types.md
index faad275ac0..4fba8ca28e 100644
--- a/_overviews/reflection/symbols-trees-types.md
+++ b/_overviews/reflection/symbols-trees-types.md
@@ -694,11 +694,11 @@ section:
It's important to note that, unlike `reify`, toolboxes aren't limited by the
typeability requirement-- although this flexibility is achieved by sacrificing
-robustness. That is, here we can see that `parse`, unlike `reify`, doesn’t
+robustness. That is, here we can see that `parse`, unlike `reify`, doesn't
reflect the fact that `println` should be bound to the standard `println`
method.
-_Note:_ when using macros, one shouldn’t use `ToolBox.parse`. This is because
+_Note:_ when using macros, one shouldn't use `ToolBox.parse`. This is because
there’s already a `parse` method built into the macro context. For example:
bash$ scala -Yrepl-class-based:false
@@ -726,7 +726,7 @@ and execute trees.
In addition to outlining the structure of the program, trees also hold
important information about the semantics of the program encoded in `symbol`
(a symbol assigned to trees that introduce or reference definitions), and
-`tpe` (the type of the tree). By default these fields are empty, but
+`tpe` (the type of the tree). By default, these fields are empty, but
typechecking fills them in.
When using the runtime reflection framework, typechecking is implemented by
diff --git a/_overviews/reflection/thread-safety.md b/_overviews/reflection/thread-safety.md
index 5ea8071637..6c5aaa2e11 100644
--- a/_overviews/reflection/thread-safety.md
+++ b/_overviews/reflection/thread-safety.md
@@ -6,7 +6,7 @@ overview-name: Reflection
num: 6
-languages: [ja]
+languages: [ja, zh-cn]
permalink: /overviews/reflection/:title.html
---
@@ -20,7 +20,7 @@ and to look up technical details, and here's a concise summary of the state of t
NEW Thread safety issues have been fixed in Scala 2.11.0-RC1, but we are going to keep this document available for now, since the problem still remains in the Scala 2.10.x series, and we currently don't have concrete plans on when the fix is going to be backported.
-Currently we know about two kinds of races associated with reflection. First of all, reflection initialization (the code that is called
+Currently, we know about two kinds of races associated with reflection. First of all, reflection initialization (the code that is called
when `scala.reflect.runtime.universe` is accessed for the first time) cannot be safely called from multiple threads. Secondly, symbol
initialization (the code that is called when symbol's flags or type signature are accessed for the first time) isn't safe as well.
Here's a typical manifestation:
diff --git a/_overviews/reflection/typetags-manifests.md b/_overviews/reflection/typetags-manifests.md
index e1c32a1c8f..6b6febff89 100644
--- a/_overviews/reflection/typetags-manifests.md
+++ b/_overviews/reflection/typetags-manifests.md
@@ -6,7 +6,7 @@ overview-name: Reflection
num: 5
-languages: [ja]
+languages: [ja, zh-cn]
permalink: /overviews/reflection/:title.html
---
diff --git a/_overviews/repl/overview.md b/_overviews/repl/overview.md
index 38d5008dd6..c462643399 100644
--- a/_overviews/repl/overview.md
+++ b/_overviews/repl/overview.md
@@ -79,4 +79,4 @@ Its facilities can be witnessed using `:imports` or `-Xprint:parser`.
### Contributing to Scala REPL
The REPL source is part of the Scala project. Issues are tracked by the standard
-mechanism for the project and pull requests are accepted at [the github repository](https://github.com/scala/scala).
+mechanism for the project and pull requests are accepted at [the GitHub repository](https://github.com/scala/scala).
diff --git a/_overviews/scala-book/abstract-classes.md b/_overviews/scala-book/abstract-classes.md
index a5ec3b96fa..88c496945c 100644
--- a/_overviews/scala-book/abstract-classes.md
+++ b/_overviews/scala-book/abstract-classes.md
@@ -5,11 +5,11 @@ title: Abstract Classes
description: This page shows how to use abstract classes, including when and why you should use abstract classes.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 27
outof: 54
previous-page: traits-abstract-mixins
next-page: collections-101
+new-version: /scala3/book/domain-modeling-tools.html#abstract-classes
---
@@ -107,11 +107,3 @@ d.speak
```
We encourage you to copy and paste that code into the REPL to be sure that it works as expected, and then experiment with it as desired.
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/anonymous-functions.md b/_overviews/scala-book/anonymous-functions.md
index bbd7bc8d8d..619d8854a7 100644
--- a/_overviews/scala-book/anonymous-functions.md
+++ b/_overviews/scala-book/anonymous-functions.md
@@ -5,11 +5,11 @@ title: Anonymous Functions
description: This page shows how to use anonymous functions in Scala, including examples with the List class 'map' and 'filter' functions.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 34
outof: 54
previous-page: set-class
next-page: collections-methods
+new-version: /scala3/book/fun-anonymous-functions.html
---
@@ -201,16 +201,3 @@ is the same as this example:
```scala
val y = ints.filter(_ < 5)
```
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/arraybuffer-examples.md b/_overviews/scala-book/arraybuffer-examples.md
index fba905bc89..06bd6d1af2 100644
--- a/_overviews/scala-book/arraybuffer-examples.md
+++ b/_overviews/scala-book/arraybuffer-examples.md
@@ -5,11 +5,11 @@ title: The ArrayBuffer Class
description: This page provides examples of how to use the Scala ArrayBuffer class, including adding and removing elements.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 29
outof: 54
previous-page: collections-101
next-page: list-class
+new-version: /scala3/book/collections-classes.html#arraybuffer
---
@@ -46,7 +46,7 @@ scala> ints += 2
res1: ints.type = ArrayBuffer(1, 2)
```
-That’s just one way create an `ArrayBuffer` and add elements to it. You can also create an `ArrayBuffer` with initial elements like this:
+That’s just one way to create an `ArrayBuffer` and add elements to it. You can also create an `ArrayBuffer` with initial elements like this:
```scala
val nums = ArrayBuffer(1, 2, 3)
@@ -114,31 +114,20 @@ As a brief overview, here are several methods you can use with an `ArrayBuffer`:
```scala
val a = ArrayBuffer(1, 2, 3) // ArrayBuffer(1, 2, 3)
a.append(4) // ArrayBuffer(1, 2, 3, 4)
-a.append(5, 6) // ArrayBuffer(1, 2, 3, 4, 5, 6)
-a.appendAll(Seq(7,8)) // ArrayBuffer(1, 2, 3, 4, 5, 6, 7, 8)
+a.appendAll(Seq(5, 6)) // ArrayBuffer(1, 2, 3, 4, 5, 6)
a.clear // ArrayBuffer()
val a = ArrayBuffer(9, 10) // ArrayBuffer(9, 10)
a.insert(0, 8) // ArrayBuffer(8, 9, 10)
a.insertAll(0, Vector(4, 5, 6, 7)) // ArrayBuffer(4, 5, 6, 7, 8, 9, 10)
a.prepend(3) // ArrayBuffer(3, 4, 5, 6, 7, 8, 9, 10)
-a.prepend(1, 2) // ArrayBuffer(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
-a.prependAll(Array(0)) // ArrayBuffer(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+a.prependAll(Array(0, 1, 2)) // ArrayBuffer(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val a = ArrayBuffer.range('a', 'h') // ArrayBuffer(a, b, c, d, e, f, g)
a.remove(0) // ArrayBuffer(b, c, d, e, f, g)
a.remove(2, 3) // ArrayBuffer(b, c, g)
val a = ArrayBuffer.range('a', 'h') // ArrayBuffer(a, b, c, d, e, f, g)
-a.trimStart(2) // ArrayBuffer(c, d, e, f, g)
-a.trimEnd(2) // ArrayBuffer(c, d, e)
+a.dropInPlace(2) // ArrayBuffer(c, d, e, f, g)
+a.dropRightInPlace(2) // ArrayBuffer(c, d, e)
```
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/built-in-types.md b/_overviews/scala-book/built-in-types.md
index 209b1b8f0b..c251b9a4f1 100644
--- a/_overviews/scala-book/built-in-types.md
+++ b/_overviews/scala-book/built-in-types.md
@@ -5,11 +5,11 @@ title: A Few Built-In Types
description: A brief introduction to Scala's built-in types.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 10
outof: 54
previous-page: type-is-optional
next-page: two-notes-about-strings
+new-version: /scala3/book/first-look-at-types.html#scalas-value-types
---
@@ -106,10 +106,3 @@ val c: Char = 'a'
```
As shown, enclose strings in double-quotes and a character in single-quotes.
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/case-classes.md b/_overviews/scala-book/case-classes.md
index 8722d4c5ae..9ffae6db23 100644
--- a/_overviews/scala-book/case-classes.md
+++ b/_overviews/scala-book/case-classes.md
@@ -5,11 +5,11 @@ title: Case Classes
description: This lesson provides an introduction to 'case classes' in Scala.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 49
outof: 54
previous-page: companion-objects
next-page: case-objects
+new-version: /scala3/book/domain-modeling-tools.html#case-classes
---
@@ -185,5 +185,3 @@ res0: Person = Person(Christina,niece)
## The biggest advantage
While all of these features are great benefits to functional programming, as they write in the book, [Programming in Scala](https://www.amazon.com/Programming-Scala-Updated-2-12/dp/0981531687/) (Odersky, Spoon, and Venners), “the biggest advantage of case classes is that they support pattern matching.” Pattern matching is a major feature of FP languages, and Scala’s case classes provide a simple way to implement pattern matching in match expressions and other areas.
-
-
diff --git a/_overviews/scala-book/case-objects.md b/_overviews/scala-book/case-objects.md
index 1b7426f12a..9bb17d2ec7 100644
--- a/_overviews/scala-book/case-objects.md
+++ b/_overviews/scala-book/case-objects.md
@@ -5,11 +5,11 @@ title: Case Objects
description: This lesson introduces Scala 'case objects', which are used to create singletons with a few additional features.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 50
outof: 54
previous-page: case-classes
next-page: functional-error-handling
+new-version: /scala3/book/domain-modeling-tools.html#case-objects
---
@@ -123,11 +123,3 @@ class Speak extends Actor {
```
This is a good, safe way to pass messages around in Scala applications.
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/classes-aux-constructors.md b/_overviews/scala-book/classes-aux-constructors.md
index a66a4b4d80..8bca7dc8cf 100644
--- a/_overviews/scala-book/classes-aux-constructors.md
+++ b/_overviews/scala-book/classes-aux-constructors.md
@@ -5,11 +5,11 @@ title: Auxiliary Class Constructors
description: This page shows how to write auxiliary Scala class constructors, including several examples of the syntax.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 20
outof: 54
previous-page: classes
next-page: constructors-default-values
+new-version: /scala3/book/domain-modeling-tools.html#auxiliary-constructors
---
@@ -72,11 +72,3 @@ class Pizza(
var crustType: String = DefaultCrustType
)
```
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/classes.md b/_overviews/scala-book/classes.md
index bc4fe65b66..bc7928eea0 100644
--- a/_overviews/scala-book/classes.md
+++ b/_overviews/scala-book/classes.md
@@ -5,11 +5,11 @@ title: Scala Classes
description: This page shows examples of how to create Scala classes, including the basic Scala class constructor.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 19
outof: 54
previous-page: try-catch-finally
next-page: classes-aux-constructors
+new-version: /scala3/book/domain-modeling-tools.html#classes
---
@@ -209,14 +209,3 @@ class Address (
var state: String
)
```
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/collections-101.md b/_overviews/scala-book/collections-101.md
index 6df136b528..995c20520b 100644
--- a/_overviews/scala-book/collections-101.md
+++ b/_overviews/scala-book/collections-101.md
@@ -5,11 +5,11 @@ title: Scala Collections
description: This page provides an introduction to the Scala collections classes, including Vector, List, ArrayBuffer, Map, Set, and more.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 28
outof: 54
previous-page: abstract-classes
next-page: arraybuffer-examples
+new-version: /scala3/book/collections-intro.html
---
@@ -34,6 +34,3 @@ The main Scala collections classes you’ll use on a regular basis are:
We’ll demonstrate the basics of these classes in the following lessons.
>In the following lessons on Scala collections classes, whenever we use the word *immutable*, it’s safe to assume that the class is intended for use in a *functional programming* (FP) style. With these classes you don’t modify the collection; you apply functional methods to the collection to create a new result. You’ll see what this means in the examples that follow.
-
-
-
diff --git a/_overviews/scala-book/collections-maps.md b/_overviews/scala-book/collections-maps.md
index 1556a66ef8..0abc9da611 100644
--- a/_overviews/scala-book/collections-maps.md
+++ b/_overviews/scala-book/collections-maps.md
@@ -5,11 +5,11 @@ title: Common Map Methods
description: This page shows examples of the most common methods that are available on Scala Maps.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 36
outof: 54
previous-page: collections-methods
next-page: misc
+new-version: /scala3/book/collections-methods.html
---
@@ -83,18 +83,18 @@ Here are some things you can do with a mutable `Map`:
```scala
// add elements with +=
states += ("AZ" -> "Arizona")
-states += ("CO" -> "Colorado", "KY" -> "Kentucky")
+states ++= Map("CO" -> "Colorado", "KY" -> "Kentucky")
// remove elements with -=
states -= "KY"
-states -= ("AZ", "CO")
+states --= List("AZ", "CO")
// update elements by reassigning them
states("AK") = "Alaska, The Big State"
-// retain elements by supplying a function that operates on
+// filter elements by supplying a function that operates on
// the keys and/or values
-states.retain((k,v) => k == "AK")
+states.filterInPlace((k,v) => k == "AK")
```
@@ -102,13 +102,3 @@ states.retain((k,v) => k == "AK")
## See also
There are many more things you can do with maps. See the [Map class documentation]({{site.baseurl}}/overviews/collections-2.13/maps.html) for more details and examples.
-
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/collections-methods.md b/_overviews/scala-book/collections-methods.md
index 7bd8d9a15a..e6620ec6cc 100644
--- a/_overviews/scala-book/collections-methods.md
+++ b/_overviews/scala-book/collections-methods.md
@@ -5,11 +5,11 @@ title: Common Sequence Methods
description: This page shows examples of the most common methods that are available on the Scala sequences (collections classes).
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 35
outof: 54
previous-page: anonymous-functions
next-page: collections-maps
+new-version: /scala3/book/collections-methods.html
---
@@ -320,8 +320,3 @@ That might be a little mind-blowing if you’ve never seen it before, but after
## Even more!
There are literally dozens of additional methods on the Scala sequence classes that will keep you from ever needing to write another `for` loop. However, because this is a simple introduction book they won’t all be covered here. For more information, see [the collections overview of sequence traits]({{site.baseurl}}/overviews/collections-2.13/seqs.html).
-
-
-
-
-
diff --git a/_overviews/scala-book/command-line-io.md b/_overviews/scala-book/command-line-io.md
index ffb35f698e..b3ea6ca64c 100644
--- a/_overviews/scala-book/command-line-io.md
+++ b/_overviews/scala-book/command-line-io.md
@@ -5,11 +5,11 @@ title: Command-Line I/O
description: An introduction to command-line I/O in Scala.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 12
outof: 54
previous-page: two-notes-about-strings
next-page: control-structures
+new-version: /scala3/book/taste-hello-world.html#ask-for-user-input
---
@@ -98,12 +98,3 @@ import scala.io.StdIn.readLine
```
That import statement brings the `readLine` method into the current scope so you can use it in the application.
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/companion-objects.md b/_overviews/scala-book/companion-objects.md
index 6babb21eb9..dc8cb8b1d3 100644
--- a/_overviews/scala-book/companion-objects.md
+++ b/_overviews/scala-book/companion-objects.md
@@ -5,11 +5,11 @@ title: Companion Objects
description: This lesson provides an introduction to 'companion objects' in Scala, including writing 'apply' and 'unapply' methods.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 48
outof: 54
previous-page: no-null-values
next-page: case-classes
+new-version: /scala3/book/domain-modeling-tools.html#companion-objects
---
@@ -271,13 +271,3 @@ The key points of this lesson are:
- A companion object and its class can access each other’s private members
- A companion object’s `apply` method lets you create new instances of a class without using the `new` keyword
- A companion object’s `unapply` method lets you de-construct an instance of a class into its individual components
-
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/concurrency-signpost.md b/_overviews/scala-book/concurrency-signpost.md
index 1629700299..49ab2cd094 100644
--- a/_overviews/scala-book/concurrency-signpost.md
+++ b/_overviews/scala-book/concurrency-signpost.md
@@ -5,13 +5,12 @@ title: Concurrency
description: An introduction to concurrency in Scala.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 52
outof: 54
previous-page: functional-error-handling
next-page: futures
+new-version: /scala3/book/concurrency.html
---
In the next lesson you’ll see a primary tool for writing parallel and concurrent applications, the Scala `Future`.
-
diff --git a/_overviews/scala-book/constructors-default-values.md b/_overviews/scala-book/constructors-default-values.md
index aa4429305e..952fe3fd46 100644
--- a/_overviews/scala-book/constructors-default-values.md
+++ b/_overviews/scala-book/constructors-default-values.md
@@ -5,11 +5,11 @@ title: Supplying Default Values for Constructor Parameters
description: This page shows how to provide default values for Scala constructor parameters, with several examples.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 21
outof: 54
previous-page: classes-aux-constructors
next-page: methods-first-look
+new-version: /scala3/book/domain-modeling-tools.html#default-parameter-values
---
Scala lets you supply default values for constructor parameters. For example, in previous lessons we showed that you can define a `Socket` class like this:
@@ -88,12 +88,3 @@ is more readable than this code:
```scala
val s = new Socket(2000, 3000)
```
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/control-structures.md b/_overviews/scala-book/control-structures.md
index 813a05face..8724ba7050 100644
--- a/_overviews/scala-book/control-structures.md
+++ b/_overviews/scala-book/control-structures.md
@@ -5,11 +5,11 @@ title: Control Structures
description: This page provides an introduction to Scala's control structures, including if/then/else, for loops, try/catch/finally, etc.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 13
outof: 54
previous-page: command-line-io
next-page: if-then-else-construct
+new-version: /scala3/book/control-structures.html
---
@@ -25,10 +25,3 @@ It also has a few unique constructs, including:
- `for` expressions
We’ll demonstrate these in the following lessons.
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/enumerations-pizza-class.md b/_overviews/scala-book/enumerations-pizza-class.md
index 31625129f0..abe76d8b07 100644
--- a/_overviews/scala-book/enumerations-pizza-class.md
+++ b/_overviews/scala-book/enumerations-pizza-class.md
@@ -5,11 +5,11 @@ title: Enumerations (and a Complete Pizza Class)
description: This page introduces Scala enumerations, and further shows how to create a complete OOP 'Pizza' class that uses those enumerations.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 23
outof: 54
previous-page: methods-first-look
next-page: traits-intro
+new-version: /scala3/book/domain-modeling-fp.html#modeling-the-data
---
@@ -186,7 +186,3 @@ Toppings: ArrayBuffer(Cheese, Pepperoni)
That code combines several different concepts — including two things we haven’t discussed yet in the `import` statement and the `ArrayBuffer` — but if you have experience with Java and other languages, hopefully it’s not too much to throw at you at one time.
At this point we encourage you to work with that code as desired. Make changes to the code, and try using the `removeTopping` and `removeAllToppings` methods to make sure they work the way you expect them to work.
-
-
-
-
diff --git a/_overviews/scala-book/for-expressions.md b/_overviews/scala-book/for-expressions.md
index 7977777872..e7e5c0a90a 100644
--- a/_overviews/scala-book/for-expressions.md
+++ b/_overviews/scala-book/for-expressions.md
@@ -5,11 +5,11 @@ title: for Expressions
description: This page shows how to use Scala 'for' expressions (also known as 'for-expressions'), including examples of how to use it with the 'yield' keyword.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 16
outof: 54
previous-page: for-loops
next-page: match-expressions
+new-version: /scala3/book/control-structures.html#for-expressions
---
@@ -125,11 +125,3 @@ You can also put curly braces around the algorithm, if you prefer:
```scala
val capNames = for (name <- names) yield { name.drop(1).capitalize }
```
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/for-loops.md b/_overviews/scala-book/for-loops.md
index 5eef6cc279..b462c4d289 100644
--- a/_overviews/scala-book/for-loops.md
+++ b/_overviews/scala-book/for-loops.md
@@ -5,11 +5,11 @@ title: for Loops
description: This page provides an introduction to the Scala 'for' loop, including how to iterate over Scala collections.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 15
outof: 54
previous-page: if-then-else-construct
next-page: for-expressions
+new-version: /scala3/book/control-structures.html#for-loops
---
@@ -107,7 +107,3 @@ ratings.foreach {
case(movie, rating) => println(s"key: $movie, value: $rating")
}
```
-
-
-
-
diff --git a/_overviews/scala-book/functional-error-handling.md b/_overviews/scala-book/functional-error-handling.md
index 84d4cd2145..bdbcc2f228 100644
--- a/_overviews/scala-book/functional-error-handling.md
+++ b/_overviews/scala-book/functional-error-handling.md
@@ -5,11 +5,11 @@ title: Functional Error Handling in Scala
description: This lesson takes a look at error handling with functional programming in Scala.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 51
outof: 54
previous-page: case-objects
next-page: concurrency-signpost
+new-version: /scala3/book/fp-functional-error-handling.html
---
@@ -55,7 +55,7 @@ These approaches were discussed in the “No Null Values” lesson, so we won’
Another trio of classes named `Try`, `Success`, and `Failure` work just like `Option`, `Some`, and `None`, but with two nice features:
- `Try` makes it very simple to catch exceptions
-- `Failure` contains the exception message
+- `Failure` contains the exception
Here’s the `toInt` method re-written to use these classes. First, import the classes into the current scope:
@@ -93,7 +93,7 @@ scala> val b = toInt("boo")
b: scala.util.Try[Int] = Failure(java.lang.NumberFormatException: For input string: "boo")
```
-As that output shows, the `Failure` that’s returned by `toInt` contains the reason for the failure, i.e., the exception message.
+As that output shows, the `Failure` that’s returned by `toInt` contains the reason for the failure, i.e., the exception.
There are quite a few ways to work with the results of a `Try` — including the ability to “recover” from the failure — but common approaches still involve using `match` and `for` expressions:
@@ -129,15 +129,3 @@ scala.util.Try[Int] = Failure(java.lang.NumberFormatException: For input string:
There are other classes that work in a similar manner, including Either/Left/Right in the Scala library, and other third-party libraries, but Option/Some/None and Try/Success/Failure are commonly used, and good to learn first.
You can use whatever you like, but Try/Success/Failure is generally used when dealing with code that can throw exceptions — because you almost always want to understand the exception — and Option/Some/None is used in other places, such as to avoid using null values.
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/functional-programming.md b/_overviews/scala-book/functional-programming.md
index aa0581cf87..806697f189 100644
--- a/_overviews/scala-book/functional-programming.md
+++ b/_overviews/scala-book/functional-programming.md
@@ -5,11 +5,11 @@ title: Functional Programming
description: This lesson begins a second on 'An introduction to functional programming in Scala'.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 44
outof: 54
previous-page: sbt-scalatest-bdd
next-page: pure-functions
+new-version: /scala3/book/fp-intro.html
---
@@ -19,13 +19,3 @@ Scala lets you write code in an object-oriented programming (OOP) style, a funct
*Functional programming* is a style of programming that emphasizes writing applications using only pure functions and immutable values. As Alvin Alexander wrote in [Functional Programming, Simplified](https://alvinalexander.com/scala/functional-programming-simplified-book), rather than using that description, it can be helpful to say that functional programmers have an extremely strong desire to see their code as math — to see the combination of their functions as a series of algebraic equations. In that regard, you could say that functional programmers like to think of themselves as mathematicians. That’s the driving desire that leads them to use *only* pure functions and immutable values, because that’s what you use in algebra and other forms of math.
Functional programming is a large topic, and there’s no simple way to condense the entire topic into this little book, but in the following lessons we’ll give you a taste of FP, and show some of the tools Scala provides for developers to write functional code.
-
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/futures.md b/_overviews/scala-book/futures.md
index 9324b0ddf9..8493ed1931 100644
--- a/_overviews/scala-book/futures.md
+++ b/_overviews/scala-book/futures.md
@@ -5,11 +5,11 @@ title: Scala Futures
description: This page provides an introduction to Futures in Scala, including Future callback methods.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 53
outof: 54
previous-page: concurrency-signpost
next-page: where-next
+new-version: /scala3/book/concurrency.html
---
When you want to write parallel and concurrent applications in Scala, you *could* still use the native Java `Thread` — but the Scala [Future](https://www.scala-lang.org/api/current/scala/concurrent/Future$.html) makes parallel/concurrent programming much simpler, and it’s preferred.
@@ -348,12 +348,3 @@ While this was a short introduction, hopefully those examples give you an idea o
- A small demo GUI application named *Future Board* was written to accompany this lesson. It works a little like [Flipboard](https://flipboard.com), updating a group of news sources simultaneously. You can find the source code for Future Board in [this Github repository](https://github.com/alvinj/FPFutures).
- While futures are intended for one-short, relatively short-lived concurrent processes, [Akka](https://akka.io) is an “actor model” library for Scala, and provides a terrific way to implement long-running parallel processes. (If this term is new to you, an *actor* is a long-running process that runs in parallel to the main application thread, and responds to messages that are sent to it.)
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/hello-world-1.md b/_overviews/scala-book/hello-world-1.md
index c9793a2376..d9f9ddc0c6 100644
--- a/_overviews/scala-book/hello-world-1.md
+++ b/_overviews/scala-book/hello-world-1.md
@@ -5,11 +5,11 @@ title: Hello, World
description: This page shares a Scala 'Hello, world' example.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 5
outof: 54
previous-page: scala-features
next-page: hello-world-2
+new-version: /scala3/book/taste-hello-world.html
---
Since the release of the book, *C Programming Language*, most programming books have begun with a simple “Hello, world” example, and in keeping with tradition, here’s the source code for a Scala “Hello, world” example:
@@ -87,7 +87,3 @@ public final class Hello {
````
As that output shows, the `javap` command reads that *.class* file just as if it was created from Java source code. Scala code runs on the JVM and can use existing Java libraries — and both are terrific benefits for Scala programmers.
-
-
-
-
diff --git a/_overviews/scala-book/hello-world-2.md b/_overviews/scala-book/hello-world-2.md
index d07b7da00f..ac2f61cfe2 100644
--- a/_overviews/scala-book/hello-world-2.md
+++ b/_overviews/scala-book/hello-world-2.md
@@ -5,11 +5,11 @@ title: Hello, World - Version 2
description: This is a second Scala 'Hello, World' example.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 6
outof: 54
previous-page: hello-world-1
next-page: scala-repl
+new-version: /scala3/book/taste-hello-world.html
---
While that first “Hello, World” example works just fine, Scala provides a way to write applications more conveniently. Rather than including a `main` method, your `object` can just extend the `App` trait, like this:
@@ -62,15 +62,3 @@ This shows:
- Command-line arguments are automatically made available to you in a variable named `args`.
- You determine the number of elements in `args` with `args.size` (or `args.length`, if you prefer).
- `args` is an `Array`, and you access `Array` elements as `args(0)`, `args(1)`, etc. Because `args` is an object, you access the array elements with parentheses (not `[]` or any other special syntax).
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/if-then-else-construct.md b/_overviews/scala-book/if-then-else-construct.md
index 6fd09ef879..7087c3340c 100644
--- a/_overviews/scala-book/if-then-else-construct.md
+++ b/_overviews/scala-book/if-then-else-construct.md
@@ -5,11 +5,11 @@ title: The if/then/else Construct
description: This page demonstrates Scala's if/then/else construct, including several examples you can try in the REPL.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 14
outof: 54
previous-page: control-structures
next-page: for-loops
+new-version: /scala3/book/control-structures.html#the-ifthenelse-construct
---
@@ -79,10 +79,3 @@ println("Hello")
```
The first example runs the `doSomething` method as a side effect when `a` is equal to `b`. The second example is used for the side effect of writing a string to STDOUT. As you learn more about Scala you’ll find yourself writing more *expressions* and fewer *statements*. The differences between expressions and statements will also become more apparent.
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/introduction.md b/_overviews/scala-book/introduction.md
index 7b417388fb..42bfe49502 100644
--- a/_overviews/scala-book/introduction.md
+++ b/_overviews/scala-book/introduction.md
@@ -8,6 +8,7 @@ overview-name: Scala Book
num: 1
outof: 54
next-page: prelude-taste-of-scala
+new-version: /scala3/book/introduction.html
---
In these pages, *Scala Book* provides a quick introduction and overview of the Scala programming language. The book is written in an informal style, and consists of more than 50 small lessons. Each lesson is long enough to give you an idea of how the language features in that lesson work, but short enough that you can read it in fifteen minutes or less.
@@ -17,10 +18,3 @@ One note before beginning:
- In regards to programming style, most Scala programmers indent their code with two spaces, but we use four spaces because we think it makes the code easier to read, especially in a book format.
To begin reading, click the “next” link, or select the *Prelude: A Taste of Scala* lesson in the table of contents.
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/list-class.md b/_overviews/scala-book/list-class.md
index 1a606afc98..568463f1f7 100644
--- a/_overviews/scala-book/list-class.md
+++ b/_overviews/scala-book/list-class.md
@@ -5,11 +5,11 @@ title: The List Class
description: This page provides examples of the Scala List class, including how to add and remove elements from a List.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 30
outof: 54
previous-page: arraybuffer-examples
next-page: vector-class
+new-version: /scala3/book/collections-classes.html#list
---
[The List class](https://www.scala-lang.org/api/current/scala/collection/immutable/List.html) is a linear, immutable sequence. All this means is that it’s a linked-list that you can’t modify. Any time you want to add or remove `List` elements, you create a new `List` from an existing `List`.
@@ -140,15 +140,3 @@ list: List[Int] = List(1, 2, 3)
```
This works because a `List` is a singly-linked list that ends with the `Nil` element.
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/map-class.md b/_overviews/scala-book/map-class.md
index 4a7d48db98..88efb3eec8 100644
--- a/_overviews/scala-book/map-class.md
+++ b/_overviews/scala-book/map-class.md
@@ -5,11 +5,11 @@ title: The Map Class
description: This page provides examples of the Scala 'Map' class, including how to add and remove elements from a Map, and iterate over Map elements.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 32
outof: 54
previous-page: vector-class
next-page: set-class
+new-version: /scala3/book/collections-classes.html#maps
---
@@ -158,12 +158,3 @@ ratings.foreach {
## See also
There are other ways to work with Scala Maps, and a nice collection of Map classes for different needs. See the [Map class documentation]({{site.baseurl}}/overviews/collections-2.13/maps.html) for more information and examples.
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/match-expressions.md b/_overviews/scala-book/match-expressions.md
index 4b54dfb35c..1c19d09c07 100644
--- a/_overviews/scala-book/match-expressions.md
+++ b/_overviews/scala-book/match-expressions.md
@@ -5,11 +5,11 @@ title: match Expressions
description: This page shows examples of the Scala 'match' expression, including how to write match/case expressions.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 17
outof: 54
previous-page: for-expressions
next-page: try-catch-finally
+new-version: /scala3/book/control-structures.html#match-expressions
---
@@ -247,11 +247,3 @@ stock match {
## Even more
`match` expressions are very powerful, and there are even more things you can do with them, but hopefully these examples provide a good start towards using them.
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/methods-first-look.md b/_overviews/scala-book/methods-first-look.md
index 7e10bdfd77..7a8d8bb71e 100644
--- a/_overviews/scala-book/methods-first-look.md
+++ b/_overviews/scala-book/methods-first-look.md
@@ -5,11 +5,11 @@ title: A First Look at Scala Methods
description: This page provides a first look at how to write Scala methods, including how to test them in the REPL.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 22
outof: 54
previous-page: constructors-default-values
next-page: enumerations-pizza-class
+new-version: /scala3/book/methods-intro.html
---
@@ -104,9 +104,3 @@ If you paste that code into the REPL, you’ll see that it works just like the p
scala> addThenDouble(1, 1)
res0: Int = 4
```
-
-
-
-
-
-
diff --git a/_overviews/scala-book/misc.md b/_overviews/scala-book/misc.md
index 61c19bd1b2..d7c7b77c89 100644
--- a/_overviews/scala-book/misc.md
+++ b/_overviews/scala-book/misc.md
@@ -5,11 +5,11 @@ title: A Few Miscellaneous Items
description: A few miscellaneous items about Scala
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 37
outof: 54
previous-page: collections-maps
next-page: tuples
+new-version: /scala3/book/introduction.html
---
@@ -17,5 +17,3 @@ In this section we’ll cover a few miscellaneous items about Scala:
- Tuples
- A Scala OOP example of a pizza restaurant order-entry system
-
-
diff --git a/_overviews/scala-book/no-null-values.md b/_overviews/scala-book/no-null-values.md
index dc77febe52..66771927f0 100644
--- a/_overviews/scala-book/no-null-values.md
+++ b/_overviews/scala-book/no-null-values.md
@@ -5,11 +5,11 @@ title: No Null Values
description: This lesson demonstrates the Scala Option, Some, and None classes, including how to use them instead of null values.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 47
outof: 54
previous-page: passing-functions-around
next-page: companion-objects
+new-version: /scala3/book/fp-functional-error-handling.html
---
@@ -120,7 +120,7 @@ val y = for {
When that expression finishes running, `y` will be one of two things:
- If all three strings convert to integers, `y` will be a `Some[Int]`, i.e., an integer wrapped inside a `Some`
-- If any of the three strings can’t be converted to an inside, `y` will be a `None`
+- If any of the three strings can’t be converted to an integer, `y` will be a `None`
You can test this for yourself in the Scala REPL. First, paste these three string variables into the REPL:
@@ -301,10 +301,3 @@ This lesson was a little longer than the others, so here’s a quick review of t
## See also
- Tony Hoare invented the null reference in 1965, and refers to it as his “[billion dollar mistake](https://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions).”
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/oop-pizza-example.md b/_overviews/scala-book/oop-pizza-example.md
index 7d50686e71..a7d11f9ff5 100644
--- a/_overviews/scala-book/oop-pizza-example.md
+++ b/_overviews/scala-book/oop-pizza-example.md
@@ -5,11 +5,11 @@ title: An OOP Example
description: This lesson shares an example of some OOP-style classes for a pizza restaurant order entry system, including Pizza, Topping, and Order classes.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 39
outof: 54
previous-page: tuples
next-page: sbt-scalatest-intro
+new-version: /scala3/book/domain-modeling-oop.html
---
@@ -216,9 +216,4 @@ To experiment with this on your own, please see the *PizzaOopExample* project in
- [github.com/alvinj/HelloScalaExamples](https://github.com/alvinj/HelloScalaExamples)
-To compile this project it will help to either (a) use IntelliJ IDEA or Eclipse, or (b) know how to use the [Scala Build Tool](http://www.scala-sbt.org).
-
-
-
-
-
+To compile this project it will help to either (a) use IntelliJ IDEA or Metals, or (b) know how to use the [Scala Build Tool](http://www.scala-sbt.org).
diff --git a/_overviews/scala-book/passing-functions-around.md b/_overviews/scala-book/passing-functions-around.md
index 2700ea06c7..91ca50d198 100644
--- a/_overviews/scala-book/passing-functions-around.md
+++ b/_overviews/scala-book/passing-functions-around.md
@@ -5,11 +5,11 @@ title: Passing Functions Around
description: Like a good functional programming language, Scala lets you use functions just like other variables, including passing them into other functions.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 46
outof: 54
previous-page: pure-functions
next-page: no-null-values
+new-version: /scala3/book/fp-functions-are-values.html
---
@@ -104,11 +104,3 @@ Those examples that use a “regular” function are equivalent to these anonymo
List("foo", "bar").map(s => s.toUpperCase)
List("foo", "bar").map(_.toUpperCase)
```
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/preliminaries.md b/_overviews/scala-book/preliminaries.md
index e8057e37d9..8308f59818 100644
--- a/_overviews/scala-book/preliminaries.md
+++ b/_overviews/scala-book/preliminaries.md
@@ -5,11 +5,11 @@ title: Preliminaries
description: A few things to know about getting started with Scala.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 3
outof: 54
previous-page: prelude-taste-of-scala
next-page: scala-features
+new-version: /scala3/book/taste-intro.html#setting-up-scala
---
@@ -21,7 +21,7 @@ That being said, there are a few good things to know before you read this book.
## Installing Scala
-First, to run the examples in this book you’ll need to install Scala on your computer. See our general [Getting Started]({{site.baseurl}}/getting-started/index.html) page for details on how to use Scala (a) in an IDE and (b) from the command line.
+First, to run the examples in this book you’ll need to install Scala on your computer. See our general [Getting Started]({{site.baseurl}}/getting-started/install-scala.html) page for details on how to use Scala (a) in an IDE and (b) from the command line.
@@ -45,11 +45,10 @@ One good thing to know up front is that comments in Scala are just like comments
## IDEs
-The three main IDEs (integrated development environments) for Scala are:
+The two main IDEs (integrated development environments) for Scala are:
- [IntelliJ IDEA](https://www.jetbrains.com/idea/download)
- [Visual Studio Code](https://code.visualstudio.com)
-- [Scala IDE for Eclipse](http://scala-ide.org)
@@ -60,12 +59,3 @@ Another good thing to know is that Scala naming conventions follow the same “c
- Class names: `Person`, `StoreEmployee`
- Variable names: `name`, `firstName`
- Method names: `convertToInt`, `toUpper`
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/prelude-taste-of-scala.md b/_overviews/scala-book/prelude-taste-of-scala.md
index 1564032440..970631acf6 100644
--- a/_overviews/scala-book/prelude-taste-of-scala.md
+++ b/_overviews/scala-book/prelude-taste-of-scala.md
@@ -5,16 +5,16 @@ title: Prelude꞉ A Taste of Scala
description: This page shares a Taste Of Scala example, quickly covering Scala's main features.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 2
outof: 54
previous-page: introduction
next-page: preliminaries
+new-version: /scala3/book/taste-intro.html
---
Our hope in this book is to demonstrate that [Scala](http://scala-lang.org) is a beautiful, modern, expressive programming language. To help demonstrate that, in this first chapter we’ll jump right in and provide a whirlwind tour of Scala’s main features. After this tour, the book begins with a more traditional “Getting Started” chapter.
->In this book we assume that you’ve used a language like Java before, and are ready to see a series of Scala examples to get a feel for what the language looks like. Although it’s not 100% necessary, it will also help if you’ve already [downloaded and installed Scala](https://www.scala-lang.org/download) so you can test the examples as you go along. You can also test these examples online with [ScalaFiddle.io](https://scalafiddle.io).
+>In this book we assume that you’ve used a language like Java before, and are ready to see a series of Scala examples to get a feel for what the language looks like. Although it’s not 100% necessary, it will also help if you’ve already [downloaded and installed Scala](https://www.scala-lang.org/download) so you can test the examples as you go along. You can also test these examples online with [Scastie](https://scastie.scala-lang.org/).
@@ -462,19 +462,30 @@ There are many (many!) more methods available to Scala collections classes, and
## Tuples
-Tuples let you put a heterogenous collection of elements in a little container. Tuples can contain between two and 22 values, and they can all be different types. For example, given a `Person` class like this:
+Tuples let you put a heterogenous collection of elements in a little container. A tuple can contain between two and 22 values, and all of the values can have different types. For example, this is a tuple that holds three different types, an `Int`, a `Double`, and a `String`:
```scala
-class Person(var name: String)
+(11, 11.0, "Eleven")
```
-You can create a tuple that contains three different types like this:
+This is known as a `Tuple3`, because it contains three elements.
+
+Tuples are convenient in many places, such as where you might use an ad-hoc class in other languages. For instance, you can return a tuple from a method instead of returning a class:
```scala
-val t = (11, "Eleven", new Person("Eleven"))
+def getAaplInfo(): (String, BigDecimal, Long) = {
+ // get the stock symbol, price, and volume
+ ("AAPL", BigDecimal(123.45), 101202303L)
+}
```
-You can access the tuple values by number:
+Then you can assign the result of the method to a variable:
+
+```scala
+val t = getAaplInfo()
+```
+
+Once you have a tuple variable, you can access its values by number, preceded by an underscore:
```scala
t._1
@@ -482,13 +493,39 @@ t._2
t._3
```
-Or assign the tuple fields to variables:
+The REPL demonstrates the results of accessing those fields:
+
+```scala
+scala> t._1
+res0: String = AAPL
+
+scala> t._2
+res1: scala.math.BigDecimal = 123.45
+
+scala> t._3
+res2: Long = 101202303
+```
+
+The values of a tuple can also be extracted using pattern matching. In this next example, the fields inside the tuple are assigned to the variables `symbol`, `price`, and `volume`:
+
+```scala
+val (symbol, price, volume) = getAaplInfo()
+```
+
+Once again, the REPL shows the result:
```scala
-val (num, string, person) = (11, "Eleven", new Person("Eleven"))
+scala> val (symbol, price, volume) = getAaplInfo()
+symbol: String = AAPL
+price: scala.math.BigDecimal = 123.45
+volume: Long = 101202303
```
-Tuples are nice for those times when you need to put a little “bag” of things together for a little while.
+Tuples are nice for those times when you want to quickly (and temporarily) group some things together.
+If you notice that you are using the same tuples multiple times, it could be useful to declare a dedicated case class, such as:
+```scala
+case class StockInfo(symbol: String, price: BigDecimal, volume: Long)
+```
@@ -516,13 +553,3 @@ If you like what you’ve seen so far, we hope you’ll like the rest of the boo
## A bit of background
Scala was created by [Martin Odersky](https://en.wikipedia.org/wiki/Martin_Odersky), who studied under [Niklaus Wirth](https://en.wikipedia.org/wiki/Niklaus_Wirth), who created Pascal and several other languages. Mr. Odersky is one of the co-designers of Generic Java, and is also known as the “father” of the `javac` compiler.
-
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/pure-functions.md b/_overviews/scala-book/pure-functions.md
index e753d67ce4..35597bd01a 100644
--- a/_overviews/scala-book/pure-functions.md
+++ b/_overviews/scala-book/pure-functions.md
@@ -5,11 +5,11 @@ title: Pure Functions
description: This lesson provides an introduction to writing pure functions in Scala.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 45
outof: 54
previous-page: functional-programming
next-page: passing-functions-around
+new-version: /scala3/book/fp-pure-functions.html
---
@@ -49,7 +49,7 @@ Conversely, the following functions are *impure* because they violate the defini
The `foreach` method on collections classes is impure because it’s only used for its side effects, such as printing to STDOUT.
->A great hint that `foreach` is impure is that it’s method signature declares that it returns the type `Unit`. Because it returns nothing, logically the only reason you ever call it is to achieve some side effect. Similarly, *any* method that returns `Unit` is going to be an impure function.
+>A great hint that `foreach` is impure is that its method signature declares that it returns the type `Unit`. Because it returns nothing, logically the only reason you ever call it is to achieve some side effect. Similarly, *any* method that returns `Unit` is going to be an impure function.
Date and time related methods like `getDayOfWeek`, `getHour`, and `getMinute` are all impure because their output depends on something other than their input parameters. Their results rely on some form of hidden I/O, *hidden input* in these examples.
@@ -100,19 +100,3 @@ The first key point of this lesson is the definition of a pure function:
>A *pure function* is a function that depends only on its declared inputs and its internal algorithm to produce its output. It does not read any other values from “the outside world” — the world outside of the function’s scope — and it does not modify any values in the outside world.
A second key point is that real-world applications consist of a combination of pure and impure functions. A common recommendation is to write the core of your application using pure functions, and then to use impure functions to communicate with the outside world.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/sbt-scalatest-bdd.md b/_overviews/scala-book/sbt-scalatest-bdd.md
index ee20a8490e..29ba5e1eb6 100644
--- a/_overviews/scala-book/sbt-scalatest-bdd.md
+++ b/_overviews/scala-book/sbt-scalatest-bdd.md
@@ -5,11 +5,11 @@ title: Writing BDD Style Tests with ScalaTest and sbt
description: This lesson shows how to write ScalaTest unit tests with sbt in a behavior-driven development (TDD) style.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 43
outof: 54
previous-page: sbt-scalatest-tdd
next-page: functional-programming
+new-version: /scala3/book/tools-sbt.html#using-sbt-with-scalatest
---
@@ -45,9 +45,9 @@ Next, create a file named *MathUtilsTests.scala* in the *src/test/scala/simplete
```scala
package simpletest
-import org.scalatest.FunSpec
+import org.scalatest.funspec.AnyFunSpec
-class MathUtilsSpec extends FunSpec {
+class MathUtilsSpec extends AnyFunSpec {
describe("MathUtils::double") {
@@ -70,7 +70,7 @@ class MathUtilsSpec extends FunSpec {
As you can see, this is a very different-looking style than the TDD tests in the previous lesson. If you’ve never used a BDD style of testing before, a main idea is that the tests should be relatively easy to read for one of the “domain experts” who work with the programmers to create the application. A few notes about this code:
-- It uses the `FunSpec` class where the TDD tests used `FunSuite`
+- It uses the `AnyFunSpec` class where the TDD tests used `AnyFunSuite`
- A set of tests begins with `describe`
- Each test begins with `it`. The idea is that the test should read like, “It should do XYZ...,” where “it” is the `double` function
- This example also shows how to mark a test as “pending”
@@ -96,7 +96,7 @@ With those files in place you can again run `sbt test`. The important part of th
[info] Suites: completed 2, aborted 0
[info] Tests: succeeded 4, failed 0, canceled 0, ignored 0, pending 1
[info] All tests passed.
-[success] Total time: 4 s, completed Jan 6, 2018 4:58:23 PM
+[success] Total time: 4 s
````
A few notes about that output:
@@ -113,13 +113,5 @@ If you want to have a little fun with this, change one or more of the tests so t
For more information about sbt and ScalaTest, see the following resources:
-- [The main sbt documentation](http://www.scala-sbt.org/documentation.html)
-- [The ScalaTest documentation](http://www.scalatest.org/user_guide)
-
-
-
-
-
-
-
-
+- [The main sbt documentation](https://www.scala-sbt.org/1.x/docs/)
+- [The ScalaTest documentation](https://www.scalatest.org/user_guide)
diff --git a/_overviews/scala-book/sbt-scalatest-intro.md b/_overviews/scala-book/sbt-scalatest-intro.md
index bf40ba8c6c..2c80d06799 100644
--- a/_overviews/scala-book/sbt-scalatest-intro.md
+++ b/_overviews/scala-book/sbt-scalatest-intro.md
@@ -5,11 +5,11 @@ title: sbt and ScalaTest
description: In this lesson we'll start to introduce sbt and ScalaTest, two tools commonly used on Scala projects.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 40
outof: 54
previous-page: oop-pizza-example
next-page: scala-build-tool-sbt
+new-version: /scala3/book/tools-sbt.html
---
@@ -19,5 +19,3 @@ In the next few lessons you’ll see a couple of tools that are commonly used in
- [ScalaTest](http://www.scalatest.org), a code testing framework
We’ll start by showing how to use sbt, and then you’ll see how to use ScalaTest and sbt together to build and test your Scala projects.
-
-
diff --git a/_overviews/scala-book/sbt-scalatest-tdd.md b/_overviews/scala-book/sbt-scalatest-tdd.md
index 7214566a09..dbdbeeb53c 100644
--- a/_overviews/scala-book/sbt-scalatest-tdd.md
+++ b/_overviews/scala-book/sbt-scalatest-tdd.md
@@ -5,11 +5,11 @@ title: Using ScalaTest with sbt
description: This lesson shows how to write ScalaTest unit tests with sbt in a test-driven development (TDD) style.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 42
outof: 54
previous-page: scala-build-tool-sbt
next-page: sbt-scalatest-bdd
+new-version: /scala3/book/tools-sbt.html#using-sbt-with-scalatest
---
@@ -39,7 +39,7 @@ version := "1.0"
scalaVersion := "{{site.scala-version}}"
libraryDependencies +=
- "org.scalatest" %% "scalatest" % "3.0.8" % Test
+ "org.scalatest" %% "scalatest" % "3.2.19" % Test
```
@@ -47,7 +47,7 @@ The first three lines of this file are essentially the same as the first example
```scala
libraryDependencies +=
- "org.scalatest" %% "scalatest" % "3.0.8" % Test
+ "org.scalatest" %% "scalatest" % "3.2.19" % Test
```
>The ScalaTest documentation has always been good, and you can always find the up to date information on what those lines should look like on the [Installing ScalaTest](http://www.scalatest.org/install) page.
@@ -85,8 +85,8 @@ There isn’t much that can go wrong with that source code, but it provides a si
[warn] consider launching sbt without any commands, or explicitly passing 'shell'
...
...
-[info] Compiling 1 Scala source to /Users/al/Projects/Scala/HelloScalaTest/target/scala-2.12/classes...
-[info] Running simpletest.Hello
+[info] compiling 1 Scala source to /Users/al/Projects/Scala/HelloScalaTest/target/scala-2.13/classes...
+[info] running simpletest.Hello
Hello Alvin Alexander
[success] Total time: 4 s
````
@@ -108,9 +108,9 @@ Next, create a file named *HelloTests.scala* in that directory with the followin
```scala
package simpletest
-import org.scalatest.FunSuite
+import org.scalatest.funsuite.AnyFunSuite
-class HelloTests extends FunSuite {
+class HelloTests extends AnyFunSuite {
// test 1
test("the name is set correctly in constructor") {
@@ -130,7 +130,7 @@ class HelloTests extends FunSuite {
This file demonstrates the ScalaTest `FunSuite` approach. A few important points:
-- Your class should extend `FunSuite`
+- Your class should extend `AnyFunSuite`
- You create tests as shown, by giving each `test` a unique name
- At the end of each test you should call `assert` to test that a condition has been satisfied
@@ -140,7 +140,7 @@ Now you can run these tests with the `sbt test` command. Skipping the first few
````
> sbt test
-[info] Set current project to HelloScalaTest (in build file:/Users/al/Projects/Scala/HelloScalaTest/)
+[info] set current project to HelloScalaTest (in build file:/Users/al/Projects/Scala/HelloScalaTest/)
[info] HelloTests:
[info] - the name is set correctly in constructor
[info] - a Person's name can be changed
@@ -159,11 +159,3 @@ Now you can run these tests with the `sbt test` command. Skipping the first few
This example demonstrates a *Test-Driven Development* (TDD) style of testing with ScalaTest. In the next lesson you’ll see how to write *Behavior-Driven Development* (BDD) tests with ScalaTest and sbt.
>Keep the project you just created. You’ll use it again in the next lesson.
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/scala-build-tool-sbt.md b/_overviews/scala-book/scala-build-tool-sbt.md
index b220ed1297..c329d06aa4 100644
--- a/_overviews/scala-book/scala-build-tool-sbt.md
+++ b/_overviews/scala-book/scala-build-tool-sbt.md
@@ -5,11 +5,11 @@ title: The most used scala build tool (sbt)
description: This page provides an introduction to the Scala Build Tool, sbt, including a simple 'Hello, world' project.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 41
outof: 54
previous-page: sbt-scalatest-intro
next-page: sbt-scalatest-tdd
+new-version: /scala3/book/tools-sbt.html#building-scala-projects-with-sbt
---
@@ -82,7 +82,7 @@ If you see that, you’re in great shape for the next step.
At this point you only need two more things to run a “Hello, world” project:
- A *build.sbt* file
-- A *Hello.scala* file
+- A *HelloWorld.scala* file
For a little project like this, the *build.sbt* file only needs to contain a few lines, like this:
@@ -156,19 +156,10 @@ If you type `help` at the sbt command prompt you’ll see a bunch of other comma
## See also
-Here’s a list of other build tools you can use to build Scala projects are:
+Here’s a list of other build tools you can use to build Scala projects:
- [Ant](http://ant.apache.org/)
- [Gradle](https://gradle.org/)
- [Maven](https://maven.apache.org/)
-- [Fury](https://fury.build)
-- [Mill](http://www.lihaoyi.com/mill)
-
-
-
-
-
-
-
-
-
+- [Fury](https://github.com/propensive/fury)
+- [Mill](https://com-lihaoyi.github.io/mill/)
diff --git a/_overviews/scala-book/scala-features.md b/_overviews/scala-book/scala-features.md
index eee55bd089..5973f1ea1a 100644
--- a/_overviews/scala-book/scala-features.md
+++ b/_overviews/scala-book/scala-features.md
@@ -5,19 +5,19 @@ title: Scala Features
description: TODO
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 4
outof: 54
previous-page: preliminaries
next-page: hello-world-1
+new-version: /scala3/book/scala-features.html
---
-The name *Scala* comes from the word *scalable*, and true to that name, it’s used to power the busiest websites in the world, including Twitter, Netflix, Tumblr, LinkedIn, Foursquare, and many more.
+The name *Scala* comes from the word *scalable*, and true to that name, it’s used to power the busiest websites in the world, including X, Netflix, Tumblr, LinkedIn, Foursquare, and many more.
Here are a few more nuggets about Scala:
-- It’s a modern programming language created by [Martin Odersky](https://twitter.com/odersky?lang=en) (the father of `javac`), and influenced by Java, Ruby, Smalltalk, ML, Haskell, Erlang, and others.
+- It’s a modern programming language created by [Martin Odersky](https://x.com/odersky?lang=en) (the father of `javac`), and influenced by Java, Ruby, Smalltalk, ML, Haskell, Erlang, and others.
- It’s a high-level language.
- It’s statically typed.
- It has a sophisticated type inference system.
@@ -28,6 +28,3 @@ Here are a few more nuggets about Scala:
- Scala also works extremely well with the thousands of Java libraries that have been developed over the years.
- A great thing about Scala is that you can be productive with it on Day 1, but it’s also a deep language, so as you go along you’ll keep learning, and finding newer, better ways to write code. Some people say that Scala will change the way you think about programming (and that’s a good thing).
- A great Scala benefit is that it lets you write concise, readable code. The time a programmer spends reading code compared to the time spent writing code is said to be at least a 10:1 ratio, so writing code that’s *concise and readable* is a big deal. Because Scala has these attributes, programmers say that it’s *expressive*.
-
-
-
diff --git a/_overviews/scala-book/scala-repl.md b/_overviews/scala-book/scala-repl.md
index c1ced1f219..d3227b15b1 100644
--- a/_overviews/scala-book/scala-repl.md
+++ b/_overviews/scala-book/scala-repl.md
@@ -5,11 +5,11 @@ title: The Scala REPL
description: This page shares an introduction to the Scala REPL.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 7
outof: 54
previous-page: hello-world-2
next-page: two-types-variables
+new-version: /scala3/book/taste-repl.html
---
@@ -72,14 +72,5 @@ In addition to the REPL there are a couple of other, similar tools you can use:
- [Scastie](https://scastie.scala-lang.org) is “an interactive playground for Scala” with several nice features, including being able to control build settings and share code snippets
- IntelliJ IDEA has a Worksheet plugin that lets you do the same things inside your IDE
-- The Scala IDE for Eclipse also has a Worksheet plugin
-- [scalafiddle.io](https://scalafiddle.io) lets you run similar experiments in a web browser
For more information on the Scala REPL, see the [Scala REPL overview]({{site.baseurl}}/overviews/repl/overview.html)
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/set-class.md b/_overviews/scala-book/set-class.md
index 55fefb31d0..6123650f6f 100644
--- a/_overviews/scala-book/set-class.md
+++ b/_overviews/scala-book/set-class.md
@@ -5,11 +5,11 @@ title: The Set Class
description: This page provides examples of the Scala 'Set' class, including how to add and remove elements from a Set, and iterate over Set elements.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 33
outof: 54
previous-page: map-class
next-page: anonymous-functions
+new-version: /scala3/book/collections-classes.html#working-with-sets
---
@@ -122,11 +122,3 @@ res3: Boolean = false
## More Sets
Scala has several more `Set` classes, including `SortedSet`, `LinkedHashSet`, and more. Please see the [Set class documentation]({{site.baseurl}}/overviews/collections-2.13/sets.html) for more details on those classes.
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/traits-abstract-mixins.md b/_overviews/scala-book/traits-abstract-mixins.md
index eeecb67aee..1bcbb87936 100644
--- a/_overviews/scala-book/traits-abstract-mixins.md
+++ b/_overviews/scala-book/traits-abstract-mixins.md
@@ -5,11 +5,11 @@ title: Using Scala Traits Like Abstract Classes
description: This page shows how to use Scala traits just like abstract classes in Java, with examples of concrete and abstract methods.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 26
outof: 54
previous-page: traits-interfaces
next-page: abstract-classes
+new-version: /scala3/book/domain-modeling-tools.html#traits
---
@@ -195,12 +195,3 @@ I'm running
```
This example works because all of the methods in the `TailWagger` and `Runner` traits are defined (they’re not abstract).
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/traits-interfaces.md b/_overviews/scala-book/traits-interfaces.md
index a10ed18a61..1aab8ee4e8 100644
--- a/_overviews/scala-book/traits-interfaces.md
+++ b/_overviews/scala-book/traits-interfaces.md
@@ -5,11 +5,11 @@ title: Using Scala Traits as Interfaces
description: This page shows how to use Scala traits just like Java interfaces, including several examples.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 25
outof: 54
previous-page: traits-intro
next-page: traits-abstract-mixins
+new-version: /scala3/book/domain-modeling-tools.html#traits
---
## Using Scala Traits as Interfaces
@@ -146,10 +146,3 @@ Key points of this code:
- Use `with` to extend subsequent traits
From what you’ve seen so far, Scala traits work just like Java interfaces. But there’s more ...
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/traits-intro.md b/_overviews/scala-book/traits-intro.md
index a6d1db0f26..66c7cf99d6 100644
--- a/_overviews/scala-book/traits-intro.md
+++ b/_overviews/scala-book/traits-intro.md
@@ -5,19 +5,14 @@ title: Scala Traits and Abstract Classes
description: An introduction to Scala traits and abstract classes.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 24
outof: 54
previous-page: enumerations-pizza-class
next-page: traits-interfaces
+new-version: /scala3/book/domain-modeling-tools.html#traits
---
Scala traits are a great feature of the language. As you’ll see in the following lessons, you can use them just like a Java interface, and you can also use them like abstract classes that have real methods. Scala classes can also extend and “mix in” multiple traits.
Scala also has the concept of an abstract class, and we’ll show when you should use an abstract class instead of a trait.
-
-
-
-
-
diff --git a/_overviews/scala-book/try-catch-finally.md b/_overviews/scala-book/try-catch-finally.md
index 5dee7890a4..a9e855cce1 100644
--- a/_overviews/scala-book/try-catch-finally.md
+++ b/_overviews/scala-book/try-catch-finally.md
@@ -5,11 +5,11 @@ title: try/catch/finally Expressions
description: This page shows how to use Scala's try/catch/finally construct, including several complete examples.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 18
outof: 54
previous-page: match-expressions
next-page: classes
+new-version: /scala3/book/control-structures.html#trycatchfinally
---
@@ -58,9 +58,3 @@ catch {
## More later
We’ll cover more details about Scala’s try/catch/finally syntax in later lessons, such as in the “Functional Error Handling” lessons, but these examples demonstrate how the syntax works. A great thing about the syntax is that it’s consistent with the `match` expression syntax. This makes your code consistent and easier to read, and you don’t have to remember a special/different syntax.
-
-
-
-
-
-
diff --git a/_overviews/scala-book/tuples.md b/_overviews/scala-book/tuples.md
index c2eb8e4225..dab29195c8 100644
--- a/_overviews/scala-book/tuples.md
+++ b/_overviews/scala-book/tuples.md
@@ -5,11 +5,11 @@ title: Tuples
description: This page is an introduction to the Scala 'tuple' data type, showing examples of how to use tuples in your Scala code.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 38
outof: 54
previous-page: misc
next-page: oop-pizza-example
+new-version: /scala3/book/taste-collections.html#tuples
---
@@ -115,9 +115,3 @@ For cases like this where it feels like overkill to create a class for the metho
## Tuples aren’t collections
Technically, Scala 2.x tuples aren’t collections classes, they’re just a convenient little container. Because they aren’t a collection, they don’t have methods like `map`, `filter`, etc.
-
-
-
-
-
-
diff --git a/_overviews/scala-book/two-notes-about-strings.md b/_overviews/scala-book/two-notes-about-strings.md
index fdcbd7a29a..31a097f758 100644
--- a/_overviews/scala-book/two-notes-about-strings.md
+++ b/_overviews/scala-book/two-notes-about-strings.md
@@ -5,11 +5,11 @@ title: Two Notes About Strings
description: This page shares two important notes about strings in Scala.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 11
outof: 54
previous-page: built-in-types
next-page: command-line-io
+new-version: /scala3/book/first-look-at-types.html#strings
---
@@ -110,6 +110,3 @@ our fathers ...
```
Because this is what you generally want, this is a common way to create multiline strings.
-
-
-
diff --git a/_overviews/scala-book/two-types-variables.md b/_overviews/scala-book/two-types-variables.md
index 678c89dc3d..3ce00a0e54 100644
--- a/_overviews/scala-book/two-types-variables.md
+++ b/_overviews/scala-book/two-types-variables.md
@@ -5,11 +5,11 @@ title: Two Types of Variables
description: Scala has two types of variables, val and var.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 8
outof: 54
previous-page: scala-repl
next-page: type-is-optional
+new-version: /scala3/book/taste-vars-data-types.html
---
@@ -94,8 +94,7 @@ object Hello3 extends App {
As before:
- Save that code in a file named *Hello3.scala*
-- Compile it with `scalac Hello3.scala`
-- Run it with `scala Hello3`
+- Compile and run it with `scala run Hello3.scala`
@@ -112,12 +111,3 @@ age: Int = 19
```
`val` fields can’t be redefined like that in the real world, but they can be redefined in the REPL playground.
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/type-is-optional.md b/_overviews/scala-book/type-is-optional.md
index 3b21654433..6a49d6b751 100644
--- a/_overviews/scala-book/type-is-optional.md
+++ b/_overviews/scala-book/type-is-optional.md
@@ -5,11 +5,11 @@ title: The Type is Optional
description: A note about explicit and implicit data type declarations in Scala.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 9
outof: 54
previous-page: two-types-variables
next-page: built-in-types
+new-version: /scala3/book/taste-vars-data-types.html#declaring-variable-types
---
@@ -56,13 +56,3 @@ val p: Person = new Person("Candy") // unnecessarily verbose
## Use the explicit form when you need to be clear
One place where you’ll want to show the data type is when you want to be clear about what you’re creating. That is, if you don’t explicitly declare the data type, the compiler may make a wrong assumption about what you want to create. Some examples of this are when you want to create numbers with specific data types. We show this in the next lesson.
-
-
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/vector-class.md b/_overviews/scala-book/vector-class.md
index 15981e7904..7da81e3125 100644
--- a/_overviews/scala-book/vector-class.md
+++ b/_overviews/scala-book/vector-class.md
@@ -5,11 +5,11 @@ title: The Vector Class
description: This page provides examples of the Scala 'Vector' class, including how to add and remove elements from a Vector.
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 31
outof: 54
previous-page: list-class
next-page: map-class
+new-version: /scala3/book/collections-classes.html#vector
---
[The Vector class](https://www.scala-lang.org/api/current/scala/collection/immutable/Vector.html) is an indexed, immutable sequence. The “indexed” part of the description means that you can access `Vector` elements very rapidly by their index value, such as accessing `listOfPeople(999999)`.
@@ -96,11 +96,3 @@ Joel
Chris
Ed
```
-
-
-
-
-
-
-
-
diff --git a/_overviews/scala-book/where-next.md b/_overviews/scala-book/where-next.md
index 4b045d7182..9210e690e7 100644
--- a/_overviews/scala-book/where-next.md
+++ b/_overviews/scala-book/where-next.md
@@ -5,14 +5,12 @@ title: Where To Go Next
description: Where to go next after reading the Scala Book
partof: scala_book
overview-name: Scala Book
-discourse: true
num: 54
outof: 54
previous-page: futures
+new-version: /scala3/book/where-next.html
---
We hope you enjoyed this introduction to the Scala programming language, and we also hope we were able to share some of the beauty of the language.
As you continue working with Scala, you can find many more details at the [Guides and Overviews section]({{site.baseurl}}/overviews/index.html) of our website.
-
-
diff --git a/_overviews/scala3-book/ca-context-bounds.md b/_overviews/scala3-book/ca-context-bounds.md
new file mode 100644
index 0000000000..d4346ed94c
--- /dev/null
+++ b/_overviews/scala3-book/ca-context-bounds.md
@@ -0,0 +1,123 @@
+---
+title: Context Bounds
+type: section
+description: This page demonstrates Context Bounds in Scala.
+languages: [ru, zh-cn]
+num: 63
+previous-page: ca-context-parameters
+next-page: ca-given-imports
+---
+
+In many situations the name of a [context parameter]({% link _overviews/scala3-book/ca-context-parameters.md %}#context-parameters) does not have to be mentioned explicitly, since it is only used by the compiler in synthesized arguments for other context parameters.
+In that case you don’t have to define a parameter name, and can just provide the parameter type.
+
+
+## Background
+
+For example, consider a method `maxElement` that returns the maximum value in a collection:
+
+{% tabs context-bounds-max-named-param class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+def maxElement[A](as: List[A])(implicit ord: Ord[A]): A =
+ as.reduceLeft(max(_, _)(ord))
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+def maxElement[A](as: List[A])(using ord: Ord[A]): A =
+ as.reduceLeft(max(_, _)(using ord))
+```
+{% endtab %}
+
+{% endtabs %}
+
+The method `maxElement` takes a _context parameter_ of type `Ord[A]` only to pass it on as an argument to the method
+`max`.
+
+For the sake of completeness, here are the definitions of `max` and `Ord` (note that in practice we would use the
+existing method `max` on `List`, but we made up this example for illustration purpose):
+
+{% tabs context-bounds-max-ord class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+/** Defines how to compare values of type `A` */
+trait Ord[A] {
+ def greaterThan(a1: A, a2: A): Boolean
+}
+
+/** Returns the maximum of two values */
+def max[A](a1: A, a2: A)(implicit ord: Ord[A]): A =
+ if (ord.greaterThan(a1, a2)) a1 else a2
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+/** Defines how to compare values of type `A` */
+trait Ord[A]:
+ def greaterThan(a1: A, a2: A): Boolean
+
+/** Returns the maximum of two values */
+def max[A](a1: A, a2: A)(using ord: Ord[A]): A =
+ if ord.greaterThan(a1, a2) then a1 else a2
+```
+{% endtab %}
+
+{% endtabs %}
+
+Note that the method `max` takes a context parameter of type `Ord[A]`, like the method `maxElement`.
+
+## Omitting context arguments
+
+Since `ord` is a context parameter in the method `max`, the compiler can supply it for us in the implementation of `maxElement`,
+when we call the method `max`:
+
+{% tabs context-bounds-context class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+def maxElement[A](as: List[A])(implicit ord: Ord[A]): A =
+ as.reduceLeft(max(_, _))
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+def maxElement[A](as: List[A])(using Ord[A]): A =
+ as.reduceLeft(max(_, _))
+```
+
+Note that, because we don’t need to explicitly pass it to the method `max`, we can leave out its name in the definition
+of the method `maxElement`. This is an _anonymous context parameter_.
+{% endtab %}
+
+{% endtabs %}
+
+## Context bounds
+
+Given that background, a _context bound_ is a shorthand syntax for expressing the pattern of, “a context parameter applied to a type parameter.”
+
+Using a context bound, the `maxElement` method can be written like this:
+
+{% tabs context-bounds-max-rewritten %}
+
+{% tab 'Scala 2 and 3' %}
+
+```scala
+def maxElement[A: Ord](as: List[A]): A =
+ as.reduceLeft(max(_, _))
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+
+A bound like `: Ord` on a type parameter `A` of a method or class indicates a context parameter with type `Ord[A]`.
+Under the hood, the compiler transforms this syntax into the one shown in the Background section.
+
+For more information about context bounds, see the [“What are context bounds?”]({% link _overviews/FAQ/index.md %}#what-are-context-bounds) section of the Scala FAQ.
diff --git a/_overviews/scala3-book/ca-context-parameters.md b/_overviews/scala3-book/ca-context-parameters.md
new file mode 100644
index 0000000000..3da62d4b3b
--- /dev/null
+++ b/_overviews/scala3-book/ca-context-parameters.md
@@ -0,0 +1,157 @@
+---
+title: Context Parameters
+type: section
+description: This page demonstrates how to declare context parameters, and how the compiler infers them at call-site.
+languages: [ru, zh-cn]
+num: 62
+previous-page: ca-extension-methods
+next-page: ca-context-bounds
+redirect_from: /scala3/book/ca-given-using-clauses.html
+---
+
+Scala offers two important features for contextual abstraction:
+
+- **Context Parameters** allow you to specify parameters that, at the call-site, can be omitted by the programmer and should be automatically provided by the context.
+- **Given Instances** (in Scala 3) or **Implicit Definitions** (in Scala 2) are terms that can be used by the Scala compiler to fill in the missing arguments.
+
+## Context Parameters
+
+When designing a system, often context information like _configuration_ or settings need to be provided to the different components of your system.
+One common way to achieve this is by passing the configuration as an additional argument (or arguments) to your methods.
+
+In the following example, we define a case class `Config` to model some website configuration and pass it around in the different methods.
+
+{% tabs example %}
+{% tab 'Scala 2 and 3' %}
+```scala
+case class Config(port: Int, baseUrl: String)
+
+def renderWebsite(path: String, config: Config): String =
+ "" + renderWidget(List("cart"), config) + ""
+
+def renderWidget(items: List[String], config: Config): String = ???
+
+val config = Config(8080, "docs.scala-lang.org")
+renderWebsite("/home", config)
+```
+{% endtab %}
+{% endtabs %}
+
+Let us assume that the configuration does not change throughout most of our code base.
+Passing `config` to each and every method call (like `renderWidget`) becomes very tedious and makes our program more difficult to read, since we need to ignore the `config` argument.
+
+### Marking parameters as contextual
+
+We can mark some parameters of our methods as _contextual_.
+
+{% tabs 'contextual-parameters' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+def renderWebsite(path: String)(implicit config: Config): String =
+ "" + renderWidget(List("cart")) + ""
+ // ^
+ // no argument config required anymore
+
+def renderWidget(items: List[String])(implicit config: Config): String = ???
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+def renderWebsite(path: String)(using config: Config): String =
+ "" + renderWidget(List("cart")) + ""
+ // ^
+ // no argument config required anymore
+
+def renderWidget(items: List[String])(using config: Config): String = ???
+```
+{% endtab %}
+{% endtabs %}
+
+By starting a parameter section with the keyword `using` in Scala 3 or `implicit` in Scala 2, we tell the compiler that at the call-site it should automatically find an argument with the correct type.
+The Scala compiler thus performs **term inference**.
+
+In our call to `renderWidget(List("cart"))` the Scala compiler will see that there is a term of type `Config` in scope (the `config`) and automatically provide it to `renderWidget`.
+So the program is equivalent to the one above.
+
+In fact, since we do not need to refer to `config` in our implementation of `renderWebsite` anymore, we can even omit its name in the signature in Scala 3:
+
+{% tabs 'anonymous' %}
+{% tab 'Scala 3 Only' %}
+```scala
+// no need to come up with a parameter name
+// vvvvvvvvvvvvv
+def renderWebsite(path: String)(using Config): String =
+ "" + renderWidget(List("cart")) + ""
+```
+{% endtab %}
+{% endtabs %}
+
+In Scala 2, the name of implicit parameters is still mandatory.
+
+### Explicitly providing contextual arguments
+
+We have seen how to _abstract_ over contextual parameters and that the Scala compiler can provide arguments automatically for us.
+But how can we specify which configuration to use for our call to `renderWebsite`?
+
+{% tabs 'explicit' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+We explicitly supply the argument value as if it was a regular argument:
+```scala
+renderWebsite("/home")(config)
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+Like we specified our parameter section with `using`, we can also explicitly provide contextual arguments with `using`:
+```scala
+renderWebsite("/home")(using config)
+```
+{% endtab %}
+{% endtabs %}
+
+Explicitly providing contextual parameters can be useful if we have multiple different values in scope that would make sense, and we want to make sure that the correct one is passed to the function.
+
+For all other cases, as we will see in the next section, there is also another way to bring contextual values into scope.
+
+## Given Instances (Implicit Definitions in Scala 2)
+
+We have seen that we can explicitly pass arguments as contextual parameters.
+However, if there is _a single canonical value_ for a particular type, there is another preferred way to make it available to the Scala compiler: by marking it as `given` in Scala 3 or `implicit` in Scala 2.
+
+{% tabs 'instances' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+implicit val config: Config = Config(8080, "docs.scala-lang.org")
+// ^^^^^^
+// this is the value the Scala compiler will infer
+// as argument to contextual parameters of type Config
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+val config = Config(8080, "docs.scala-lang.org")
+
+// this is the type that we want to provide the
+// canonical value for
+// vvvvvv
+given Config = config
+// ^^^^^^
+// this is the value the Scala compiler will infer
+// as argument to contextual parameters of type Config
+```
+{% endtab %}
+{% endtabs %}
+
+In the above example we specify that whenever a contextual parameter of type `Config` is omitted in the current scope, the compiler should infer `config` as an argument.
+
+Having defined a canonical value for the type `Config`, we can call `renderWebsite` as follows:
+
+```scala
+renderWebsite("/home")
+// ^
+// again no argument
+```
+
+A detailed guide to where Scala looks for canonical values can be found in [the FAQ]({% link _overviews/FAQ/index.md %}#where-does-scala-look-for-implicits).
+
+[reference]: {{ site.scala3ref }}/overview.html
+[blog-post]: /2020/11/06/explicit-term-inference-in-scala-3.html
diff --git a/_overviews/scala3-book/ca-contextual-abstractions-intro.md b/_overviews/scala3-book/ca-contextual-abstractions-intro.md
new file mode 100644
index 0000000000..8f7f5f79af
--- /dev/null
+++ b/_overviews/scala3-book/ca-contextual-abstractions-intro.md
@@ -0,0 +1,87 @@
+---
+title: Contextual Abstractions
+type: chapter
+description: This chapter provides an introduction to the Scala 3 concept of Contextual Abstractions.
+languages: [ru, zh-cn]
+num: 60
+previous-page: types-others
+next-page: ca-extension-methods
+---
+
+
+## Background
+
+Contextual abstractions are a way to abstract over context.
+They represent a unified paradigm with a great variety of use cases, among them:
+
+- Implementing type classes
+- Establishing context
+- Dependency injection
+- Expressing capabilities
+- Computing new types, and proving relationships between them
+
+Other languages have been influenced by Scala in this regard. E.g., Rust’s traits or Swift’s protocol extensions.
+Design proposals are also on the table for Kotlin as compile time dependency resolution, for C# as Shapes and Extensions or for F# as Traits.
+Contextual abstractions are also a common feature of theorem provers such as Coq or Agda.
+
+Even though these designs use different terminology, they’re all variants of the core idea of **term inference**: given a type, the compiler synthesizes a “canonical” term that has that type.
+
+## Scala 3 Redesign
+
+In Scala 2, contextual abstractions are supported by marking definitions (methods and values) or parameters as `implicit` (see [Context Parameters]({% link _overviews/scala3-book/ca-context-parameters.md %})).
+
+Scala 3 includes a redesign of contextual abstractions.
+While these concepts were gradually “discovered” in Scala 2, they’re now well known and understood, and the redesign takes advantage of that knowledge.
+
+The design of Scala 3 focuses on **intent** rather than **mechanism**.
+Instead of offering one very powerful feature of implicits, Scala 3 offers several use-case oriented features:
+
+- **Retroactively extending classes**.
+ In Scala 2, extension methods are encoded by using [implicit conversions][implicit-conversions] or [implicit classes]({% link _overviews/core/implicit-classes.md %}).
+ In contrast, in Scala 3 [extension methods][extension-methods] are now directly built into the language, leading to better error messages and improved type inference.
+
+- **Abstracting over contextual information**.
+ [Using clauses][givens] allow programmers to abstract over information that is available in the calling context and should be passed implicitly.
+ As an improvement over Scala 2 implicits, using clauses can be specified by type, freeing function signatures from term variable names that are never explicitly referred to.
+
+- **Providing Type-class instances**.
+ [Given instances][givens] allow programmers to define the _canonical value_ of a certain type.
+ This makes programming with [type-classes][type-classes] more straightforward without leaking implementation details.
+
+- **Viewing one type as another**.
+ Implicit conversions have been [redesigned][implicit-conversions] from the ground up as instances of a type-class `Conversion`.
+
+- **Higher-order contextual abstractions**.
+ The _all-new_ feature of [context functions][contextual-functions] makes contextual abstractions a first-class citizen.
+ They are an important tool for library authors and allow to express concise domain specific languages.
+
+- **Actionable feedback from the compiler**.
+ In case an implicit parameter can not be resolved by the compiler, it now provides you [import suggestions](https://www.scala-lang.org/blog/2020/05/05/scala-3-import-suggestions.html) that may fix the problem.
+
+
+## Benefits
+
+These changes in Scala 3 achieve a better separation of term inference from the rest of the language:
+
+- There’s a single way to define givens
+- There’s a single way to introduce implicit parameters and arguments
+- There’s a separate way to [import givens][given-imports] that does not allow them to hide in a sea of normal imports
+- There’s a single way to define an [implicit conversion][implicit-conversions], which is clearly marked as such, and does not require special syntax
+
+Benefits of these changes include:
+
+- The new design thus avoids feature interactions and makes the language more consistent
+- It makes implicits easier to learn and harder to abuse
+- It greatly improves the clarity of the 95% of Scala programs that use implicits
+- It has the potential to enable term inference in a principled way that is also accessible and friendly
+
+This chapter introduces many of these new features in the following sections.
+
+[givens]: {% link _overviews/scala3-book/ca-context-parameters.md %}
+[given-imports]: {% link _overviews/scala3-book/ca-given-imports.md %}
+[implicit-conversions]: {% link _overviews/scala3-book/ca-implicit-conversions.md %}
+[extension-methods]: {% link _overviews/scala3-book/ca-extension-methods.md %}
+[context-bounds]: {% link _overviews/scala3-book/ca-context-bounds.md %}
+[type-classes]: {% link _overviews/scala3-book/ca-type-classes.md %}
+[equality]: {% link _overviews/scala3-book/ca-multiversal-equality.md %}
+[contextual-functions]: {{ site.scala3ref }}/contextual/context-functions.html
diff --git a/_overviews/scala3-book/ca-extension-methods.md b/_overviews/scala3-book/ca-extension-methods.md
new file mode 100644
index 0000000000..49f07b45be
--- /dev/null
+++ b/_overviews/scala3-book/ca-extension-methods.md
@@ -0,0 +1,126 @@
+---
+title: Extension Methods
+type: section
+description: This page demonstrates how Extension Methods work in Scala 3.
+languages: [ru, zh-cn]
+num: 61
+previous-page: ca-contextual-abstractions-intro
+next-page: ca-context-parameters
+scala3: true
+versionSpecific: true
+---
+
+In Scala 2, a similar result could be achieved with [implicit classes]({% link _overviews/core/implicit-classes.md %}).
+
+---
+
+Extension methods let you add methods to a type after the type is defined, i.e., they let you add new methods to closed classes.
+For example, imagine that someone else has created a `Circle` class:
+
+{% tabs ext1 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+case class Circle(x: Double, y: Double, radius: Double)
+```
+{% endtab %}
+{% endtabs %}
+
+Now imagine that you need a `circumference` method, but you can’t modify their source code.
+Before the concept of term inference was introduced into programming languages, the only thing you could do was write a method in a separate class or object like this:
+
+{% tabs ext2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+object CircleHelpers {
+ def circumference(c: Circle): Double = c.radius * math.Pi * 2
+}
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+object CircleHelpers:
+ def circumference(c: Circle): Double = c.radius * math.Pi * 2
+```
+{% endtab %}
+{% endtabs %}
+
+Then you’d use that method like this:
+
+{% tabs ext3 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val aCircle = Circle(2, 3, 5)
+
+// without extension methods
+CircleHelpers.circumference(aCircle)
+```
+{% endtab %}
+{% endtabs %}
+
+But with extension methods you can create a `circumference` method to work on `Circle` instances:
+
+{% tabs ext4 %}
+{% tab 'Scala 3 Only' %}
+```scala
+extension (c: Circle)
+ def circumference: Double = c.radius * math.Pi * 2
+```
+{% endtab %}
+{% endtabs %}
+
+In this code:
+
+- `Circle` is the type that the extension method `circumference` will be added to
+- The `c: Circle` syntax lets you reference the variable `c` in your extension method(s)
+
+Then in your code you use `circumference` just as though it was originally defined in the `Circle` class:
+
+{% tabs ext5 %}
+{% tab 'Scala 3 Only' %}
+```scala
+aCircle.circumference
+```
+{% endtab %}
+{% endtabs %}
+
+### Import extension method
+
+Imagine, that `circumference` is defined in package `lib`, you can import it by
+
+{% tabs ext6 %}
+{% tab 'Scala 3 Only' %}
+```scala
+import lib.circumference
+
+aCircle.circumference
+```
+{% endtab %}
+{% endtabs %}
+
+The compiler also supports you if the import is missing by showing a detailed compilation error message such as the following:
+
+```text
+value circumference is not a member of Circle, but could be made available as an extension method.
+
+The following import might fix the problem:
+
+ import lib.circumference
+```
+
+## Discussion
+
+The `extension` keyword declares that you’re about to define one or more extension methods on the type that’s put in parentheses.
+To define multiple extension methods on a type, use this syntax:
+
+{% tabs ext7 %}
+{% tab 'Scala 3 Only' %}
+```scala
+extension (c: Circle)
+ def circumference: Double = c.radius * math.Pi * 2
+ def diameter: Double = c.radius * 2
+ def area: Double = math.Pi * c.radius * c.radius
+```
+{% endtab %}
+{% endtabs %}
+
+
diff --git a/_overviews/scala3-book/ca-given-imports.md b/_overviews/scala3-book/ca-given-imports.md
new file mode 100644
index 0000000000..bc7c0754f4
--- /dev/null
+++ b/_overviews/scala3-book/ca-given-imports.md
@@ -0,0 +1,51 @@
+---
+title: Given Imports
+type: section
+description: This page demonstrates how 'given' import statements work in Scala 3.
+languages: [ru, zh-cn]
+num: 64
+previous-page: ca-context-bounds
+next-page: ca-type-classes
+scala3: true
+versionSpecific: true
+---
+
+
+To make it more clear where givens in the current scope are coming from, a special form of the `import` statement is used to import `given` instances.
+The basic form is shown in this example:
+
+```scala
+object A:
+ class TC
+ given tc: TC = ???
+ def f(using TC) = ???
+
+object B:
+ import A.* // import all non-given members
+ import A.given // import the given instance
+```
+
+In this code the `import A.*` clause of object `B` imports all members of `A` *except* the `given` instance, `tc`.
+Conversely, the second import, `import A.given`, imports *only* that `given` instance.
+The two `import` clauses can also be merged into one:
+
+```scala
+object B:
+ import A.{given, *}
+```
+
+## Discussion
+
+The wildcard selector `*` brings all definitions other than givens or extensions into scope, whereas a `given` selector brings all *givens*---including those resulting from extensions---into scope.
+
+These rules have two main benefits:
+
+- It’s more clear where givens in the current scope are coming from.
+ In particular, it’s not possible to hide imported givens in a long list of other wildcard imports.
+- It enables importing all givens without importing anything else.
+ This is important because givens can be anonymous, so the usual use of named imports is not practical.
+
+More examples of the “import given” syntax are shown in the [Packaging and Imports chapter][imports].
+
+
+[imports]: {% link _overviews/scala3-book/packaging-imports.md %}
diff --git a/_overviews/scala3-book/ca-implicit-conversions.md b/_overviews/scala3-book/ca-implicit-conversions.md
new file mode 100644
index 0000000000..2c2884aa56
--- /dev/null
+++ b/_overviews/scala3-book/ca-implicit-conversions.md
@@ -0,0 +1,223 @@
+---
+title: Implicit Conversions
+type: section
+description: This page demonstrates how to implement Implicit Conversions in Scala.
+languages: [ru, zh-cn]
+num: 67
+previous-page: ca-multiversal-equality
+next-page: ca-summary
+---
+
+Implicit conversions are a powerful Scala feature that allows users to supply an argument
+of one type as if it were another type, to avoid boilerplate.
+
+> Note that in Scala 2, implicit conversions were also used to provide additional members
+> to closed classes (see [Implicit Classes]({% link _overviews/core/implicit-classes.md %})).
+> In Scala 3, we recommend to address this use-case by defining [extension methods] instead
+> of implicit conversions (although the standard library still relies on implicit conversions
+> for historical reasons).
+
+## Example
+
+Consider for instance a method `findUserById` that takes a parameter of type `Long`:
+
+{% tabs implicit-conversions-1 %}
+{% tab 'Scala 2 and 3' %}
+~~~ scala
+def findUserById(id: Long): Option[User]
+~~~
+{% endtab %}
+{% endtabs %}
+
+We omit the definition of the type `User` for the sake of brevity, it does not matter for
+our example.
+
+In Scala, it is possible to call the method `findUserById` with an argument of type `Int`
+instead of the expected type `Long`, because the argument will be implicitly converted
+into the type `Long`:
+
+{% tabs implicit-conversions-2 %}
+{% tab 'Scala 2 and 3' %}
+~~~ scala
+val id: Int = 42
+findUserById(id) // OK
+~~~
+{% endtab %}
+{% endtabs %}
+
+This code does not fail to compile with an error like “type mismatch: expected `Long`,
+found `Int`” because there is an implicit conversion that converts the argument `id`
+to a value of type `Long`.
+
+## Detailed Explanation
+
+This section describes how to define and use implicit conversions.
+
+### Defining an Implicit Conversion
+
+{% tabs implicit-conversions-3 class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+In Scala 2, an implicit conversion from type `S` to type `T` is defined by an
+[implicit class]({% link _overviews/core/implicit-classes.md %}) `T` that takes
+a single constructor parameter of type `S`, an
+[implicit value]({% link _overviews/scala3-book/ca-context-parameters.md %}) of
+function type `S => T`, or by an implicit method convertible to a value of that type.
+
+For example, the following code defines an implicit conversion from `Int` to `Long`:
+
+~~~ scala
+import scala.language.implicitConversions
+
+implicit def int2long(x: Int): Long = x.toLong
+~~~
+
+This is an implicit method convertible to a value of type `Int => Long`.
+
+See the section “Beware the Power of Implicit Conversions” below for an
+explanation of the clause `import scala.language.implicitConversions`
+at the beginning.
+{% endtab %}
+
+{% tab 'Scala 3' %}
+In Scala 3, an implicit conversion from type `S` to type `T` is defined by a
+[`given` instance]({% link _overviews/scala3-book/ca-context-parameters.md %})
+of type `scala.Conversion[S, T]`. For compatibility with Scala 2, it can also
+be defined by an implicit method (read more in the Scala 2 tab).
+
+For example, this code defines an implicit conversion from `Int` to `Long`:
+
+```scala
+given int2long: Conversion[Int, Long] with
+ def apply(x: Int): Long = x.toLong
+```
+
+Like other given definitions, implicit conversions can be anonymous:
+
+~~~ scala
+given Conversion[Int, Long] with
+ def apply(x: Int): Long = x.toLong
+~~~
+
+Using an alias, this can be expressed more concisely as:
+
+```scala
+given Conversion[Int, Long] = (x: Int) => x.toLong
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Using an Implicit Conversion
+
+Implicit conversions are applied in two situations:
+
+1. If an expression `e` is of type `S`, and `S` does not conform to the expression's expected type `T`.
+2. In a selection `e.m` with `e` of type `S`, if the selector `m` does not denote a member of `S`
+ (to support Scala-2-style [extension methods]).
+
+In the first case, a conversion `c` is searched for, which is applicable to `e` and whose result type conforms to `T`.
+
+In our example above, when we pass the argument `id` of type `Int` to the method `findUserById`,
+the implicit conversion `int2long(id)` is inserted.
+
+In the second case, a conversion `c` is searched for, which is applicable to `e` and whose result contains a member named `m`.
+
+An example is to compare two strings `"foo" < "bar"`. In this case, `String` has no member `<`, so the implicit conversion `Predef.augmentString("foo") < "bar"` is inserted. (`scala.Predef` is automatically imported into all Scala programs.)
+
+### How Are Implicit Conversions Brought Into Scope?
+
+When the compiler searches for applicable conversions:
+
+- first, it looks into the current lexical scope
+ - implicit conversions defined in the current scope or the outer scopes
+ - imported implicit conversions
+ - implicit conversions imported by a wildcard import (Scala 2 only)
+- then, it looks into the [companion objects] _associated_ with the argument
+ type `S` or the expected type `T`. The companion objects associated with
+ a type `X` are:
+ - the companion object `X` itself
+ - the companion objects associated with any of `X`’s inherited types
+ - the companion objects associated with any type argument in `X`
+ - if `X` is an inner class, the outer objects in which it is embedded
+
+For instance, consider an implicit conversion `fromStringToUser` defined in an
+object `Conversions`:
+
+{% tabs implicit-conversions-4 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+~~~ scala
+import scala.language.implicitConversions
+
+object Conversions {
+ implicit def fromStringToUser(name: String): User = User(name)
+}
+~~~
+{% endtab %}
+{% tab 'Scala 3' %}
+~~~ scala
+object Conversions:
+ given fromStringToUser: Conversion[String, User] = (name: String) => User(name)
+~~~
+{% endtab %}
+{% endtabs %}
+
+The following imports would equivalently bring the conversion into scope:
+
+{% tabs implicit-conversions-5 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+~~~ scala
+import Conversions.fromStringToUser
+// or
+import Conversions._
+~~~
+{% endtab %}
+{% tab 'Scala 3' %}
+~~~ scala
+import Conversions.fromStringToUser
+// or
+import Conversions.given
+// or
+import Conversions.{given Conversion[String, User]}
+~~~
+
+Note that in Scala 3, a wildcard import (ie `import Conversions.*`) does not import given
+definitions.
+{% endtab %}
+{% endtabs %}
+
+In the introductory example, the conversion from `Int` to `Long` does not require an import
+because it is defined in the object `Int`, which is the companion object of the type `Int`.
+
+Further reading:
+[Where does Scala look for implicits? (on Stackoverflow)](https://stackoverflow.com/a/5598107).
+
+### Beware the Power of Implicit Conversions
+
+{% tabs implicit-conversions-6 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+Because implicit conversions can have pitfalls if used indiscriminately the compiler warns when compiling the implicit conversion definition.
+
+To turn off the warnings take either of these actions:
+
+* Import `scala.language.implicitConversions` into the scope of the implicit conversion definition
+* Invoke the compiler with `-language:implicitConversions`
+
+No warning is emitted when the conversion is applied by the compiler.
+{% endtab %}
+{% tab 'Scala 3' %}
+Because implicit conversions can have pitfalls if used indiscriminately the compiler warns in two situations:
+- when compiling a Scala 2 style implicit conversion definition.
+- at the call site where a given instance of `scala.Conversion` is inserted as a conversion.
+
+To turn off the warnings take either of these actions:
+
+- Import `scala.language.implicitConversions` into the scope of:
+ - a Scala 2 style implicit conversion definition
+ - call sites where a given instance of `scala.Conversion` is inserted as a conversion.
+- Invoke the compiler with `-language:implicitConversions`
+{% endtab %}
+{% endtabs %}
+
+[extension methods]: {% link _overviews/scala3-book/ca-extension-methods.md %}
+[companion objects]: {% link _overviews/scala3-book/domain-modeling-tools.md %}#companion-objects
diff --git a/_overviews/scala3-book/ca-multiversal-equality.md b/_overviews/scala3-book/ca-multiversal-equality.md
new file mode 100644
index 0000000000..dfc6b4cdb0
--- /dev/null
+++ b/_overviews/scala3-book/ca-multiversal-equality.md
@@ -0,0 +1,201 @@
+---
+title: Multiversal Equality
+type: section
+description: This page demonstrates how to implement Multiversal Equality in Scala 3.
+languages: [ru, zh-cn]
+num: 66
+previous-page: ca-type-classes
+next-page: ca-implicit-conversions
+scala3: true
+versionSpecific: true
+---
+
+Previously, Scala had *universal equality*: Two values of any types could be compared with each other using `==` and `!=`.
+This came from the fact that `==` and `!=` are implemented in terms of Java’s `equals` method, which can also compare values of any two reference types.
+
+Universal equality is convenient, but it’s also dangerous since it undermines type safety.
+For instance, let’s assume that after some refactoring, you’re left with an erroneous program where a value `y` has type `S` instead of the correct type `T`:
+
+```scala
+val x = ... // of type T
+val y = ... // of type S, but should be T
+x == y // typechecks, will always yield false
+```
+
+If `y` gets compared to other values of type `T`, the program will still typecheck, since values of all types can be compared with each other.
+But it will probably give unexpected results and fail at runtime.
+
+A type-safe programming language can do better, and multiversal equality is an opt-in way to make universal equality safer.
+It uses the binary type class `CanEqual` to indicate that values of two given types can be compared with each other.
+
+
+## Allowing the comparison of class instances
+
+By default, in Scala 3 you can still create an equality comparison like this:
+
+```scala
+case class Cat(name: String)
+case class Dog(name: String)
+val d = Dog("Fido")
+val c = Cat("Morris")
+
+d == c // false, but it compiles
+```
+
+But with Scala 3 you can disable such comparisons.
+By (a) importing `scala.language.strictEquality` or (b) using the `-language:strictEquality` compiler flag, this comparison no longer compiles:
+
+```scala
+import scala.language.strictEquality
+
+val rover = Dog("Rover")
+val fido = Dog("Fido")
+println(rover == fido) // compiler error
+
+// compiler error message:
+// Values of types Dog and Dog cannot be compared with == or !=
+```
+
+
+## Enabling comparisons
+
+There are two ways to enable this comparison using the Scala 3 `CanEqual` type class.
+For simple cases like this, your class can *derive* the `CanEqual` class:
+
+```scala
+// Option 1
+case class Dog(name: String) derives CanEqual
+```
+
+As you’ll see in a few moments, when you need more flexibility you can also use this syntax:
+
+```scala
+// Option 2
+case class Dog(name: String)
+given CanEqual[Dog, Dog] = CanEqual.derived
+```
+
+Either of those two approaches now let `Dog` instances to be compared to each other.
+
+
+## A more real-world example
+
+In a more real-world example, imagine you have an online bookstore and want to allow or disallow the comparison of physical, printed books, and audiobooks.
+With Scala 3 you start by enabling multiversal equality as shown in the previous example:
+
+```scala
+// [1] add this import, or this command line flag: -language:strictEquality
+import scala.language.strictEquality
+```
+
+Then create your domain objects as usual:
+
+```scala
+// [2] create your class hierarchy
+trait Book:
+ def author: String
+ def title: String
+ def year: Int
+
+case class PrintedBook(
+ author: String,
+ title: String,
+ year: Int,
+ pages: Int
+) extends Book
+
+case class AudioBook(
+ author: String,
+ title: String,
+ year: Int,
+ lengthInMinutes: Int
+) extends Book
+```
+
+Finally, use `CanEqual` to define which comparisons you want to allow:
+
+```scala
+// [3] create type class instances to define the allowed comparisons.
+// allow `PrintedBook == PrintedBook`
+// allow `AudioBook == AudioBook`
+given CanEqual[PrintedBook, PrintedBook] = CanEqual.derived
+given CanEqual[AudioBook, AudioBook] = CanEqual.derived
+
+// [4a] comparing two printed books works as desired
+val p1 = PrintedBook("1984", "George Orwell", 1961, 328)
+val p2 = PrintedBook("1984", "George Orwell", 1961, 328)
+println(p1 == p2) // true
+
+// [4b] you can’t compare a printed book and an audiobook
+val pBook = PrintedBook("1984", "George Orwell", 1961, 328)
+val aBook = AudioBook("1984", "George Orwell", 2006, 682)
+println(pBook == aBook) // compiler error
+```
+
+The last line of code results in this compiler error message:
+
+````
+Values of types PrintedBook and AudioBook cannot be compared with == or !=
+````
+
+This is how multiversal equality catches illegal type comparisons at compile time.
+
+
+### Enabling “PrintedBook == AudioBook”
+
+That works as desired, but in some situations you may want to allow the comparison of physical books to audiobooks.
+When you want this, create these two additional equality comparisons:
+
+```scala
+// allow `PrintedBook == AudioBook`, and `AudioBook == PrintedBook`
+given CanEqual[PrintedBook, AudioBook] = CanEqual.derived
+given CanEqual[AudioBook, PrintedBook] = CanEqual.derived
+```
+
+Now you can compare physical books to audiobooks without a compiler error:
+
+```scala
+println(pBook == aBook) // false
+println(aBook == pBook) // false
+```
+
+#### Implement “equals” to make them really work
+
+While these comparisons are now allowed, they will always be `false` because their `equals` methods don’t know how to make these comparisons.
+Therefore, the solution is to override the `equals` methods for each class.
+For instance, when you override the `equals` method for `AudioBook`:
+
+```scala
+case class AudioBook(
+ author: String,
+ title: String,
+ year: Int,
+ lengthInMinutes: Int
+) extends Book:
+ // override to allow AudioBook to be compared to PrintedBook
+ override def equals(that: Any): Boolean = that match
+ case a: AudioBook =>
+ this.author == a.author
+ && this.title == a.title
+ && this.year == a.year
+ && this.lengthInMinutes == a.lengthInMinutes
+ case p: PrintedBook =>
+ this.author == p.author && this.title == p.title
+ case _ =>
+ false
+```
+
+You can now compare an `AudioBook` to a `PrintedBook`:
+
+```scala
+println(aBook == pBook) // true (works because of `equals` in `AudioBook`)
+println(pBook == aBook) // false
+```
+
+Currently, the `PrintedBook` book doesn’t have an `equals` method, so the second comparison returns `false`.
+To enable that comparison, just override the `equals` method in `PrintedBook`.
+
+You can find additional information on [multiversal equality][ref-equal] in the reference documentation.
+
+
+[ref-equal]: {{ site.scala3ref }}/contextual/multiversal-equality.html
diff --git a/_overviews/scala3-book/ca-summary.md b/_overviews/scala3-book/ca-summary.md
new file mode 100644
index 0000000000..bdd8c58537
--- /dev/null
+++ b/_overviews/scala3-book/ca-summary.md
@@ -0,0 +1,34 @@
+---
+title: Summary
+type: section
+description: This page provides a summary of the Contextual Abstractions lessons.
+languages: [ru, zh-cn]
+num: 68
+previous-page: ca-implicit-conversions
+next-page: concurrency
+---
+
+This chapter provides an introduction to most Contextual Abstractions topics, including:
+
+- [Extension Methods]({% link _overviews/scala3-book/ca-extension-methods.md %})
+- [Given Instances and Using Clauses]({% link _overviews/scala3-book/ca-context-parameters.md %})
+- [Context Bounds]({% link _overviews/scala3-book/ca-context-bounds.md %})
+- [Given Imports]({% link _overviews/scala3-book/ca-given-imports.md %})
+- [Type Classes]({% link _overviews/scala3-book/ca-type-classes.md %})
+- [Multiversal Equality]({% link _overviews/scala3-book/ca-multiversal-equality.md %})
+- [Implicit Conversions]({% link _overviews/scala3-book/ca-implicit-conversions.md %})
+
+These features are all variants of the core idea of **term inference**: given a type, the compiler synthesizes a “canonical” term that has that type.
+
+A few more advanced topics aren’t covered here, including:
+
+- Conditional Given Instances
+- Type Class Derivation
+- Context Functions
+- By-Name Context Parameters
+- Relationship with Scala 2 Implicits
+
+Those topics are discussed in detail in the [Reference documentation][ref].
+
+
+[ref]: {{ site.scala3ref }}/contextual
diff --git a/_overviews/scala3-book/ca-type-classes.md b/_overviews/scala3-book/ca-type-classes.md
new file mode 100644
index 0000000000..2a56a5de47
--- /dev/null
+++ b/_overviews/scala3-book/ca-type-classes.md
@@ -0,0 +1,188 @@
+---
+title: Type Classes
+type: section
+description: This page demonstrates how to create and use type classes.
+languages: [ru, zh-cn]
+num: 65
+previous-page: ca-given-imports
+next-page: ca-multiversal-equality
+redirect_from: /scala3/book/types-type-classes.html
+---
+
+A _type class_ is an abstract, parameterized type that lets you add new behavior to any closed data type without using sub-typing.
+If you are coming from Java, you can think of type classes as something like [`java.util.Comparator[T]`][comparator].
+
+> The paper [“Type Classes as Objects and Implicits”][typeclasses-paper] (2010) by Oliveira et al. discusses the basic ideas behind type classes in Scala.
+> Even though the paper uses an older version of Scala, the ideas still hold to the current day.
+
+A type class is useful in multiple use-cases, for example:
+
+- Expressing how a type you don’t own---from the standard library or a third-party library---conforms to such behavior
+- Expressing such a behavior for multiple types without involving sub-typing relationships between those types
+
+Type classes are traits with one or more parameters whose implementations are provided as `given` instances in Scala 3 or `implicit` values in Scala 2.
+
+## Example
+
+For example, `Show` is a well-known type class in Haskell, and the following code shows one way to implement it in Scala.
+If you imagine that Scala classes don’t have a `toString` method, you can define a `Show` type class to add this behavior to any type that you want to be able to convert to a custom string.
+
+### The type class
+
+The first step in creating a type class is to declare a parameterized trait that has one or more abstract methods.
+Because `Showable` only has one method named `show`, it’s written like this:
+
+{% tabs 'definition' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+// a type class
+trait Showable[A] {
+ def show(a: A): String
+}
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+// a type class
+trait Showable[A]:
+ extension (a: A) def show: String
+```
+{% endtab %}
+{% endtabs %}
+
+Notice that this approach is close to the usual object-oriented approach, where you would typically define a trait `Show` as follows:
+
+{% tabs 'trait' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+// a trait
+trait Show {
+ def show: String
+}
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+// a trait
+trait Show:
+ def show: String
+```
+{% endtab %}
+{% endtabs %}
+
+There are a few important things to point out:
+
+1. Type-classes like `Showable` take a type parameter `A` to say which type we provide the implementation of `show` for; in contrast, classic traits like `Show` do not.
+2. To add the show functionality to a certain type `A`, the classic trait requires that `A extends Show`, while for type-classes we require to have an implementation of `Showable[A]`.
+3. In Scala 3, to allow the same method calling syntax in both `Showable` that mimics the one of `Show`, we define `Showable.show` as an extension method.
+
+### Implement concrete instances
+
+The next step is to determine what classes in your application `Showable` should work for, and then implement that behavior for them.
+For instance, to implement `Showable` for this `Person` class:
+
+{% tabs 'person' %}
+{% tab 'Scala 2 and 3' %}
+```scala
+case class Person(firstName: String, lastName: String)
+```
+{% endtab %}
+{% endtabs %}
+
+you’ll define a single _canonical value_ of type `Showable[Person]`, ie an instance of `Showable` for the type `Person`, as the following code example demonstrates:
+
+{% tabs 'instance' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+implicit val showablePerson: Showable[Person] = new Showable[Person] {
+ def show(p: Person): String =
+ s"${p.firstName} ${p.lastName}"
+}
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+given Showable[Person] with
+ extension (p: Person) def show: String =
+ s"${p.firstName} ${p.lastName}"
+```
+{% endtab %}
+{% endtabs %}
+
+### Using the type class
+
+Now you can use this type class like this:
+
+{% tabs 'usage' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+val person = Person("John", "Doe")
+println(showablePerson.show(person))
+```
+
+Note that in practice, type classes are typically used with values whose type is unknown, unlike the type `Person`, as shown in the next section.
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+val person = Person("John", "Doe")
+println(person.show)
+```
+{% endtab %}
+{% endtabs %}
+
+Again, if Scala didn’t have a `toString` method available to every class, you could use this technique to add `Showable` behavior to any class that you want to be able to convert to a `String`.
+
+### Writing methods that use the type class
+
+As with inheritance, you can define methods that use `Showable` as a type parameter:
+
+{% tabs 'method' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+def showAll[A](as: List[A])(implicit showable: Showable[A]): Unit =
+ as.foreach(a => println(showable.show(a)))
+
+showAll(List(Person("Jane"), Person("Mary")))
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+def showAll[A: Showable](as: List[A]): Unit =
+ as.foreach(a => println(a.show))
+
+showAll(List(Person("Jane"), Person("Mary")))
+```
+{% endtab %}
+{% endtabs %}
+
+### A type class with multiple methods
+
+Note that if you want to create a type class that has multiple methods, the initial syntax looks like this:
+
+{% tabs 'multiple-methods' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+trait HasLegs[A] {
+ def walk(a: A): Unit
+ def run(a: A): Unit
+}
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+trait HasLegs[A]:
+ extension (a: A)
+ def walk(): Unit
+ def run(): Unit
+```
+{% endtab %}
+{% endtabs %}
+
+### A real-world example
+
+For a real-world example of how type classes are used in Scala 3, see the `CanEqual` discussion in the [Multiversal Equality section][multiversal].
+
+[typeclasses-paper]: https://infoscience.epfl.ch/record/150280/files/TypeClasses.pdf
+[typeclasses-chapter]: {% link _overviews/scala3-book/ca-type-classes.md %}
+[comparator]: https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html
+[multiversal]: {% link _overviews/scala3-book/ca-multiversal-equality.md %}
diff --git a/_overviews/scala3-book/collections-classes.md b/_overviews/scala3-book/collections-classes.md
new file mode 100644
index 0000000000..acf3a7ff87
--- /dev/null
+++ b/_overviews/scala3-book/collections-classes.md
@@ -0,0 +1,975 @@
+---
+title: Collections Types
+type: section
+description: This page introduces the common Scala 3 collections types and some of their methods.
+languages: [ru, zh-cn]
+num: 39
+previous-page: collections-intro
+next-page: collections-methods
+---
+
+
+{% comment %}
+TODO: mention Array, ArrayDeque, ListBuffer, Queue, Stack, StringBuilder?
+LATER: note that methods like `+`, `++`, etc., are aliases for other methods
+LATER: add links to the Scaladoc for the major types shown here
+{% endcomment %}
+
+
+This page demonstrates the common Scala 3 collections and their accompanying methods.
+Scala comes with a wealth of collections types, but you can go a long way by starting with just a few of them, and later using the others as needed.
+Similarly, each collection type has dozens of methods to make your life easier, but you can achieve a lot by starting with just a handful of them.
+
+Therefore, this section introduces and demonstrates the most common types and methods that you’ll need to get started.
+When you need more flexibility, see these pages at the end of this section for more details.
+
+
+
+## Three main categories of collections
+
+Looking at Scala collections from a high level, there are three main categories to choose from:
+
+- **Sequences** are a sequential collection of elements and may be _indexed_ (like an array) or _linear_ (like a linked list)
+- **Maps** contain a collection of key/value pairs, like a Java `Map`, Python dictionary, or Ruby `Hash`
+- **Sets** are an unordered collection of unique elements
+
+All of those are basic types, and have subtypes for specific purposes, such as concurrency, caching, and streaming.
+In addition to those three main categories, there are other useful collection types, including ranges, stacks, and queues.
+
+
+### Collections hierarchy
+
+As a brief overview, the next three figures show the hierarchy of classes and traits in the Scala collections.
+
+This first figure shows the collections types in package
+_scala.collection_.
+These are all high-level abstract classes or traits, which
+generally have _immutable_ and _mutable_ implementations.
+
+![General collection hierarchy][collections1]
+
+This figure shows all collections in package _scala.collection.immutable_:
+
+![Immutable collection hierarchy][collections2]
+
+And this figure shows all collections in package _scala.collection.mutable_:
+
+![Mutable collection hierarchy][collections3]
+
+Having seen that detailed view of all the collections types, the following sections introduce some common types you’ll use on a regular basis.
+
+{% comment %}
+NOTE: those images come from this page: https://docs.scala-lang.org/overviews/collections-2.13/overview.html
+{% endcomment %}
+
+
+
+## Common collections
+
+The main collections you’ll use on a regular basis are:
+
+| Collection Type | Immutable | Mutable | Description |
+| ------------- | --------- | ------- | ----------- |
+| `List` | ✓ | | A linear (linked list), immutable sequence |
+| `Vector` | ✓ | | An indexed, immutable sequence |
+| `LazyList` | ✓ | | A lazy immutable linked list, its elements are computed only when they’re needed; Good for large or infinite sequences. |
+| `ArrayBuffer` | | ✓ | The go-to type for a mutable, indexed sequence |
+| `ListBuffer` | | ✓ | Used when you want a mutable `List`; typically converted to a `List` |
+| `Map` | ✓ | ✓ | An iterable collection that consists of pairs of keys and values. |
+| `Set` | ✓ | ✓ | An iterable collection with no duplicate elements |
+
+As shown, `Map` and `Set` come in both immutable and mutable versions.
+
+The basics of each type are demonstrated in the following sections.
+
+> In Scala, a _buffer_---such as `ArrayBuffer` and `ListBuffer`---is a sequence that can grow and shrink.
+
+
+### A note about immutable collections
+
+In the sections that follow, whenever the word _immutable_ is used, it’s safe to assume that the type is intended for use in a _functional programming_ (FP) style.
+With these types you don’t modify the collection; you apply functional methods to the collection to create a new result.
+
+
+
+## Choosing a sequence
+
+When choosing a _sequence_---a sequential collection of elements---you have two main decisions:
+
+- Should the sequence be indexed (like an array), allowing rapid access to any element, or should it be implemented as a linear linked list?
+- Do you want a mutable or immutable collection?
+
+The recommended, general-purpose, “go to” sequential collections for the combinations of mutable/immutable and indexed/linear are shown here:
+
+| Type/Category | Immutable | Mutable |
+| --------------------- | --------- | ------------ |
+| Indexed | `Vector` |`ArrayBuffer` |
+| Linear (Linked lists) | `List` |`ListBuffer` |
+
+For example, if you need an immutable, indexed collection, in general you should use a `Vector`.
+Conversely, if you need a mutable, indexed collection, use an `ArrayBuffer`.
+
+> `List` and `Vector` are often used when writing code in a functional style.
+> `ArrayBuffer` is commonly used when writing code in an imperative style.
+> `ListBuffer` is used when you’re mixing styles, such as building a list.
+
+The next several sections briefly demonstrate the `List`, `Vector`, and `ArrayBuffer` types.
+
+
+
+## `List`
+
+[The List type](https://www.scala-lang.org/api/current/scala/collection/immutable/List.html) is a linear, immutable sequence.
+This just means that it’s a linked-list that you can’t modify.
+Any time you want to add or remove `List` elements, you create a new `List` from an existing `List`.
+
+### Creating Lists
+
+This is how you create an initial `List`:
+
+{% tabs list-creation %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val ints = List(1, 2, 3)
+val names = List("Joel", "Chris", "Ed")
+
+// another way to construct a List
+val namesAgain = "Joel" :: "Chris" :: "Ed" :: Nil
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+You can also declare the `List`’s type, if you prefer, though it generally isn’t necessary:
+
+{% tabs list-type %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val ints: List[Int] = List(1, 2, 3)
+val names: List[String] = List("Joel", "Chris", "Ed")
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+One exception is when you have mixed types in a collection; in that case you may want to explicitly specify its type:
+
+{% tabs list-mixed-types class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+val things: List[Any] = List(1, "two", 3.0)
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val things: List[String | Int | Double] = List(1, "two", 3.0) // with union types
+val thingsAny: List[Any] = List(1, "two", 3.0) // with any
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Adding elements to a List
+
+Because `List` is immutable, you can’t add new elements to it.
+Instead, you create a new list by prepending or appending elements to an existing `List`.
+For instance, given this `List`:
+
+{% tabs adding-elements-init %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = List(1, 2, 3)
+```
+{% endtab %}
+
+{% endtabs %}
+
+When working with a `List`, _prepend_ one element with `::`, and prepend another `List` with `:::`, as shown here:
+
+{% tabs adding-elements-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val b = 0 :: a // List(0, 1, 2, 3)
+val c = List(-1, 0) ::: a // List(-1, 0, 1, 2, 3)
+```
+{% endtab %}
+
+{% endtabs %}
+
+You can also _append_ elements to a `List`, but because `List` is a singly-linked list, you should generally only prepend elements to it;
+appending elements to it is a relatively slow operation, especially when you work with large sequences.
+
+> Tip: If you want to prepend and append elements to an immutable sequence, use `Vector` instead.
+
+Because `List` is a linked-list, you shouldn’t try to access the elements of large lists by their index value.
+For instance, if you have a `List` with one million elements in it, accessing an element like `myList(999_999)` will take a relatively long time, because that request has to traverse all those elements.
+If you have a large collection and want to access elements by their index, use a `Vector` or `ArrayBuffer` instead.
+
+### How to remember the method names
+
+These days IDEs help us out tremendously, but one way to remember those method names is to think that the `:` character represents the side that the sequence is on, so when you use `+:` you know that the list needs to be on the right, like this:
+
+{% tabs list-prepending %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+0 +: a
+```
+{% endtab %}
+
+{% endtabs %}
+
+Similarly, when you use `:+` you know the list needs to be on the left:
+
+{% tabs list-appending %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+a :+ 4
+```
+{% endtab %}
+
+{% endtabs %}
+
+There are more technical ways to think about this, but this can be a helpful way to remember the method names.
+
+{% comment %}
+LATER: Add a discussion of `:` on method names, right-associativity, and infix operators.
+{% endcomment %}
+
+Also, a good thing about these symbolic method names is that they’re consistent.
+The same method names are used with other immutable sequences, such as `Seq` and `Vector`.
+You can also use non-symbolic method names to append and prepend elements, if you prefer.
+
+### How to loop over lists
+
+Given a `List` of names:
+
+{% tabs list-loop-init %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val names = List("Joel", "Chris", "Ed")
+```
+{% endtab %}
+
+{% endtabs %}
+
+you can print each string like this:
+
+{% tabs list-loop-example class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+for (name <- names) println(name)
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+for name <- names do println(name)
+```
+{% endtab %}
+
+{% endtabs %}
+
+This is what it looks like in the REPL:
+
+{% tabs list-loop-repl class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+scala> for (name <- names) println(name)
+Joel
+Chris
+Ed
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+scala> for name <- names do println(name)
+Joel
+Chris
+Ed
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+A great thing about using `for` loops with collections is that Scala is consistent, and the same approach works with all sequences, including `Array`, `ArrayBuffer`, `List`, `Seq`, `Vector`, `Map`, `Set`, etc.
+
+### A little bit of history
+
+For those interested in a little bit of history, the Scala `List` is similar to the `List` from [the Lisp programming language](https://en.wikipedia.org/wiki/Lisp_(programming_language)), which was originally specified in 1958.
+Indeed, in addition to creating a `List` like this:
+
+{% tabs list-history-init %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val ints = List(1, 2, 3)
+```
+{% endtab %}
+
+{% endtabs %}
+
+you can also create the exact same list this way:
+
+{% tabs list-history-init2 %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val list = 1 :: 2 :: 3 :: Nil
+```
+{% endtab %}
+
+{% endtabs %}
+
+The REPL shows how this works:
+
+{% tabs list-history-repl %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> val list = 1 :: 2 :: 3 :: Nil
+list: List[Int] = List(1, 2, 3)
+```
+{% endtab %}
+
+{% endtabs %}
+
+This works because a `List` is a singly-linked list that ends with the `Nil` element, and `::` is a `List` method that works like Lisp’s “cons” operator.
+
+
+### Aside: The LazyList
+
+The Scala collections also include a [LazyList](https://www.scala-lang.org/api/current/scala/collection/immutable/LazyList.html), which is a _lazy_ immutable linked list.
+It’s called “lazy”---or non-strict---because it computes its elements only when they are needed.
+
+You can see how lazy a `LazyList` is in the REPL:
+
+{% tabs lazylist-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val x = LazyList.range(1, Int.MaxValue)
+x.take(1) // LazyList()
+x.take(5) // LazyList()
+x.map(_ + 1) // LazyList()
+```
+{% endtab %}
+
+{% endtabs %}
+
+In all of those examples, nothing happens.
+Indeed, nothing will happen until you force it to happen, such as by calling its `foreach` method:
+
+{% tabs lazylist-evaluation-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> x.take(1).foreach(println)
+1
+```
+{% endtab %}
+
+{% endtabs %}
+
+For more information on the uses, benefits, and drawbacks of strict and non-strict (lazy) collections, see the “strict” and “non-strict” discussions on the [The Architecture of Scala 2.13’s Collections][strict] page.
+
+
+
+
+
+## Vector
+
+[Vector](https://www.scala-lang.org/api/current/scala/collection/immutable/Vector.html) is an indexed, immutable sequence.
+The “indexed” part of the description means that it provides random access and update in effectively constant time, so you can access `Vector` elements rapidly by their index value, such as accessing `listOfPeople(123_456_789)`.
+
+In general, except for the difference that (a) `Vector` is indexed and `List` is not, and (b) `List` has the `::` method, the two types work the same, so we’ll quickly run through the following examples.
+
+Here are a few ways you can create a `Vector`:
+
+{% tabs vector-creation %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val nums = Vector(1, 2, 3, 4, 5)
+
+val strings = Vector("one", "two")
+
+case class Person(name: String)
+val people = Vector(
+ Person("Bert"),
+ Person("Ernie"),
+ Person("Grover")
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Because `Vector` is immutable, you can’t add new elements to it.
+Instead, you create a new sequence by appending or prepending elements to an existing `Vector`.
+These examples show how to _append_ elements to a `Vector`:
+
+{% tabs vector-appending %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = Vector(1,2,3) // Vector(1, 2, 3)
+val b = a :+ 4 // Vector(1, 2, 3, 4)
+val c = a ++ Vector(4, 5) // Vector(1, 2, 3, 4, 5)
+```
+{% endtab %}
+
+{% endtabs %}
+
+This is how you _prepend_ elements:
+
+{% tabs vector-prepending %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = Vector(1,2,3) // Vector(1, 2, 3)
+val b = 0 +: a // Vector(0, 1, 2, 3)
+val c = Vector(-1, 0) ++: a // Vector(-1, 0, 1, 2, 3)
+```
+{% endtab %}
+
+{% endtabs %}
+
+In addition to fast random access and updates, `Vector` provides fast append and prepend times, so you can use these features as desired.
+
+> See the [Collections Performance Characteristics](https://docs.scala-lang.org/overviews/collections-2.13/performance-characteristics.html) for performance details about `Vector` and other collections.
+
+Finally, you use a `Vector` in a `for` loop just like a `List`, `ArrayBuffer`, or any other sequence:
+
+{% tabs vector-loop class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+scala> val names = Vector("Joel", "Chris", "Ed")
+val names: Vector[String] = Vector(Joel, Chris, Ed)
+
+scala> for (name <- names) println(name)
+Joel
+Chris
+Ed
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+scala> val names = Vector("Joel", "Chris", "Ed")
+val names: Vector[String] = Vector(Joel, Chris, Ed)
+
+scala> for name <- names do println(name)
+Joel
+Chris
+Ed
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+## ArrayBuffer
+
+Use `ArrayBuffer` when you need a general-purpose, mutable indexed sequence in your Scala applications.
+It’s mutable, so you can change its elements, and also resize it.
+Because it’s indexed, random access of elements is fast.
+
+### Creating an ArrayBuffer
+
+To use an `ArrayBuffer`, first import it:
+
+{% tabs arraybuffer-import %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+import scala.collection.mutable.ArrayBuffer
+```
+{% endtab %}
+
+{% endtabs %}
+
+If you need to start with an empty `ArrayBuffer`, just specify its type:
+
+{% tabs arraybuffer-creation %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+var strings = ArrayBuffer[String]()
+var ints = ArrayBuffer[Int]()
+var people = ArrayBuffer[Person]()
+```
+{% endtab %}
+
+{% endtabs %}
+
+If you know the approximate size your `ArrayBuffer` eventually needs to be, you can create it with an initial size:
+
+{% tabs list-creation-with-size %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+// ready to hold 100,000 ints
+val buf = new ArrayBuffer[Int](100_000)
+```
+{% endtab %}
+
+{% endtabs %}
+
+To create a new `ArrayBuffer` with initial elements, just specify its initial elements, just like a `List` or `Vector`:
+
+{% tabs arraybuffer-init %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val nums = ArrayBuffer(1, 2, 3)
+val people = ArrayBuffer(
+ Person("Bert"),
+ Person("Ernie"),
+ Person("Grover")
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Adding elements to an ArrayBuffer
+
+Append new elements to an `ArrayBuffer` with the `+=` and `++=` methods.
+Or if you prefer methods with textual names you can also use `append`, `appendAll`, `insert`, `insertAll`, `prepend`, and `prependAll`.
+
+Here are some examples of `+=` and `++=`:
+
+{% tabs arraybuffer-add %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val nums = ArrayBuffer(1, 2, 3) // ArrayBuffer(1, 2, 3)
+nums += 4 // ArrayBuffer(1, 2, 3, 4)
+nums ++= List(5, 6) // ArrayBuffer(1, 2, 3, 4, 5, 6)
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Removing elements from an ArrayBuffer
+
+`ArrayBuffer` is mutable, so it has methods like `-=`, `--=`, `clear`, `remove`, and more.
+These examples demonstrate the `-=` and `--=` methods:
+
+{% tabs arraybuffer-remove %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = ArrayBuffer.range('a', 'h') // ArrayBuffer(a, b, c, d, e, f, g)
+a -= 'a' // ArrayBuffer(b, c, d, e, f, g)
+a --= Seq('b', 'c') // ArrayBuffer(d, e, f, g)
+a --= Set('d', 'e') // ArrayBuffer(f, g)
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Updating ArrayBuffer elements
+
+Update elements in an `ArrayBuffer` by either reassigning the desired element, or use the `update` method:
+
+{% tabs arraybuffer-update %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = ArrayBuffer.range(1,5) // ArrayBuffer(1, 2, 3, 4)
+a(2) = 50 // ArrayBuffer(1, 2, 50, 4)
+a.update(0, 10) // ArrayBuffer(10, 2, 50, 4)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+
+## Maps
+
+A `Map` is an iterable collection that consists of pairs of keys and values.
+Scala has both mutable and immutable `Map` types, and this section demonstrates how to use the _immutable_ `Map`.
+
+### Creating an immutable Map
+
+Create an immutable `Map` like this:
+
+{% tabs map-init %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val states = Map(
+ "AK" -> "Alaska",
+ "AL" -> "Alabama",
+ "AZ" -> "Arizona"
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Once you have a `Map` you can traverse its elements in a `for` loop like this:
+
+{% tabs map-loop class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+for ((k, v) <- states) println(s"key: $k, value: $v")
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+for (k, v) <- states do println(s"key: $k, value: $v")
+```
+{% endtab %}
+
+{% endtabs %}
+
+The REPL shows how this works:
+
+{% tabs map-repl class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+scala> for ((k, v) <- states) println(s"key: $k, value: $v")
+key: AK, value: Alaska
+key: AL, value: Alabama
+key: AZ, value: Arizona
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+scala> for (k, v) <- states do println(s"key: $k, value: $v")
+key: AK, value: Alaska
+key: AL, value: Alabama
+key: AZ, value: Arizona
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Accessing Map elements
+
+Access map elements by specifying the desired key value in parentheses:
+
+{% tabs map-access-element %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val ak = states("AK") // ak: String = Alaska
+val al = states("AL") // al: String = Alabama
+```
+{% endtab %}
+
+{% endtabs %}
+
+In practice, you’ll also use methods like `keys`, `keySet`, `keysIterator`, `for` loops, and higher-order functions like `map` to work with `Map` keys and values.
+
+### Adding elements to a Map
+
+Add elements to an immutable map using `+` and `++`, remembering to assign the result to a new variable:
+
+{% tabs map-add-element %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = Map(1 -> "one") // a: Map(1 -> one)
+val b = a + (2 -> "two") // b: Map(1 -> one, 2 -> two)
+val c = b ++ Seq(
+ 3 -> "three",
+ 4 -> "four"
+)
+// c: Map(1 -> one, 2 -> two, 3 -> three, 4 -> four)
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Removing elements from a Map
+
+Remove elements from an immutable map using `-` or `--` and the key values to remove, remembering to assign the result to a new variable:
+
+{% tabs map-remove-element %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = Map(
+ 1 -> "one",
+ 2 -> "two",
+ 3 -> "three",
+ 4 -> "four"
+)
+
+val b = a - 4 // b: Map(1 -> one, 2 -> two, 3 -> three)
+val c = a - 4 - 3 // c: Map(1 -> one, 2 -> two)
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Updating Map elements
+
+To update elements in an immutable map, use the `updated` method (or the `+` operator) while assigning the result to a new variable:
+
+{% tabs map-update-element %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = Map(
+ 1 -> "one",
+ 2 -> "two",
+ 3 -> "three"
+)
+
+val b = a.updated(3, "THREE!") // b: Map(1 -> one, 2 -> two, 3 -> THREE!)
+val c = a + (2 -> "TWO...") // c: Map(1 -> one, 2 -> TWO..., 3 -> three)
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Traversing a Map
+
+As shown earlier, this is a common way to manually traverse elements in a map using a `for` loop:
+
+
+{% tabs map-traverse class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+val states = Map(
+ "AK" -> "Alaska",
+ "AL" -> "Alabama",
+ "AZ" -> "Arizona"
+)
+
+for ((k, v) <- states) println(s"key: $k, value: $v")
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val states = Map(
+ "AK" -> "Alaska",
+ "AL" -> "Alabama",
+ "AZ" -> "Arizona"
+)
+
+for (k, v) <- states do println(s"key: $k, value: $v")
+```
+{% endtab %}
+
+{% endtabs %}
+
+That being said, there are _many_ ways to work with the keys and values in a map.
+Common `Map` methods include `foreach`, `map`, `keys`, and `values`.
+
+Scala has many more specialized `Map` types, including `CollisionProofHashMap`, `HashMap`, `LinkedHashMap`, `ListMap`, `SortedMap`, `TreeMap`, `WeakHashMap`, and more.
+
+
+
+## Working with Sets
+
+The Scala [Set]({{site.baseurl}}/overviews/collections-2.13/sets.html) is an iterable collection with no duplicate elements.
+
+Scala has both mutable and immutable `Set` types.
+This section demonstrates the _immutable_ `Set`.
+
+
+### Creating a Set
+
+Create new empty sets like this:
+
+{% tabs set-creation %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val nums = Set[Int]()
+val letters = Set[Char]()
+```
+{% endtab %}
+
+{% endtabs %}
+
+Create sets with initial data like this:
+
+{% tabs set-init %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val nums = Set(1, 2, 3, 3, 3) // Set(1, 2, 3)
+val letters = Set('a', 'b', 'c', 'c') // Set('a', 'b', 'c')
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+### Adding elements to a Set
+
+Add elements to an immutable `Set` using `+` and `++`, remembering to assign the result to a new variable:
+
+{% tabs set-add-element %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = Set(1, 2) // Set(1, 2)
+val b = a + 3 // Set(1, 2, 3)
+val c = b ++ Seq(4, 1, 5, 5) // HashSet(5, 1, 2, 3, 4)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Notice that when you attempt to add duplicate elements, they’re quietly dropped.
+
+Also notice that the order of iteration of the elements is arbitrary.
+
+
+### Deleting elements from a Set
+
+Remove elements from an immutable set using `-` and `--`, again assigning the result to a new variable:
+
+{% tabs set-remove-element %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = Set(1, 2, 3, 4, 5) // HashSet(5, 1, 2, 3, 4)
+val b = a - 5 // HashSet(1, 2, 3, 4)
+val c = b -- Seq(3, 4) // HashSet(1, 2)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+
+## Range
+
+The Scala `Range` is often used to populate data structures and to iterate over `for` loops.
+These REPL examples demonstrate how to create ranges:
+
+{% comment %}
+LATER: the dotty repl currently shows results differently
+{% endcomment %}
+
+{% tabs range-init %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+1 to 5 // Range(1, 2, 3, 4, 5)
+1 until 5 // Range(1, 2, 3, 4)
+1 to 10 by 2 // Range(1, 3, 5, 7, 9)
+'a' to 'c' // NumericRange(a, b, c)
+```
+{% endtab %}
+
+{% endtabs %}
+
+You can use ranges to populate collections:
+
+{% tabs range-conversion %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val x = (1 to 5).toList // List(1, 2, 3, 4, 5)
+val x = (1 to 5).toBuffer // ArrayBuffer(1, 2, 3, 4, 5)
+```
+{% endtab %}
+
+{% endtabs %}
+
+They’re also used in `for` loops:
+
+{% tabs range-iteration class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+scala> for (i <- 1 to 3) println(i)
+1
+2
+3
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+scala> for i <- 1 to 3 do println(i)
+1
+2
+3
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+There are also `range` methods on :
+
+{% tabs range-methods %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+Vector.range(1, 5) // Vector(1, 2, 3, 4)
+List.range(1, 10, 2) // List(1, 3, 5, 7, 9)
+Set.range(1, 10) // HashSet(5, 1, 6, 9, 2, 7, 3, 8, 4)
+```
+{% endtab %}
+
+{% endtabs %}
+
+When you’re running tests, ranges are also useful for generating test collections:
+
+{% tabs range-tests %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val evens = (0 to 10 by 2).toList // List(0, 2, 4, 6, 8, 10)
+val odds = (1 to 10 by 2).toList // List(1, 3, 5, 7, 9)
+val doubles = (1 to 5).map(_ * 2.0) // Vector(2.0, 4.0, 6.0, 8.0, 10.0)
+
+// create a Map
+val map = (1 to 3).map(e => (e,s"$e")).toMap
+ // map: Map[Int, String] = Map(1 -> "1", 2 -> "2", 3 -> "3")
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+## More details
+
+When you need more information about specialized collections, see the following resources:
+
+- [Concrete Immutable Collection Classes](https://docs.scala-lang.org/overviews/collections-2.13/concrete-immutable-collection-classes.html)
+- [Concrete Mutable Collection Classes](https://docs.scala-lang.org/overviews/collections-2.13/concrete-mutable-collection-classes.html)
+- [How are the collections structured? Which one should I choose?](https://docs.scala-lang.org/tutorials/FAQ/collections.html)
+
+
+
+[strict]: {% link _overviews/core/architecture-of-scala-213-collections.md %}
+[collections1]: /resources/images/tour/collections-diagram-213.svg
+[collections2]: /resources/images/tour/collections-immutable-diagram-213.svg
+[collections3]: /resources/images/tour/collections-mutable-diagram-213.svg
diff --git a/_overviews/scala3-book/collections-intro.md b/_overviews/scala3-book/collections-intro.md
new file mode 100644
index 0000000000..e953b95302
--- /dev/null
+++ b/_overviews/scala3-book/collections-intro.md
@@ -0,0 +1,25 @@
+---
+title: Scala Collections
+type: chapter
+description: This page provides and introduction to the common collections classes and their methods in Scala 3.
+languages: [ru, zh-cn]
+num: 38
+previous-page: packaging-imports
+next-page: collections-classes
+---
+
+This chapter introduces the most common Scala 3 collections and their accompanying methods.
+Scala comes with a wealth of collections types, but you can go a long way by starting with just a few of them, and later using the others as needed.
+Similarly, each type has dozens of methods to make your life easier, but you can achieve a lot by starting with just a handful of them.
+
+Therefore, this section introduces and demonstrates the most common collections types and methods that you’ll need to get started.
+
+
+{% comment %}
+LATER: Use more of the content from this page:
+ https://docs.scala-lang.org/overviews/index.html
+{% endcomment %}
+
+
+
+
diff --git a/_overviews/scala3-book/collections-methods.md b/_overviews/scala3-book/collections-methods.md
new file mode 100644
index 0000000000..6a56814b5c
--- /dev/null
+++ b/_overviews/scala3-book/collections-methods.md
@@ -0,0 +1,644 @@
+---
+title: Collections Methods
+type: section
+description: This page demonstrates the common methods on the Scala 3 collections classes.
+languages: [ru, zh-cn]
+num: 40
+previous-page: collections-classes
+next-page: collections-summary
+---
+
+
+
+A great strength of Scala collections is that they come with dozens of methods out of the box, and those methods are consistently available across the immutable and mutable collections types.
+The benefits of this are that you no longer need to write custom `for` loops every time you need to work with a collection, and when you move from one project to another, you’ll find these same methods used, rather than more custom `for` loops.
+
+There are *dozens* of methods available to you, so they aren’t all shown here.
+Instead, only some of the most commonly-used methods are shown, including:
+
+- `map`
+- `filter`
+- `foreach`
+- `head`
+- `tail`
+- `take`, `takeWhile`
+- `drop`, `dropWhile`
+- `reduce`
+
+The following methods work on all of the sequence types, including `List`, `Vector`, `ArrayBuffer`, etc., but these examples use a `List` unless otherwise specified.
+
+> As a very important note, none of the methods on `List` mutate the list.
+> They all work in a functional style, meaning that they return a new collection with the modified results.
+
+
+
+## Examples of common methods
+
+To give you an overview of what you’ll see in the following sections, these examples show some of the most commonly used collections methods.
+First, here are some methods that don’t use lambdas:
+
+{% tabs common-method-examples %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = List(10, 20, 30, 40, 10) // List(10, 20, 30, 40, 10)
+
+a.distinct // List(10, 20, 30, 40)
+a.drop(2) // List(30, 40, 10)
+a.dropRight(2) // List(10, 20, 30)
+a.head // 10
+a.headOption // Some(10)
+a.init // List(10, 20, 30, 40)
+a.intersect(List(19,20,21)) // List(20)
+a.last // 10
+a.lastOption // Some(10)
+a.slice(2,4) // List(30, 40)
+a.tail // List(20, 30, 40, 10)
+a.take(3) // List(10, 20, 30)
+a.takeRight(2) // List(40, 10)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+### Higher-order functions and lambdas
+
+Next, we’ll show some commonly used higher-order functions (HOFs) that accept lambdas (anonymous functions).
+To get started, here are several variations of the lambda syntax, starting with the longest form, working in steps towards the most concise form:
+
+{% tabs higher-order-functions-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+// these functions are all equivalent and return
+// the same data: List(10, 20, 10)
+
+a.filter((i: Int) => i < 25) // 1. most explicit form
+a.filter((i) => i < 25) // 2. `Int` is not required
+a.filter(i => i < 25) // 3. the parens are not required
+a.filter(_ < 25) // 4. `i` is not required
+```
+{% endtab %}
+
+{% endtabs %}
+
+In those numbered examples:
+
+1. The first example shows the longest form.
+ This much verbosity is _rarely_ required, and only needed in the most complex usages.
+2. The compiler knows that `a` contains `Int`, so it’s not necessary to restate that here.
+3. Parentheses aren’t needed when you have only one parameter, such as `i`.
+4. When you have a single parameter, and it appears only once in your anonymous function, you can replace the parameter with `_`.
+
+The [Anonymous Function][lambdas] provides more details and examples of the rules related to shortening lambda expressions.
+
+Now that you’ve seen the concise form, here are examples of other HOFs that use the short-form lambda syntax:
+
+{% tabs anonymous-functions-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+a.dropWhile(_ < 25) // List(30, 40, 10)
+a.filter(_ > 100) // List()
+a.filterNot(_ < 25) // List(30, 40)
+a.find(_ > 20) // Some(30)
+a.takeWhile(_ < 30) // List(10, 20)
+```
+{% endtab %}
+
+{% endtabs %}
+
+It’s important to note that HOFs also accept methods and functions as parameters---not just lambda expressions.
+Here are some examples of the `map` HOF that uses a method named `double`.
+Several variations of the lambda syntax are shown again:
+
+{% tabs method-as-parameter-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+def double(i: Int) = i * 2
+
+// these all return `List(20, 40, 60, 80, 20)`
+a.map(i => double(i))
+a.map(double(_))
+a.map(double)
+```
+{% endtab %}
+
+{% endtabs %}
+
+In the last example, when an anonymous function consists of one function call that takes a single argument, you don’t have to name the argument, so even `_` isn’t required.
+
+Finally, you can combine HOFs as desired to solve problems:
+
+{% tabs higher-order-functions-combination-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+// yields `List(100, 200)`
+a.filter(_ < 40)
+ .takeWhile(_ < 30)
+ .map(_ * 10)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+
+## Sample data
+
+The examples in the following sections use these lists:
+
+{% tabs sample-data %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val oneToTen = (1 to 10).toList
+val names = List("adam", "brandy", "chris", "david")
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+
+## `map`
+
+The `map` method steps through each element in the existing list, applying the function you supply to each element, one at a time;
+it then returns a new list with all of the modified elements.
+
+Here’s an example of the `map` method being applied to the `oneToTen` list:
+
+{% tabs map-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> val doubles = oneToTen.map(_ * 2)
+doubles: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
+```
+{% endtab %}
+
+{% endtabs %}
+
+You can also write anonymous functions using a long form, like this:
+
+{% tabs map-example-anonymous %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> val doubles = oneToTen.map(i => i * 2)
+doubles: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
+```
+{% endtab %}
+
+{% endtabs %}
+
+However, in this lesson we’ll always use the first, shorter form.
+
+Here are a few more examples of the `map` method being applied to the `oneToTen` and `names` lists:
+
+{% tabs few-more-examples %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> val capNames = names.map(_.capitalize)
+capNames: List[String] = List(Adam, Brandy, Chris, David)
+
+scala> val nameLengthsMap = names.map(s => (s, s.length)).toMap
+nameLengthsMap: Map[String, Int] = Map(adam -> 4, brandy -> 6, chris -> 5, david -> 5)
+
+scala> val isLessThanFive = oneToTen.map(_ < 5)
+isLessThanFive: List[Boolean] = List(true, true, true, true, false, false, false, false, false, false)
+```
+{% endtab %}
+
+{% endtabs %}
+
+As shown in the last two examples, it’s perfectly legal (and common) to use `map` to return a collection that has a different type than the original type.
+
+
+
+## `filter`
+
+The `filter` method creates a new list containing the element that satisfy the provided predicate.
+A predicate, or condition, is a function that returns a `Boolean` (`true` or `false`).
+Here are a few examples:
+
+{% tabs filter-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> val lessThanFive = oneToTen.filter(_ < 5)
+lessThanFive: List[Int] = List(1, 2, 3, 4)
+
+scala> val evens = oneToTen.filter(_ % 2 == 0)
+evens: List[Int] = List(2, 4, 6, 8, 10)
+
+scala> val shortNames = names.filter(_.length <= 4)
+shortNames: List[String] = List(adam)
+```
+{% endtab %}
+
+{% endtabs %}
+
+A great thing about the functional methods on collections is that you can chain them together to solve problems.
+For instance, this example shows how to chain `filter` and `map`:
+
+{% tabs filter-example-anonymous %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+oneToTen.filter(_ < 4).map(_ * 10)
+```
+{% endtab %}
+
+{% endtabs %}
+
+The REPL shows the result:
+
+{% tabs filter-example-anonymous-repl %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> oneToTen.filter(_ < 4).map(_ * 10)
+val res1: List[Int] = List(10, 20, 30)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+
+## `foreach`
+
+The `foreach` method is used to loop over all elements in a collection.
+Note that `foreach` is used for side-effects, such as printing information.
+Here’s an example with the `names` list:
+
+{% tabs foreach-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> names.foreach(println)
+adam
+brandy
+chris
+david
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+
+## `head`
+
+The `head` method comes from Lisp and other earlier functional programming languages.
+It’s used to access the first element (the head element) of a list:
+
+{% tabs head-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+oneToTen.head // 1
+names.head // adam
+```
+{% endtab %}
+
+{% endtabs %}
+
+Because a `String` can be seen as a sequence of characters, you can also treat it like a list.
+This is how `head` works on these strings:
+
+{% tabs string-head-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+"foo".head // 'f'
+"bar".head // 'b'
+```
+{% endtab %}
+
+{% endtabs %}
+
+`head` is a great method to work with, but as a word of caution it can also throw an exception when called on an empty collection:
+
+{% tabs head-error-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val emptyList = List[Int]() // emptyList: List[Int] = List()
+emptyList.head // java.util.NoSuchElementException: head of empty list
+```
+{% endtab %}
+
+{% endtabs %}
+
+Because of this you may want to use `headOption` instead of `head`, especially when programming in a functional style:
+
+{% tabs head-option-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+emptyList.headOption // None
+```
+{% endtab %}
+
+{% endtabs %}
+
+As shown, it doesn't throw an exception, it simply returns the type `Option` that has the value `None`.
+You can learn more about this programming style in the [Functional Programming][fp-intro] chapter.
+
+
+
+## `tail`
+
+The `tail` method also comes from Lisp, and it’s used to print every element in a list after the head element.
+A few examples demonstrate this:
+
+{% tabs tail-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+oneToTen.head // 1
+oneToTen.tail // List(2, 3, 4, 5, 6, 7, 8, 9, 10)
+
+names.head // adam
+names.tail // List(brandy, chris, david)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Just like `head`, `tail` also works on strings:
+
+{% tabs string-tail-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+"foo".tail // "oo"
+"bar".tail // "ar"
+```
+{% endtab %}
+
+{% endtabs %}
+
+`tail` throws a _java.lang.UnsupportedOperationException_ if the list is empty, so just like `head` and `headOption`, there’s also a `tailOption` method, which is preferred in functional programming.
+
+A list can also be matched, so you can write expressions like this:
+
+{% tabs tail-match-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val x :: xs = names
+```
+{% endtab %}
+
+{% endtabs %}
+
+Putting that code in the REPL shows that `x` is assigned to the head of the list, and `xs` is assigned to the tail:
+
+{% tabs tail-match-example-repl %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> val x :: xs = names
+val x: String = adam
+val xs: List[String] = List(brandy, chris, david)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Pattern matching like this is useful in many situations, such as writing a `sum` method using recursion:
+
+{% tabs tail-match-sum-example class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+def sum(list: List[Int]): Int = list match {
+ case Nil => 0
+ case x :: xs => x + sum(xs)
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+def sum(list: List[Int]): Int = list match
+ case Nil => 0
+ case x :: xs => x + sum(xs)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+
+## `take`, `takeRight`, `takeWhile`
+
+The `take`, `takeRight`, and `takeWhile` methods give you a nice way of “taking” the elements from a list that you want to use to create a new list.
+This is `take` and `takeRight`:
+
+{% tabs take-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+oneToTen.take(1) // List(1)
+oneToTen.take(2) // List(1, 2)
+
+oneToTen.takeRight(1) // List(10)
+oneToTen.takeRight(2) // List(9, 10)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Notice how these methods work with “edge” cases, where we ask for more elements than are in the sequence, or ask for zero elements:
+
+{% tabs take-edge-cases-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+oneToTen.take(Int.MaxValue) // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+oneToTen.takeRight(Int.MaxValue) // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+oneToTen.take(0) // List()
+oneToTen.takeRight(0) // List()
+```
+{% endtab %}
+
+{% endtabs %}
+
+And this is `takeWhile`, which works with a predicate function:
+
+{% tabs take-while-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+oneToTen.takeWhile(_ < 5) // List(1, 2, 3, 4)
+names.takeWhile(_.length < 5) // List(adam)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+## `drop`, `dropRight`, `dropWhile`
+
+`drop`, `dropRight`, and `dropWhile` are essentially the opposite of their “take” counterparts, dropping elements from a list.
+Here are some examples:
+
+{% tabs drop-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+oneToTen.drop(1) // List(2, 3, 4, 5, 6, 7, 8, 9, 10)
+oneToTen.drop(5) // List(6, 7, 8, 9, 10)
+
+oneToTen.dropRight(8) // List(1, 2)
+oneToTen.dropRight(7) // List(1, 2, 3)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Again notice how these methods work with edge cases:
+
+{% tabs drop-edge-cases-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+oneToTen.drop(Int.MaxValue) // List()
+oneToTen.dropRight(Int.MaxValue) // List()
+oneToTen.drop(0) // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+oneToTen.dropRight(0) // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+```
+{% endtab %}
+
+{% endtabs %}
+
+And this is `dropWhile`, which works with a predicate function:
+
+{% tabs drop-while-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+oneToTen.dropWhile(_ < 5) // List(5, 6, 7, 8, 9, 10)
+names.dropWhile(_ != "chris") // List(chris, david)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+
+## `reduce`
+
+When you hear the term, “map reduce,” the “reduce” part refers to methods like `reduce`.
+It takes a function (or anonymous function) and applies that function to successive elements in the list.
+
+The best way to explain `reduce` is to create a little helper method you can pass into it.
+For example, this is an `add` method that adds two integers together, and also provides us some nice debug output:
+
+{% tabs reduce-example class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+def add(x: Int, y: Int): Int = {
+ val theSum = x + y
+ println(s"received $x and $y, their sum is $theSum")
+ theSum
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+def add(x: Int, y: Int): Int =
+ val theSum = x + y
+ println(s"received $x and $y, their sum is $theSum")
+ theSum
+```
+{% endtab %}
+
+{% endtabs %}
+
+Given that method and this list:
+
+{% tabs reduce-example-init %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = List(1,2,3,4)
+```
+{% endtab %}
+
+{% endtabs %}
+
+this is what happens when you pass the `add` method into `reduce`:
+
+{% tabs reduce-example-evaluation %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> a.reduce(add)
+received 1 and 2, their sum is 3
+received 3 and 3, their sum is 6
+received 6 and 4, their sum is 10
+res0: Int = 10
+```
+{% endtab %}
+
+{% endtabs %}
+
+As that result shows, `reduce` uses `add` to reduce the list `a` into a single value, in this case, the sum of the integers in the list.
+
+Once you get used to `reduce`, you’ll write a “sum” algorithm like this:
+
+{% tabs reduce-example-sum %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> a.reduce(_ + _)
+res0: Int = 10
+```
+{% endtab %}
+
+{% endtabs %}
+
+Similarly, a “product” algorithm looks like this:
+
+{% tabs reduce-example-multiply %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> a.reduce(_ * _)
+res1: Int = 24
+```
+{% endtab %}
+
+{% endtabs %}
+
+> An important concept to know about `reduce` is that---as its name implies---it’s used to _reduce_ a collection down to a single value.
+
+
+
+## Even more
+
+There are literally dozens of additional methods on the Scala collections types that will keep you from ever needing to write another `for` loop. See [Mutable and Immutable Collections][mut-immut-colls] and [The Architecture of Scala Collections][architecture] for many more details on the Scala collections.
+
+> As a final note, if you’re using Java code in a Scala project, you can convert Java collections to Scala collections.
+> By doing this you can use those collections in `for` expressions, and can also take advantage of Scala’s functional collections methods.
+> See the [Interacting with Java][interacting] section for more details.
+
+
+
+[interacting]: {% link _overviews/scala3-book/interacting-with-java.md %}
+[lambdas]: {% link _overviews/scala3-book/fun-anonymous-functions.md %}
+[fp-intro]: {% link _overviews/scala3-book/fp-intro.md %}
+[mut-immut-colls]: {% link _overviews/collections-2.13/overview.md %}
+[architecture]: {% link _overviews/core/architecture-of-scala-213-collections.md %}
+
diff --git a/_overviews/scala3-book/collections-summary.md b/_overviews/scala3-book/collections-summary.md
new file mode 100644
index 0000000000..4a7aa1c385
--- /dev/null
+++ b/_overviews/scala3-book/collections-summary.md
@@ -0,0 +1,31 @@
+---
+title: Summary
+type: section
+description: This page provides a summary of the Collections chapter.
+languages: [ru, zh-cn]
+num: 41
+previous-page: collections-methods
+next-page: fp-intro
+---
+
+This chapter provides a summary of the common Scala 3 collections and their accompanying methods.
+As shown, Scala comes with a wealth of collections and methods.
+
+When you need to see more details about the collections types shown in this chapter, see their Scaladoc pages:
+
+- [List](https://www.scala-lang.org/api/current/scala/collection/immutable/List.html)
+- [Vector](https://www.scala-lang.org/api/current/scala/collection/immutable/Vector.html)
+- [ArrayBuffer](https://www.scala-lang.org/api/current/scala/collection/mutable/ArrayBuffer.html)
+- [Range](https://www.scala-lang.org/api/current/scala/collection/immutable/Range.html)
+
+Also mentioned are the immutable `Map` and `Set`:
+
+- [Map](https://www.scala-lang.org/api/current/scala/collection/immutable/Map.html)
+- [Set](https://www.scala-lang.org/api/current/scala/collection/immutable/Set.html)
+
+and the mutable `Map` and `Set`:
+
+- [Map](https://www.scala-lang.org/api/current/scala/collection/mutable/Map.html)
+- [Set](https://www.scala-lang.org/api/current/scala/collection/mutable/Set.html)
+
+
diff --git a/_overviews/scala3-book/concurrency.md b/_overviews/scala3-book/concurrency.md
new file mode 100644
index 0000000000..4364239bd8
--- /dev/null
+++ b/_overviews/scala3-book/concurrency.md
@@ -0,0 +1,325 @@
+---
+title: Concurrency
+type: chapter
+description: This page discusses how Scala concurrency works, with an emphasis on Scala Futures.
+languages: [ru, zh-cn]
+num: 69
+previous-page: ca-summary
+next-page: scala-tools
+---
+
+
+When you want to write parallel and concurrent applications in Scala, you _can_ use the native Java `Thread`---but the Scala [Future](https://www.scala-lang.org/api/current/scala/concurrent/Future$.html) offers a more high level and idiomatic approach, so it’s preferred, and covered in this chapter.
+
+
+
+## Introduction
+
+Here’s a description of the Scala `Future` from its Scaladoc:
+
+> “A `Future` represents a value which may or may not _currently_ be available, but will be available at some point, or an exception if that value could not be made available.”
+
+To demonstrate what that means, let’s first look at single-threaded programming.
+In the single-threaded world you bind the result of a method call to a variable like this:
+
+```scala
+def aShortRunningTask(): Int = 42
+val x = aShortRunningTask()
+```
+
+In this code, the value `42` is immediately bound to `x`.
+
+When you’re working with a `Future`, the assignment process looks similar:
+
+```scala
+def aLongRunningTask(): Future[Int] = ???
+val x = aLongRunningTask()
+```
+
+But the main difference in this case is that because `aLongRunningTask` takes an indeterminate amount of time to return, the value in `x` may or may not be _currently_ available, but it will be available at some point---in the future.
+
+Another way to look at this is in terms of blocking.
+In this single-threaded example, the `println` statement isn’t printed until `aShortRunningTask` completes:
+
+```scala
+def aShortRunningTask(): Int =
+ Thread.sleep(500)
+ 42
+val x = aShortRunningTask()
+println("Here")
+```
+
+Conversely, if `aShortRunningTask` is created as a `Future`, the `println` statement is printed almost immediately because `aShortRunningTask` is spawned off on some other thread---it doesn't block.
+
+In this chapter you’ll see how to use futures, including how to run multiple futures in parallel and combine their results in a `for` expression.
+You’ll also see examples of methods that are used to handle the value in a future once it returns.
+
+> When you think about futures, it’s important to know that they’re intended as a one-shot, “Handle this relatively slow computation on some other thread, and call me back with a result when you’re done” construct.
+> As a point of contrast, [Akka](https://akka.io) actors are intended to run for a long time and respond to many requests during their lifetime.
+> While an actor may live forever, a future eventually contains the result
+> of a computation that ran only once.
+
+
+
+## An example in the REPL
+
+A future is used to create a temporary pocket of concurrency.
+For instance, you use a future when you need to call an algorithm that runs an indeterminate amount of time---such as calling a remote microservice---so you want to run it off of the main thread.
+
+To demonstrate how this works, let’s start with a `Future` example in the REPL.
+First, paste in these required `import` statements:
+
+```scala
+import scala.concurrent.Future
+import scala.concurrent.ExecutionContext.Implicits.global
+import scala.util.{Failure, Success}
+```
+
+Now you’re ready to create a future.
+For this example, first define a long-running, single-threaded algorithm:
+
+```scala
+def longRunningAlgorithm() =
+ Thread.sleep(10_000)
+ 42
+```
+
+That fancy algorithm returns the integer value `42` after a ten-second delay.
+Now call that algorithm by wrapping it into the `Future` constructor, and assigning the result to a variable:
+
+```scala
+scala> val eventualInt = Future(longRunningAlgorithm())
+eventualInt: scala.concurrent.Future[Int] = Future()
+```
+
+Right away, your computation---the call to `longRunningAlgorithm()`---begins running.
+If you immediately check the value of the variable `eventualInt`, you see that the future hasn't been completed yet:
+
+```scala
+scala> eventualInt
+val res1: scala.concurrent.Future[Int] = Future()
+```
+
+But if you check again after ten seconds, you’ll see that it is completed successfully:
+
+```scala
+scala> eventualInt
+val res2: scala.concurrent.Future[Int] = Future(Success(42))
+```
+
+While that’s a relatively simple example, it shows the basic approach: Just construct a new `Future` with your long-running algorithm.
+
+One thing to notice is that the `42` you expected is wrapped in a `Success`, which is further wrapped in a `Future`.
+This is a key concept to understand: the value in a `Future` is always an instance of one of the `scala.util.Try` types: `Success` or `Failure`.
+Therefore, when you work with the result of a future, you use the usual `Try`-handling techniques.
+
+
+### Using `map` with futures
+
+`Future` has a `map` method, which you use just like the `map` method on collections.
+This is what the result looks like when you call `map` right after creating the variable `a`:
+
+```scala
+scala> val a = Future(longRunningAlgorithm()).map(_ * 2)
+a: scala.concurrent.Future[Int] = Future()
+```
+
+As shown, for the future that was created with the `longRunningAlgorithm`, the initial output shows `Future()`.
+But when you check `a`’s value after ten seconds you’ll see that it contains the expected result of `84`:
+
+```scala
+scala> a
+res1: scala.concurrent.Future[Int] = Future(Success(84))
+```
+
+Once again, the successful result is wrapped inside a `Success` and a `Future`.
+
+
+### Using callback methods with futures
+
+In addition to higher-order functions like `map`, you can also use callback methods with futures.
+One commonly used callback method is `onComplete`, which takes a *partial function* in which you handle the `Success` and `Failure` cases:
+
+```scala
+Future(longRunningAlgorithm()).onComplete {
+ case Success(value) => println(s"Got the callback, value = $value")
+ case Failure(e) => e.printStackTrace
+}
+```
+
+When you paste that code in the REPL you’ll eventually see the result:
+
+```scala
+Got the callback, value = 42
+```
+
+
+
+## Other Future methods
+
+The `Future` class has other methods you can use.
+It has some methods that you find on Scala collections classes, including:
+
+- `filter`
+- `flatMap`
+- `map`
+
+Its callback methods are:
+
+- `onComplete`
+- `andThen`
+- `foreach`
+
+Other transformation methods include:
+
+- `fallbackTo`
+- `recover`
+- `recoverWith`
+
+See the [Futures and Promises][futures] page for a discussion of additional methods available to futures.
+
+
+
+## Running multiple futures and joining their results
+
+To run multiple computations in parallel and join their results when all of the futures have been completed, use a `for` expression.
+
+The correct approach is:
+
+1. Start the computations that return `Future` results
+2. Merge their results in a `for` expression
+3. Extract the merged result using `onComplete` or a similar technique
+
+
+### An example
+
+The three steps of the correct approach are shown in the following example.
+A key is that you first start the computations that return futures, and then join them in the `for` expression:
+
+```scala
+import scala.concurrent.Future
+import scala.concurrent.ExecutionContext.Implicits.global
+import scala.util.{Failure, Success}
+
+val startTime = System.currentTimeMillis()
+def delta() = System.currentTimeMillis() - startTime
+def sleep(millis: Long) = Thread.sleep(millis)
+
+@main def multipleFutures1 =
+
+ println(s"creating the futures: ${delta()}")
+
+ // (1) start the computations that return futures
+ val f1 = Future { sleep(800); 1 } // eventually returns 1
+ val f2 = Future { sleep(200); 2 } // eventually returns 2
+ val f3 = Future { sleep(400); 3 } // eventually returns 3
+
+ // (2) join the futures in a `for` expression
+ val result =
+ for
+ r1 <- f1
+ r2 <- f2
+ r3 <- f3
+ yield
+ println(s"in the 'yield': ${delta()}")
+ (r1 + r2 + r3)
+
+ // (3) process the result
+ result.onComplete {
+ case Success(x) =>
+ println(s"in the Success case: ${delta()}")
+ println(s"result = $x")
+ case Failure(e) =>
+ e.printStackTrace
+ }
+
+ println(s"before the 'sleep(3000)': ${delta()}")
+
+ // important for a little parallel demo: keep the jvm alive
+ sleep(3000)
+```
+
+When you run that application, you see output that looks like this:
+
+````
+creating the futures: 1
+before the 'sleep(3000)': 2
+in the 'yield': 806
+in the Success case: 806
+result = 6
+````
+
+As that output shows, the futures are created very rapidly, and in just two milliseconds the print statement right before the `sleep(3000)` statement at the end of the method is reached.
+All of that code is run on the JVM’s main thread.
+Then, at 806 ms, the three futures complete and the code in the `yield` block is run.
+Then the code immediately goes to the `Success` case in the `onComplete` method.
+
+The 806 ms output is a key to seeing that the three computations are run in parallel.
+If they were run sequentially, the total time would be about 1,400 ms---the sum of the sleep times of the three computations.
+But because they’re run in parallel, the total time is just slightly longer than the longest-running computation: `f1`, which is 800 ms.
+
+> Notice that if the computations were run within the `for` expression, they
+> would be executed sequentially, not in parallel:
+> ~~~
+> // Sequential execution (no parallelism!)
+> for
+> r1 <- Future { sleep(800); 1 }
+> r2 <- Future { sleep(200); 2 }
+> r3 <- Future { sleep(400); 3 }
+> yield
+> r1 + r2 + r3
+> ~~~
+> So, if you want the computations to be possibly run in parallel, remember
+> to run them outside the `for` expression.
+
+### A method that returns a future
+
+So far you’ve seen how to pass a single-threaded algorithm into a `Future` constructor.
+You can use the same technique to create a method that returns a `Future`:
+
+```scala
+// simulate a slow-running method
+def slowlyDouble(x: Int, delay: Long): Future[Int] = Future {
+ sleep(delay)
+ x * 2
+}
+```
+
+As with the previous examples, just assign the result of the method call to a new variable.
+Then when you check the result right away you’ll see that it’s not completed, but after the delay time the future will have a result:
+
+````
+scala> val f = slowlyDouble(2, 5_000L)
+val f: concurrent.Future[Int] = Future()
+
+scala> f
+val res0: concurrent.Future[Int] = Future()
+
+scala> f
+val res1: concurrent.Future[Int] = Future(Success(4))
+````
+
+
+
+## Key points about futures
+
+Hopefully those examples give you an idea of how Scala futures work.
+To summarize, a few key points about futures are:
+
+- You construct futures to run tasks off of the main thread
+- Futures are intended for one-shot, potentially long-running concurrent tasks that *eventually* return a value; they create a temporary pocket of concurrency
+- A future starts running as soon as you construct it
+- A benefit of futures over threads is that they work with `for` expressions, and come with a variety of callback methods that simplify the process of working with concurrent threads
+- When you work with futures you don’t have to concern yourself with the low-level details of thread management
+- You handle the result of a future with callback methods like `onComplete` and `andThen`, or transformation methods like `filter`, `map`, etc.
+- The value inside a `Future` is always an instance of one of the `Try` types: `Success` or `Failure`
+- If you’re using multiple futures to yield a single result, combine them in a `for` expression
+
+Also, as you saw with the `import` statements in these examples, the Scala `Future` depends on an `ExecutionContext`.
+
+For more details about futures, see [Futures and Promises][futures], an article that discusses futures, promises, and execution contexts.
+It also provides a discussion of how a `for` expression is translated into a `flatMap` operation.
+
+
+
+[futures]: {% link _overviews/core/futures.md %}
diff --git a/_overviews/scala3-book/control-structures.md b/_overviews/scala3-book/control-structures.md
new file mode 100644
index 0000000000..9d44db59cb
--- /dev/null
+++ b/_overviews/scala3-book/control-structures.md
@@ -0,0 +1,1097 @@
+---
+title: Control Structures
+type: chapter
+description: This page provides an introduction to Scala's control structures, including if/then/else, 'for' loops, 'for' expressions, 'match' expressions, try/catch/finally, and 'while' loops.
+languages: [ru, zh-cn]
+num: 19
+previous-page: string-interpolation
+next-page: domain-modeling-intro
+---
+
+
+Scala has the control structures you expect to find in a programming language, including:
+
+- `if`/`then`/`else`
+- `for` loops
+- `while` loops
+- `try`/`catch`/`finally`
+
+It also has two other powerful constructs that you may not have seen before, depending on your programming background:
+
+- `for` expressions (also known as _`for` comprehensions_)
+- `match` expressions
+
+These are all demonstrated in the following sections.
+
+## The if/then/else construct
+
+A one-line Scala `if` statement looks like this:
+
+{% tabs control-structures-1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-1 %}
+```scala
+if (x == 1) println(x)
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-1 %}
+```scala
+if x == 1 then println(x)
+```
+{% endtab %}
+{% endtabs %}
+
+When you need to run multiple lines of code after an `if` equality comparison, use this syntax:
+
+{% tabs control-structures-2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-2 %}
+```scala
+if (x == 1) {
+ println("x is 1, as you can see:")
+ println(x)
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-2 %}
+```scala
+if x == 1 then
+ println("x is 1, as you can see:")
+ println(x)
+```
+{% endtab %}
+{% endtabs %}
+
+The `if`/`else` syntax looks like this:
+
+{% tabs control-structures-3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-3 %}
+```scala
+if (x == 1) {
+ println("x is 1, as you can see:")
+ println(x)
+} else {
+ println("x was not 1")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-3 %}
+```scala
+if x == 1 then
+ println("x is 1, as you can see:")
+ println(x)
+else
+ println("x was not 1")
+```
+{% endtab %}
+{% endtabs %}
+
+And this is the `if`/`else if`/`else` syntax:
+
+{% tabs control-structures-4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-4 %}
+```scala
+if (x < 0)
+ println("negative")
+else if (x == 0)
+ println("zero")
+else
+ println("positive")
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-4 %}
+```scala
+if x < 0 then
+ println("negative")
+else if x == 0 then
+ println("zero")
+else
+ println("positive")
+```
+{% endtab %}
+{% endtabs %}
+
+### `end if` statement
+
+
+ This is new in Scala 3, and not supported in Scala 2.
+
+
+You can optionally include an `end if` statement at the end of each expression, if you prefer:
+
+{% tabs control-structures-5 %}
+{% tab 'Scala 3 Only' %}
+
+```scala
+if x == 1 then
+ println("x is 1, as you can see:")
+ println(x)
+end if
+```
+
+{% endtab %}
+{% endtabs %}
+
+### `if`/`else` expressions always return a result
+
+Note that `if`/`else` comparisons form _expressions_, meaning that they return a value which you can assign to a variable.
+Because of this, there’s no need for a special ternary operator:
+
+{% tabs control-structures-6 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-6 %}
+```scala
+val minValue = if (a < b) a else b
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-6 %}
+```scala
+val minValue = if a < b then a else b
+```
+{% endtab %}
+{% endtabs %}
+
+Because they return a value, you can use `if`/`else` expressions as the body of a method:
+
+{% tabs control-structures-7 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-7 %}
+```scala
+def compare(a: Int, b: Int): Int =
+ if (a < b)
+ -1
+ else if (a == b)
+ 0
+ else
+ 1
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-7 %}
+```scala
+def compare(a: Int, b: Int): Int =
+ if a < b then
+ -1
+ else if a == b then
+ 0
+ else
+ 1
+```
+{% endtab %}
+{% endtabs %}
+
+### Aside: Expression-oriented programming
+
+As a brief note about programming in general, when every expression you write returns a value, that style is referred to as _expression-oriented programming_, or EOP.
+For example, this is an _expression_:
+
+{% tabs control-structures-8 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-8 %}
+```scala
+val minValue = if (a < b) a else b
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-8 %}
+```scala
+val minValue = if a < b then a else b
+```
+{% endtab %}
+{% endtabs %}
+
+Conversely, lines of code that don’t return values are called _statements_, and they’re used for their _side-effects_.
+For example, these lines of code don’t return values, so they’re used for their side effects:
+
+{% tabs control-structures-9 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-9 %}
+```scala
+if (a == b) action()
+println("Hello")
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-9 %}
+```scala
+if a == b then action()
+println("Hello")
+```
+{% endtab %}
+{% endtabs %}
+
+The first example runs the `action` method as a side effect when `a` is equal to `b`.
+The second example is used for the side effect of printing a string to STDOUT.
+As you learn more about Scala you’ll find yourself writing more _expressions_ and fewer _statements_.
+
+## `for` loops
+
+In its most simple use, a Scala `for` loop can be used to iterate over the elements in a collection.
+For example, given a sequence of integers, you can loop over its elements and print their values like this:
+
+{% tabs control-structures-10 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-10 %}
+```scala
+val ints = Seq(1, 2, 3)
+for (i <- ints) println(i)
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-10 %}
+```scala
+val ints = Seq(1, 2, 3)
+for i <- ints do println(i)
+```
+{% endtab %}
+{% endtabs %}
+
+
+The code `i <- ints` is referred to as a _generator_. In any generator `p <- e`, the expression `e` can generate zero or many bindings to the pattern `p`.
+
+This is what the result looks like in the Scala REPL:
+
+{% tabs control-structures-11 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-11 %}
+````
+scala> val ints = Seq(1,2,3)
+ints: Seq[Int] = List(1, 2, 3)
+
+scala> for (i <- ints) println(i)
+1
+2
+3
+````
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-11 %}
+````
+scala> val ints = Seq(1,2,3)
+ints: Seq[Int] = List(1, 2, 3)
+
+scala> for i <- ints do println(i)
+1
+2
+3
+````
+{% endtab %}
+{% endtabs %}
+
+
+When you need a multiline block of code following the `for` generator, use the following syntax:
+
+{% tabs control-structures-12 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-12 %}
+```scala
+for (i <- ints) {
+ val x = i * 2
+ println(s"i = $i, x = $x")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-12 %}
+```scala
+for i <- ints
+do
+ val x = i * 2
+ println(s"i = $i, x = $x")
+```
+{% endtab %}
+{% endtabs %}
+
+
+### Multiple generators
+
+`for` loops can have multiple generators, as shown in this example:
+
+{% tabs control-structures-13 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-13 %}
+```scala
+for {
+ i <- 1 to 2
+ j <- 'a' to 'b'
+ k <- 1 to 10 by 5
+} {
+ println(s"i = $i, j = $j, k = $k")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-13 %}
+```scala
+for
+ i <- 1 to 2
+ j <- 'a' to 'b'
+ k <- 1 to 10 by 5
+do
+ println(s"i = $i, j = $j, k = $k")
+```
+{% endtab %}
+{% endtabs %}
+
+
+That expression prints this output:
+
+````
+i = 1, j = a, k = 1
+i = 1, j = a, k = 6
+i = 1, j = b, k = 1
+i = 1, j = b, k = 6
+i = 2, j = a, k = 1
+i = 2, j = a, k = 6
+i = 2, j = b, k = 1
+i = 2, j = b, k = 6
+````
+
+### Guards
+
+`for` loops can also contain `if` statements, which are known as _guards_:
+
+{% tabs control-structures-14 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-14 %}
+```scala
+for {
+ i <- 1 to 5
+ if i % 2 == 0
+} {
+ println(i)
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-14 %}
+```scala
+for
+ i <- 1 to 5
+ if i % 2 == 0
+do
+ println(i)
+```
+{% endtab %}
+{% endtabs %}
+
+
+The output of that loop is:
+
+````
+2
+4
+````
+
+A `for` loop can have as many guards as needed.
+This example shows one way to print the number `4`:
+
+{% tabs control-structures-15 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-15 %}
+```scala
+for {
+ i <- 1 to 10
+ if i > 3
+ if i < 6
+ if i % 2 == 0
+} {
+ println(i)
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-15 %}
+```scala
+for
+ i <- 1 to 10
+ if i > 3
+ if i < 6
+ if i % 2 == 0
+do
+ println(i)
+```
+{% endtab %}
+{% endtabs %}
+
+### Using `for` with Maps
+
+You can also use `for` loops with a `Map`.
+For example, given this `Map` of state abbreviations and their full names:
+
+{% tabs map %}
+{% tab 'Scala 2 and 3' for=map %}
+```scala
+val states = Map(
+ "AK" -> "Alaska",
+ "AL" -> "Alabama",
+ "AR" -> "Arizona"
+)
+```
+{% endtab %}
+{% endtabs %}
+
+You can print the keys and values using `for`, like this:
+
+{% tabs control-structures-16 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-16 %}
+```scala
+for ((abbrev, fullName) <- states) println(s"$abbrev: $fullName")
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-16 %}
+```scala
+for (abbrev, fullName) <- states do println(s"$abbrev: $fullName")
+```
+{% endtab %}
+{% endtabs %}
+
+Here’s what that looks like in the REPL:
+
+{% tabs control-structures-17 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-17 %}
+```scala
+scala> for ((abbrev, fullName) <- states) println(s"$abbrev: $fullName")
+AK: Alaska
+AL: Alabama
+AR: Arizona
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-17 %}
+```scala
+scala> for (abbrev, fullName) <- states do println(s"$abbrev: $fullName")
+AK: Alaska
+AL: Alabama
+AR: Arizona
+```
+{% endtab %}
+{% endtabs %}
+
+As the `for` loop iterates over the map, each key/value pair is bound to the variables `abbrev` and `fullName`, which are in a tuple:
+
+```scala
+(abbrev, fullName) <- states
+```
+
+As the loop runs, the variable `abbrev` is assigned to the current _key_ in the map, and the variable `fullName` is assigned to the current map _value_.
+
+## `for` expressions
+
+In the previous `for` loop examples, those loops were all used for _side effects_, specifically to print those values to STDOUT using `println`.
+
+It’s important to know that you can also create `for` _expressions_ that return values.
+You create a `for` expression by adding the `yield` keyword and an expression to return, like this:
+
+{% tabs control-structures-18 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-18 %}
+```scala
+val list =
+ for (i <- 10 to 12)
+ yield i * 2
+
+// list: IndexedSeq[Int] = Vector(20, 22, 24)
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-18 %}
+```scala
+val list =
+ for i <- 10 to 12
+ yield i * 2
+
+// list: IndexedSeq[Int] = Vector(20, 22, 24)
+```
+{% endtab %}
+{% endtabs %}
+
+
+After that `for` expression runs, the variable `list` is a `Vector` that contains the values shown.
+This is how the expression works:
+
+1. The `for` expression starts to iterate over the values in the range `(10, 11, 12)`.
+ It first works on the value `10`, multiplies it by `2`, then _yields_ that result, the value `20`.
+2. Next, it works on the `11`---the second value in the range.
+ It multiplies it by `2`, then yields the value `22`.
+ You can think of these yielded values as accumulating in a temporary holding place.
+3. Finally, the loop gets the number `12` from the range, multiplies it by `2`, yielding the number `24`.
+ The loop completes at this point and yields the final result, the `Vector(20, 22, 24)`.
+
+{% comment %}
+NOTE: This is a place where it would be great to have a TIP or NOTE block:
+{% endcomment %}
+
+While the intent of this section is to demonstrate `for` expressions, it can help to know that the `for` expression shown is equivalent to this `map` method call:
+
+{% tabs map-call %}
+{% tab 'Scala 2 and 3' for=map-call %}
+```scala
+val list = (10 to 12).map(i => i * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+`for` expressions can be used any time you need to traverse all the elements in a collection and apply an algorithm to those elements to create a new list.
+
+Here’s an example that shows how to use a block of code after the `yield`:
+
+{% tabs control-structures-19 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-19 %}
+```scala
+val names = List("_olivia", "_walter", "_peter")
+
+val capNames = for (name <- names) yield {
+ val nameWithoutUnderscore = name.drop(1)
+ val capName = nameWithoutUnderscore.capitalize
+ capName
+}
+
+// capNames: List[String] = List(Olivia, Walter, Peter)
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-19 %}
+```scala
+val names = List("_olivia", "_walter", "_peter")
+
+val capNames = for name <- names yield
+ val nameWithoutUnderscore = name.drop(1)
+ val capName = nameWithoutUnderscore.capitalize
+ capName
+
+// capNames: List[String] = List(Olivia, Walter, Peter)
+```
+{% endtab %}
+{% endtabs %}
+
+### Using a `for` expression as the body of a method
+
+Because a `for` expression yields a result, it can be used as the body of a method that returns a useful value.
+This method returns all the values in a given list of integers that are between `3` and `10`:
+
+{% tabs control-structures-20 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-20 %}
+```scala
+def between3and10(xs: List[Int]): List[Int] =
+ for {
+ x <- xs
+ if x >= 3
+ if x <= 10
+ } yield x
+
+between3and10(List(1, 3, 7, 11)) // : List[Int] = List(3, 7)
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-20 %}
+```scala
+def between3and10(xs: List[Int]): List[Int] =
+ for
+ x <- xs
+ if x >= 3
+ if x <= 10
+ yield x
+
+between3and10(List(1, 3, 7, 11)) // : List[Int] = List(3, 7)
+```
+{% endtab %}
+{% endtabs %}
+
+## `while` loops
+
+Scala `while` loop syntax looks like this:
+
+{% tabs control-structures-21 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-21 %}
+```scala
+var i = 0
+
+while (i < 3) {
+ println(i)
+ i += 1
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-21 %}
+```scala
+var i = 0
+
+while i < 3 do
+ println(i)
+ i += 1
+```
+{% endtab %}
+{% endtabs %}
+
+## `match` expressions
+
+Pattern matching is a major feature of functional programming languages, and Scala includes a `match` expression that has many capabilities.
+
+In the most simple case you can use a `match` expression like a Java `switch` statement, matching cases based on an integer value.
+Notice that this really is an expression, as it evaluates to a result:
+
+{% tabs control-structures-22 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-22 %}
+```scala
+// `i` is an integer
+val day = i match {
+ case 0 => "Sunday"
+ case 1 => "Monday"
+ case 2 => "Tuesday"
+ case 3 => "Wednesday"
+ case 4 => "Thursday"
+ case 5 => "Friday"
+ case 6 => "Saturday"
+ case _ => "invalid day" // the default, catch-all
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-22 %}
+```scala
+// `i` is an integer
+val day = i match
+ case 0 => "Sunday"
+ case 1 => "Monday"
+ case 2 => "Tuesday"
+ case 3 => "Wednesday"
+ case 4 => "Thursday"
+ case 5 => "Friday"
+ case 6 => "Saturday"
+ case _ => "invalid day" // the default, catch-all
+```
+{% endtab %}
+{% endtabs %}
+
+In this example, the variable `i` is tested against the cases shown.
+If it’s between `0` and `6`, `day` is bound to the string that represents that day of the week.
+Otherwise, it matches the catch-all case represented by the character, `_`, and `day` is bound to the string, `"invalid day"`.
+
+Since the cases are considered in the order they are written, and the first matching case is used, the default case, which matches any value, must come last. Any cases after the catch-all will be warned as unreachable cases.
+
+> When writing simple `match` expressions like this, it’s recommended to use the `@switch` annotation on the variable `i`.
+> This annotation provides a compile-time warning if the switch can’t be compiled to a `tableswitch` or `lookupswitch`, which are better for performance.
+
+### Using the default value
+
+When you need to access the catch-all, default value in a `match` expression, just provide a variable name on the left side of the `case` statement instead of `_`, and then use that variable name on the right side of the statement as needed:
+
+{% tabs control-structures-23 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-23 %}
+```scala
+i match {
+ case 0 => println("1")
+ case 1 => println("2")
+ case what => println(s"You gave me: $what")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-23 %}
+```scala
+i match
+ case 0 => println("1")
+ case 1 => println("2")
+ case what => println(s"You gave me: $what")
+```
+{% endtab %}
+{% endtabs %}
+
+The name used in the pattern must begin with a lowercase letter.
+A name beginning with an uppercase letter does not introduce a variable, but matches a value in scope:
+
+{% tabs control-structures-24 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-24 %}
+```scala
+val N = 42
+i match {
+ case 0 => println("1")
+ case 1 => println("2")
+ case N => println("42")
+ case n => println(s"You gave me: $n" )
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-24 %}
+```scala
+val N = 42
+i match
+ case 0 => println("1")
+ case 1 => println("2")
+ case N => println("42")
+ case n => println(s"You gave me: $n" )
+```
+{% endtab %}
+{% endtabs %}
+
+If `i` is equal to `42`, then `case N` will match, and it will print the string `"42"`. It won't reach the default case.
+
+### Handling multiple possible matches on one line
+
+As mentioned, `match` expressions have many capabilities.
+This example shows how to use multiple possible pattern matches in each `case` statement:
+
+{% tabs control-structures-25 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-25 %}
+```scala
+val evenOrOdd = i match {
+ case 1 | 3 | 5 | 7 | 9 => println("odd")
+ case 2 | 4 | 6 | 8 | 10 => println("even")
+ case _ => println("some other number")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-25 %}
+```scala
+val evenOrOdd = i match
+ case 1 | 3 | 5 | 7 | 9 => println("odd")
+ case 2 | 4 | 6 | 8 | 10 => println("even")
+ case _ => println("some other number")
+```
+{% endtab %}
+{% endtabs %}
+
+### Using `if` guards in `case` clauses
+
+You can also use guards in the `case`s of a match expression.
+In this example the second and third `case` both use guards to match multiple integer values:
+
+{% tabs control-structures-26 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-26 %}
+```scala
+i match {
+ case 1 => println("one, a lonely number")
+ case x if x == 2 || x == 3 => println("two’s company, three’s a crowd")
+ case x if x > 3 => println("4+, that’s a party")
+ case _ => println("i’m guessing your number is zero or less")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-26 %}
+```scala
+i match
+ case 1 => println("one, a lonely number")
+ case x if x == 2 || x == 3 => println("two’s company, three’s a crowd")
+ case x if x > 3 => println("4+, that’s a party")
+ case _ => println("i’m guessing your number is zero or less")
+```
+{% endtab %}
+{% endtabs %}
+
+Here’s another example, which shows how to match a given value against ranges of numbers:
+
+{% tabs control-structures-27 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-27 %}
+```scala
+i match {
+ case a if 0 to 9 contains a => println(s"0-9 range: $a")
+ case b if 10 to 19 contains b => println(s"10-19 range: $b")
+ case c if 20 to 29 contains c => println(s"20-29 range: $c")
+ case _ => println("Hmmm...")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-27 %}
+```scala
+i match
+ case a if 0 to 9 contains a => println(s"0-9 range: $a")
+ case b if 10 to 19 contains b => println(s"10-19 range: $b")
+ case c if 20 to 29 contains c => println(s"20-29 range: $c")
+ case _ => println("Hmmm...")
+```
+{% endtab %}
+{% endtabs %}
+
+#### Case classes and match expressions
+
+You can also extract fields from `case` classes---and classes that have properly written `apply`/`unapply` methods---and use those in your guard conditions.
+Here’s an example using a simple `Person` case class:
+
+{% tabs control-structures-28 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-28 %}
+```scala
+case class Person(name: String)
+
+def speak(p: Person) = p match {
+ case Person(name) if name == "Fred" => println(s"$name says, Yubba dubba doo")
+ case Person(name) if name == "Bam Bam" => println(s"$name says, Bam bam!")
+ case _ => println("Watch the Flintstones!")
+}
+
+speak(Person("Fred")) // "Fred says, Yubba dubba doo"
+speak(Person("Bam Bam")) // "Bam Bam says, Bam bam!"
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-28 %}
+```scala
+case class Person(name: String)
+
+def speak(p: Person) = p match
+ case Person(name) if name == "Fred" => println(s"$name says, Yubba dubba doo")
+ case Person(name) if name == "Bam Bam" => println(s"$name says, Bam bam!")
+ case _ => println("Watch the Flintstones!")
+
+speak(Person("Fred")) // "Fred says, Yubba dubba doo"
+speak(Person("Bam Bam")) // "Bam Bam says, Bam bam!"
+```
+{% endtab %}
+{% endtabs %}
+
+#### Binding matched patterns to variables
+
+You can bind the matched pattern to a variable to use type-specific behavior:
+
+{% tabs pattern-binding class=tabs-scala-version %}
+{% tab 'Scala 2' for=pattern-binding %}
+```scala
+trait Animal {
+ val name: String
+}
+case class Cat(name: String) extends Animal {
+ def meow: String = "Meow"
+}
+case class Dog(name: String) extends Animal {
+ def bark: String = "Bark"
+}
+
+def speak(animal: Animal) = animal match {
+ case c @ Cat(name) if name == "Felix" => println(s"$name says, ${c.meow}!")
+ case d @ Dog(name) if name == "Rex" => println(s"$name says, ${d.bark}!")
+ case _ => println("I don't know you!")
+}
+
+speak(Cat("Felix")) // "Felix says, Meow!"
+speak(Dog("Rex")) // "Rex says, Bark!"
+```
+{% endtab %}
+{% tab 'Scala 3' for=pattern-binding %}
+```scala
+trait Animal:
+ val name: String
+case class Cat(name: String) extends Animal:
+ def meow: String = "Meow"
+case class Dog(name: String) extends Animal:
+ def bark: String = "Bark"
+
+def speak(animal: Animal) = animal match
+ case c @ Cat(name) if name == "Felix" => println(s"$name says, ${c.meow}!")
+ case d @ Dog(name) if name == "Rex" => println(s"$name says, ${d.bark}!")
+ case _ => println("I don't know you!")
+
+speak(Cat("Felix")) // "Felix says, Meow!"
+speak(Dog("Rex")) // "Rex says, Bark!"
+```
+{% endtab %}
+{% endtabs %}
+
+### Using a `match` expression as the body of a method
+
+Because `match` expressions return a value, they can be used as the body of a method.
+This method takes a `Matchable` value as an input parameter, and returns a `Boolean`, based on the result of the `match` expression:
+
+{% tabs control-structures-29 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-29 %}
+```scala
+def isTruthy(a: Matchable) = a match {
+ case 0 | "" | false => false
+ case _ => true
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-29 %}
+```scala
+def isTruthy(a: Matchable) = a match
+ case 0 | "" | false => false
+ case _ => true
+```
+{% endtab %}
+{% endtabs %}
+
+The input parameter `a` is defined to be the [`Matchable` type][matchable]---which is the root of all Scala types that pattern matching can be performed on.
+The method is implemented by matching on the input, providing two cases:
+The first one checks whether the given value is either the integer `0`, an empty string or `false` and returns `false` in this case.
+In the default case, we return `true` for any other value.
+These examples show how this method works:
+
+{% tabs is-truthy-call %}
+{% tab 'Scala 2 and 3' for=is-truthy-call %}
+```scala
+isTruthy(0) // false
+isTruthy(false) // false
+isTruthy("") // false
+isTruthy(1) // true
+isTruthy(" ") // true
+isTruthy(2F) // true
+```
+{% endtab %}
+{% endtabs %}
+
+Using a `match` expression as the body of a method is a very common use.
+
+#### Match expressions support many different types of patterns
+
+There are many different forms of patterns that can be used to write `match` expressions.
+Examples include:
+
+- Constant patterns (such as `case 3 => `)
+- Sequence patterns (such as `case List(els : _*) =>`)
+- Tuple patterns (such as `case (x, y) =>`)
+- Constructor pattern (such as `case Person(first, last) =>`)
+- Type test patterns (such as `case p: Person =>`)
+
+All of these kinds of patterns are shown in the following `pattern` method, which takes an input parameter of type `Matchable` and returns a `String`:
+
+{% tabs control-structures-30 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-30 %}
+```scala
+def pattern(x: Matchable): String = x match {
+
+ // constant patterns
+ case 0 => "zero"
+ case true => "true"
+ case "hello" => "you said 'hello'"
+ case Nil => "an empty List"
+
+ // sequence patterns
+ case List(0, _, _) => "a 3-element list with 0 as the first element"
+ case List(1, _*) => "list, starts with 1, has any number of elements"
+ case Vector(1, _*) => "vector, starts w/ 1, has any number of elements"
+
+ // tuple patterns
+ case (a, b) => s"got $a and $b"
+ case (a, b, c) => s"got $a, $b, and $c"
+
+ // constructor patterns
+ case Person(first, "Alexander") => s"Alexander, first name = $first"
+ case Dog("Zeus") => "found a dog named Zeus"
+
+ // type test patterns
+ case s: String => s"got a string: $s"
+ case i: Int => s"got an int: $i"
+ case f: Float => s"got a float: $f"
+ case a: Array[Int] => s"array of int: ${a.mkString(",")}"
+ case as: Array[String] => s"string array: ${as.mkString(",")}"
+ case d: Dog => s"dog: ${d.name}"
+ case list: List[?] => s"got a List: $list"
+ case m: Map[?, ?] => m.toString
+
+ // the default wildcard pattern
+ case _ => "Unknown"
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-30 %}
+```scala
+def pattern(x: Matchable): String = x match
+
+ // constant patterns
+ case 0 => "zero"
+ case true => "true"
+ case "hello" => "you said 'hello'"
+ case Nil => "an empty List"
+
+ // sequence patterns
+ case List(0, _, _) => "a 3-element list with 0 as the first element"
+ case List(1, _*) => "list, starts with 1, has any number of elements"
+ case Vector(1, _*) => "vector, starts w/ 1, has any number of elements"
+
+ // tuple patterns
+ case (a, b) => s"got $a and $b"
+ case (a, b, c) => s"got $a, $b, and $c"
+
+ // constructor patterns
+ case Person(first, "Alexander") => s"Alexander, first name = $first"
+ case Dog("Zeus") => "found a dog named Zeus"
+
+ // type test patterns
+ case s: String => s"got a string: $s"
+ case i: Int => s"got an int: $i"
+ case f: Float => s"got a float: $f"
+ case a: Array[Int] => s"array of int: ${a.mkString(",")}"
+ case as: Array[String] => s"string array: ${as.mkString(",")}"
+ case d: Dog => s"dog: ${d.name}"
+ case list: List[?] => s"got a List: $list"
+ case m: Map[?, ?] => m.toString
+
+ // the default wildcard pattern
+ case _ => "Unknown"
+```
+{% endtab %}
+{% endtabs %}
+
+You can also write the code on the right side of the `=>` on multiple lines if you think it is easier to read. Here is one example:
+
+{% tabs control-structures-31 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-31 %}
+```scala
+count match {
+ case 1 =>
+ println("one, a lonely number")
+ case x if x == 2 || x == 3 =>
+ println("two's company, three's a crowd")
+ case x if x > 3 =>
+ println("4+, that's a party")
+ case _ =>
+ println("i'm guessing your number is zero or less")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-31 %}
+```scala
+count match
+ case 1 =>
+ println("one, a lonely number")
+ case x if x == 2 || x == 3 =>
+ println("two's company, three's a crowd")
+ case x if x > 3 =>
+ println("4+, that's a party")
+ case _ =>
+ println("i'm guessing your number is zero or less")
+```
+{% endtab %}
+{% endtabs %}
+
+In Scala 3, `match` expressions can be chained:
+
+{% tabs 'control-structures-32' %}
+{% tab 'Scala 3 Only' %}
+```scala
+i match
+ case odd: Int if odd % 2 == 1 => "odd"
+ case even: Int if even % 2 == 0 => "even"
+ case _ => "not an integer"
+match
+ case "even" => true
+ case _ => false
+```
+{% endtab %}
+{% endtabs %}
+
+The `match` expression can also follow a period, which simplifies matching on results returned by chained method calls:
+
+{% tabs 'control-structures-33' %}
+{% tab 'Scala 3 Only' %}
+```scala
+List(1, 2, 3)
+ .map(_ * 2)
+ .headOption
+ .match
+ case Some(value) => println(s"The head is: $value")
+ case None => println("The list is empty")
+```
+{% endtab %}
+{% endtabs %}
+
+## try/catch/finally
+
+Like Java, Scala has a `try`/`catch`/`finally` construct to let you catch and manage exceptions.
+For consistency, Scala uses the same syntax that `match` expressions use and supports pattern matching on the different possible exceptions that can occur.
+
+In the following example, `openAndReadAFile` is a method that does what its name implies: it opens a file and reads the text in it, assigning the result to the mutable variable `text`:
+
+{% tabs control-structures-34 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-34 %}
+```scala
+var text = ""
+try {
+ text = openAndReadAFile(filename)
+} catch {
+ case fnf: FileNotFoundException => fnf.printStackTrace()
+ case ioe: IOException => ioe.printStackTrace()
+} finally {
+ // close your resources here
+ println("Came to the 'finally' clause.")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-34 %}
+```scala
+var text = ""
+try
+ text = openAndReadAFile(filename)
+catch
+ case fnf: FileNotFoundException => fnf.printStackTrace()
+ case ioe: IOException => ioe.printStackTrace()
+finally
+ // close your resources here
+ println("Came to the 'finally' clause.")
+```
+{% endtab %}
+{% endtabs %}
+
+Assuming that the `openAndReadAFile` method uses the Java `java.io.*` classes to read a file and doesn't catch its exceptions, attempting to open and read a file can result in both a `FileNotFoundException` and an `IOException`, and those two exceptions are caught in the `catch` block of this example.
+
+[matchable]: {{ site.scala3ref }}/other-new-features/matchable.html
diff --git a/_overviews/scala3-book/domain-modeling-fp.md b/_overviews/scala3-book/domain-modeling-fp.md
new file mode 100644
index 0000000000..bc08f034c2
--- /dev/null
+++ b/_overviews/scala3-book/domain-modeling-fp.md
@@ -0,0 +1,818 @@
+---
+title: FP Modeling
+type: section
+description: This chapter provides an introduction to FP domain modeling with Scala 3.
+languages: [ru, zh-cn]
+num: 23
+previous-page: domain-modeling-oop
+next-page: methods-intro
+---
+
+
+This chapter provides an introduction to domain modeling using functional programming (FP) in Scala 3.
+When modeling the world around us with FP, you typically use these Scala constructs:
+
+- Enumerations
+- Case classes
+- Traits
+
+> If you’re not familiar with algebraic data types (ADTs) and their generalized version (GADTs), you may want to read the [Algebraic Data Types][adts] section before reading this section.
+
+## Introduction
+
+In FP, the *data* and the *operations on that data* are two separate things; you aren’t forced to encapsulate them together like you do with OOP.
+
+The concept is similar to numerical algebra.
+When you think about whole numbers whose values are greater than or equal to zero, you have a *set* of possible values that looks like this:
+
+````
+0, 1, 2 ... Int.MaxValue
+````
+
+Ignoring the division of whole numbers, the possible *operations* on those values are:
+
+````
++, -, *
+````
+
+In FP, business domains are modeled in a similar way:
+
+- You describe your set of values (your data)
+- You describe operations that work on those values (your functions)
+
+> As we will see, reasoning about programs in this style is quite different from the object-oriented programming.
+> Data in FP simply **is**:
+> Separating functionality from your data lets you inspect your data without having to worry about behavior.
+
+In this chapter we’ll model the data and operations for a “pizza” in a pizza store.
+You’ll see how to implement the “data” portion of the Scala/FP model, and then you’ll see several different ways you can organize the operations on that data.
+
+## Modeling the Data
+
+In Scala, describing the data model of a programming problem is simple:
+
+- If you want to model data with different alternatives, use the `enum` construct, (or `case object` in Scala 2).
+- If you only want to group things (or need more fine-grained control) use `case` classes
+
+### Describing Alternatives
+
+Data that simply consists of different alternatives, like crust size, crust type, and toppings, is precisely modelled
+in Scala by an enumeration.
+
+{% tabs data_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=data_1 %}
+
+In Scala 2 enumerations are expressed with a combination of a `sealed class` and several `case object` that extend the class:
+
+```scala
+sealed abstract class CrustSize
+object CrustSize {
+ case object Small extends CrustSize
+ case object Medium extends CrustSize
+ case object Large extends CrustSize
+}
+
+sealed abstract class CrustType
+object CrustType {
+ case object Thin extends CrustType
+ case object Thick extends CrustType
+ case object Regular extends CrustType
+}
+
+sealed abstract class Topping
+object Topping {
+ case object Cheese extends Topping
+ case object Pepperoni extends Topping
+ case object BlackOlives extends Topping
+ case object GreenOlives extends Topping
+ case object Onions extends Topping
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=data_1 %}
+
+In Scala 3 enumerations are concisely expressed with the `enum` construct:
+
+```scala
+enum CrustSize:
+ case Small, Medium, Large
+
+enum CrustType:
+ case Thin, Thick, Regular
+
+enum Topping:
+ case Cheese, Pepperoni, BlackOlives, GreenOlives, Onions
+```
+
+{% endtab %}
+{% endtabs %}
+
+> Data types that describe different alternatives (like `CrustSize`) are also sometimes referred to as _sum types_.
+
+### Describing Compound Data
+
+A pizza can be thought of as a _compound_ container of the different attributes above.
+We can use a `case` class to describe that a `Pizza` consists of a `crustSize`, `crustType`, and potentially multiple `toppings`:
+
+{% tabs data_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=data_2 %}
+
+```scala
+import CrustSize._
+import CrustType._
+import Topping._
+
+case class Pizza(
+ crustSize: CrustSize,
+ crustType: CrustType,
+ toppings: Seq[Topping]
+)
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=data_2 %}
+
+```scala
+import CrustSize.*
+import CrustType.*
+import Topping.*
+
+case class Pizza(
+ crustSize: CrustSize,
+ crustType: CrustType,
+ toppings: Seq[Topping]
+)
+```
+
+{% endtab %}
+{% endtabs %}
+
+> Data Types that aggregate multiple components (like `Pizza`) are also sometimes referred to as _product types_.
+
+And that’s it.
+That’s the data model for an FP-style pizza system.
+This solution is very concise because it doesn’t require the operations on a pizza to be combined with the data model.
+The data model is easy to read, like declaring the design for a relational database.
+It is also very easy to create values of our data model and inspect them:
+
+{% tabs data_3 %}
+{% tab 'Scala 2 and 3' for=data_3 %}
+
+```scala
+val myFavPizza = Pizza(Small, Regular, Seq(Cheese, Pepperoni))
+println(myFavPizza.crustType) // prints Regular
+```
+
+{% endtab %}
+{% endtabs %}
+
+#### More of the data model
+
+We might go on in the same way to model the entire pizza-ordering system.
+Here are a few other `case` classes that are used to model such a system:
+
+{% tabs data_4 %}
+{% tab 'Scala 2 and 3' for=data_4 %}
+
+```scala
+case class Address(
+ street1: String,
+ street2: Option[String],
+ city: String,
+ state: String,
+ zipCode: String
+)
+
+case class Customer(
+ name: String,
+ phone: String,
+ address: Address
+)
+
+case class Order(
+ pizzas: Seq[Pizza],
+ customer: Customer
+)
+```
+
+{% endtab %}
+{% endtabs %}
+
+#### “Skinny domain objects”
+
+In his book, *Functional and Reactive Domain Modeling*, Debasish Ghosh states that where OOP practitioners describe their classes as “rich domain models” that encapsulate data and behaviors, FP data models can be thought of as “skinny domain objects.”
+This is because---as this lesson shows---the data models are defined as `case` classes with attributes, but no behaviors, resulting in short and concise data structures.
+
+## Modeling the Operations
+
+This leads to an interesting question: Because FP separates the data from the operations on that data, how do you implement those operations in Scala?
+
+The answer is actually quite simple: you simply write functions (or methods) that operate on values of the data we just modeled.
+For instance, we can define a function that computes the price of a pizza.
+
+{% tabs data_5 class=tabs-scala-version %}
+{% tab 'Scala 2' for=data_5 %}
+
+```scala
+def pizzaPrice(p: Pizza): Double = p match {
+ case Pizza(crustSize, crustType, toppings) => {
+ val base = 6.00
+ val crust = crustPrice(crustSize, crustType)
+ val tops = toppings.map(toppingPrice).sum
+ base + crust + tops
+ }
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=data_5 %}
+
+```scala
+def pizzaPrice(p: Pizza): Double = p match
+ case Pizza(crustSize, crustType, toppings) =>
+ val base = 6.00
+ val crust = crustPrice(crustSize, crustType)
+ val tops = toppings.map(toppingPrice).sum
+ base + crust + tops
+```
+
+{% endtab %}
+{% endtabs %}
+
+You can notice how the implementation of the function simply follows the shape of the data: since `Pizza` is a case class, we use pattern matching to extract the components and call helper functions to compute the individual prices.
+
+{% tabs data_6 class=tabs-scala-version %}
+{% tab 'Scala 2' for=data_6 %}
+
+```scala
+def toppingPrice(t: Topping): Double = t match {
+ case Cheese | Onions => 0.5
+ case Pepperoni | BlackOlives | GreenOlives => 0.75
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=data_6 %}
+
+```scala
+def toppingPrice(t: Topping): Double = t match
+ case Cheese | Onions => 0.5
+ case Pepperoni | BlackOlives | GreenOlives => 0.75
+```
+
+{% endtab %}
+{% endtabs %}
+
+Similarly, since `Topping` is an enumeration, we use pattern matching to distinguish between the different variants.
+Cheese and onions are priced at 50ct while the rest is priced at 75ct each.
+
+{% tabs data_7 class=tabs-scala-version %}
+{% tab 'Scala 2' for=data_7 %}
+
+```scala
+def crustPrice(s: CrustSize, t: CrustType): Double =
+ (s, t) match {
+ // if the crust size is small or medium,
+ // the type is not important
+ case (Small | Medium, _) => 0.25
+ case (Large, Thin) => 0.50
+ case (Large, Regular) => 0.75
+ case (Large, Thick) => 1.00
+ }
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=data_7 %}
+
+```scala
+def crustPrice(s: CrustSize, t: CrustType): Double =
+ (s, t) match
+ // if the crust size is small or medium,
+ // the type is not important
+ case (Small | Medium, _) => 0.25
+ case (Large, Thin) => 0.50
+ case (Large, Regular) => 0.75
+ case (Large, Thick) => 1.00
+```
+
+{% endtab %}
+{% endtabs %}
+
+To compute the price of the crust we simultaneously pattern match on both the size and the type of the crust.
+
+> An important point about all functions shown above is that they are *pure functions*: they do not mutate any data or have other side-effects (like throwing exceptions or writing to a file).
+> All they do is simply receive values and compute the result.
+
+{% comment %}
+I’ve added this comment per [this GitHub comment](https://github.com/scalacenter/docs.scala-lang/pull/3#discussion_r543372428).
+To that point, I’ve added these definitions here from our Slack conversation, in case anyone wants to update the “pure function” definition. If not, please delete this comment.
+
+Sébastien:
+----------
+A function `f` is pure if, given the same input `x`, it will always return the same output `f(x)`, and it never modifies any state outside it (therefore potentially causing other functions to behave differently in the future).
+
+Jonathan:
+---------
+We say a function is 'pure' if it does not depend on or modify the context it is called in.
+
+Wikipedia
+---------
+The function always evaluates to the same result value given the same argument value(s). It cannot depend on any hidden state or value, and it cannot depend on any I/O.
+Evaluation of the result does not cause any semantically observable side effect or output, such as mutation of mutable objects or output to I/O devices.
+
+Mine (Alvin, now modified, from fp-pure-functions.md):
+------------------------------------------------------
+- A function `f` is pure if, given the same input `x`, it always returns the same output `f(x)`
+- The function’s output depends *only* on its input variables and its internal algorithm
+- It doesn’t modify its input parameters
+- It doesn’t mutate any hidden state
+- It doesn’t have any “back doors”: It doesn’t read data from the outside world (including the console, web services, databases, files, etc.), or write data to the outside world
+{% endcomment %}
+
+## How to Organize Functionality
+
+When implementing the `pizzaPrice` function above, we did not say _where_ we would define it.
+Scala gives you many great tools to organize your logic in different namespaces and modules.
+
+There are several different ways to implement and organize behaviors:
+
+- Define your functions in companion objects
+- Use a modular programming style
+- Use a “functional objects” approach
+- Define the functionality in extension methods
+
+These different solutions are shown in the remainder of this section.
+
+### Companion Object
+
+A first approach is to define the behavior---the functions---in a companion object.
+
+> As discussed in the Domain Modeling [Tools section][modeling-tools], a _companion object_ is an `object` that has the same name as a class, and is declared in the same file as the class.
+
+With this approach, in addition to the enumeration or case class you also define an equally named companion object that contains the behavior.
+
+{% tabs org_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=org_1 %}
+
+```scala
+case class Pizza(
+ crustSize: CrustSize,
+ crustType: CrustType,
+ toppings: Seq[Topping]
+)
+
+// the companion object of case class Pizza
+object Pizza {
+ // the implementation of `pizzaPrice` from above
+ def price(p: Pizza): Double = ...
+}
+
+sealed abstract class Topping
+
+// the companion object of enumeration Topping
+object Topping {
+ case object Cheese extends Topping
+ case object Pepperoni extends Topping
+ case object BlackOlives extends Topping
+ case object GreenOlives extends Topping
+ case object Onions extends Topping
+
+ // the implementation of `toppingPrice` above
+ def price(t: Topping): Double = ...
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=org_1 %}
+
+```scala
+case class Pizza(
+ crustSize: CrustSize,
+ crustType: CrustType,
+ toppings: Seq[Topping]
+)
+
+// the companion object of case class Pizza
+object Pizza:
+ // the implementation of `pizzaPrice` from above
+ def price(p: Pizza): Double = ...
+
+enum Topping:
+ case Cheese, Pepperoni, BlackOlives, GreenOlives, Onions
+
+// the companion object of enumeration Topping
+object Topping:
+ // the implementation of `toppingPrice` above
+ def price(t: Topping): Double = ...
+```
+
+{% endtab %}
+{% endtabs %}
+
+With this approach you can create a `Pizza` and compute its price like this:
+
+{% tabs org_2 %}
+{% tab 'Scala 2 and 3' for=org_2 %}
+
+```scala
+val pizza1 = Pizza(Small, Thin, Seq(Cheese, Onions))
+Pizza.price(pizza1)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Grouping functionality this way has a few advantages:
+
+- It associates functionality with data and makes it easier to find for programmers (and the compiler).
+- It creates a namespace and for instance lets us use `price` as a method name without having to rely on overloading.
+- The implementation of `Topping.price` can access enumeration values like `Cheese` without having to import them.
+
+However, there are also a few tradeoffs that should be considered:
+
+- It tightly couples the functionality to your data model.
+ In particular, the companion object needs to be defined in the same file as your `case` class.
+- It might be unclear where to define functions like `crustPrice` that could equally well be placed in a companion object of `CrustSize` or `CrustType`.
+
+## Modules
+
+A second way to organize behavior is to use a “modular” approach.
+The book, *Programming in Scala*, defines a *module* as, “a ‘smaller program piece’ with a well-defined interface and a hidden implementation.”
+Let’s look at what this means.
+
+### Creating a `PizzaService` interface
+
+The first thing to think about are the `Pizza`s “behaviors”.
+When doing this, you sketch a `PizzaServiceInterface` trait like this:
+
+{% tabs module_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=module_1 %}
+
+```scala
+trait PizzaServiceInterface {
+
+ def price(p: Pizza): Double
+
+ def addTopping(p: Pizza, t: Topping): Pizza
+ def removeAllToppings(p: Pizza): Pizza
+
+ def updateCrustSize(p: Pizza, cs: CrustSize): Pizza
+ def updateCrustType(p: Pizza, ct: CrustType): Pizza
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=module_1 %}
+
+```scala
+trait PizzaServiceInterface:
+
+ def price(p: Pizza): Double
+
+ def addTopping(p: Pizza, t: Topping): Pizza
+ def removeAllToppings(p: Pizza): Pizza
+
+ def updateCrustSize(p: Pizza, cs: CrustSize): Pizza
+ def updateCrustType(p: Pizza, ct: CrustType): Pizza
+```
+
+{% endtab %}
+{% endtabs %}
+
+As shown, each method takes a `Pizza` as an input parameter---along with other parameters---and then returns a `Pizza` instance as a result
+
+When you write a pure interface like this, you can think of it as a contract that states, “all non-abstract classes that extend this trait *must* provide an implementation of these services.”
+
+What you might also do at this point is imagine that you’re the consumer of this API.
+When you do that, it helps to sketch out some sample “consumer” code to make sure the API looks like what you want:
+
+{% tabs module_2 %}
+{% tab 'Scala 2 and 3' for=module_2 %}
+
+```scala
+val p = Pizza(Small, Thin, Seq(Cheese))
+
+// how you want to use the methods in PizzaServiceInterface
+val p1 = addTopping(p, Pepperoni)
+val p2 = addTopping(p1, Onions)
+val p3 = updateCrustType(p2, Thick)
+val p4 = updateCrustSize(p3, Large)
+```
+
+{% endtab %}
+{% endtabs %}
+
+If that code seems okay, you’ll typically start sketching another API---such as an API for orders---but since we’re only looking at pizzas right now, we’ll stop thinking about interfaces and create a concrete implementation of this interface.
+
+> Notice that this is usually a two-step process.
+> In the first step, you sketch the contract of your API as an *interface*.
+> In the second step you create a concrete *implementation* of that interface.
+> In some cases you’ll end up creating multiple concrete implementations of the base interface.
+
+### Creating a concrete implementation
+
+Now that you know what the `PizzaServiceInterface` looks like, you can create a concrete implementation of it by writing the body for all of the methods you defined in the interface:
+
+{% tabs module_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=module_3 %}
+
+```scala
+object PizzaService extends PizzaServiceInterface {
+
+ def price(p: Pizza): Double =
+ ... // implementation from above
+
+ def addTopping(p: Pizza, t: Topping): Pizza =
+ p.copy(toppings = p.toppings :+ t)
+
+ def removeAllToppings(p: Pizza): Pizza =
+ p.copy(toppings = Seq.empty)
+
+ def updateCrustSize(p: Pizza, cs: CrustSize): Pizza =
+ p.copy(crustSize = cs)
+
+ def updateCrustType(p: Pizza, ct: CrustType): Pizza =
+ p.copy(crustType = ct)
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=module_3 %}
+
+```scala
+object PizzaService extends PizzaServiceInterface:
+
+ def price(p: Pizza): Double =
+ ... // implementation from above
+
+ def addTopping(p: Pizza, t: Topping): Pizza =
+ p.copy(toppings = p.toppings :+ t)
+
+ def removeAllToppings(p: Pizza): Pizza =
+ p.copy(toppings = Seq.empty)
+
+ def updateCrustSize(p: Pizza, cs: CrustSize): Pizza =
+ p.copy(crustSize = cs)
+
+ def updateCrustType(p: Pizza, ct: CrustType): Pizza =
+ p.copy(crustType = ct)
+
+end PizzaService
+```
+
+{% endtab %}
+{% endtabs %}
+
+While this two-step process of creating an interface followed by an implementation isn’t always necessary, explicitly thinking about the API and its use is a good approach.
+
+With everything in place you can use your `Pizza` class and `PizzaService`:
+
+{% tabs module_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=module_4 %}
+
+```scala
+import PizzaService._
+
+val p = Pizza(Small, Thin, Seq(Cheese))
+
+// use the PizzaService methods
+val p1 = addTopping(p, Pepperoni)
+val p2 = addTopping(p1, Onions)
+val p3 = updateCrustType(p2, Thick)
+val p4 = updateCrustSize(p3, Large)
+
+println(price(p4)) // prints 8.75
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=module_4 %}
+
+```scala
+import PizzaService.*
+
+val p = Pizza(Small, Thin, Seq(Cheese))
+
+// use the PizzaService methods
+val p1 = addTopping(p, Pepperoni)
+val p2 = addTopping(p1, Onions)
+val p3 = updateCrustType(p2, Thick)
+val p4 = updateCrustSize(p3, Large)
+
+println(price(p4)) // prints 8.75
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Functional Objects
+
+In the book, *Programming in Scala*, the authors define the term, “Functional Objects” as “objects that do not have any mutable state”.
+This is also the case for types in `scala.collection.immutable`.
+For example, methods on `List` do not mutate the interal state, but instead create a copy of the `List` as a result.
+
+You can think of this approach as a “hybrid FP/OOP design” because you:
+
+- Model the data using immutable `case` classes.
+- Define the behaviors (methods) in the _same type_ as the data.
+- Implement the behavior as pure functions: They don’t mutate any internal state; rather, they return a copy.
+
+> This really is a hybrid approach: like in an **OOP design**, the methods are encapsulated in the class with the data, but as typical for a **FP design**, methods are implemented as pure functions that don’t mutate the data
+
+#### Example
+
+Using this approach, you can directly implement the functionality on pizzas in the case class:
+
+{% tabs module_5 class=tabs-scala-version %}
+{% tab 'Scala 2' for=module_5 %}
+
+```scala
+case class Pizza(
+ crustSize: CrustSize,
+ crustType: CrustType,
+ toppings: Seq[Topping]
+) {
+
+ // the operations on the data model
+ def price: Double =
+ pizzaPrice(this) // implementation from above
+
+ def addTopping(t: Topping): Pizza =
+ this.copy(toppings = this.toppings :+ t)
+
+ def removeAllToppings: Pizza =
+ this.copy(toppings = Seq.empty)
+
+ def updateCrustSize(cs: CrustSize): Pizza =
+ this.copy(crustSize = cs)
+
+ def updateCrustType(ct: CrustType): Pizza =
+ this.copy(crustType = ct)
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=module_5 %}
+
+```scala
+case class Pizza(
+ crustSize: CrustSize,
+ crustType: CrustType,
+ toppings: Seq[Topping]
+):
+
+ // the operations on the data model
+ def price: Double =
+ pizzaPrice(this) // implementation from above
+
+ def addTopping(t: Topping): Pizza =
+ this.copy(toppings = this.toppings :+ t)
+
+ def removeAllToppings: Pizza =
+ this.copy(toppings = Seq.empty)
+
+ def updateCrustSize(cs: CrustSize): Pizza =
+ this.copy(crustSize = cs)
+
+ def updateCrustType(ct: CrustType): Pizza =
+ this.copy(crustType = ct)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Notice that unlike the previous approaches, because these are methods on the `Pizza` class, they don’t take a `Pizza` reference as an input parameter.
+Instead, they have their own reference to the current pizza instance as `this`.
+
+Now you can use this new design like this:
+
+{% tabs module_6 %}
+{% tab 'Scala 2 and 3' for=module_6 %}
+
+```scala
+Pizza(Small, Thin, Seq(Cheese))
+ .addTopping(Pepperoni)
+ .updateCrustType(Thick)
+ .price
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Extension Methods
+
+Finally, we show an approach that lies between the first one (defining functions in the companion object) and the last one (defining functions as methods on the type itself).
+
+Extension methods let us create an API that is like the one of functional object, without having to define functions as methods on the type itself.
+This can have multiple advantages:
+
+- Our data model is again _very concise_ and does not mention any behavior.
+- We can equip types with additional methods _retroactively_ without having to change the original definition.
+- Other than companion objects or direct methods on the types, extension methods can be defined _externally_ in another file.
+
+Let us revisit our example once more.
+
+{% tabs module_7 class=tabs-scala-version %}
+{% tab 'Scala 2' for=module_7 %}
+
+```scala
+case class Pizza(
+ crustSize: CrustSize,
+ crustType: CrustType,
+ toppings: Seq[Topping]
+)
+
+implicit class PizzaOps(p: Pizza) {
+ def price: Double =
+ pizzaPrice(p) // implementation from above
+
+ def addTopping(t: Topping): Pizza =
+ p.copy(toppings = p.toppings :+ t)
+
+ def removeAllToppings: Pizza =
+ p.copy(toppings = Seq.empty)
+
+ def updateCrustSize(cs: CrustSize): Pizza =
+ p.copy(crustSize = cs)
+
+ def updateCrustType(ct: CrustType): Pizza =
+ p.copy(crustType = ct)
+}
+```
+In the above code, we define the different methods on pizzas as methods in an _implicit class_.
+With `implicit class PizzaOps(p: Pizza)` then wherever `PizzaOps` is imported its methods will be available on
+instances of `Pizza`. The receiver in this case is `p`.
+
+{% endtab %}
+{% tab 'Scala 3' for=module_7 %}
+
+```scala
+case class Pizza(
+ crustSize: CrustSize,
+ crustType: CrustType,
+ toppings: Seq[Topping]
+)
+
+extension (p: Pizza)
+ def price: Double =
+ pizzaPrice(p) // implementation from above
+
+ def addTopping(t: Topping): Pizza =
+ p.copy(toppings = p.toppings :+ t)
+
+ def removeAllToppings: Pizza =
+ p.copy(toppings = Seq.empty)
+
+ def updateCrustSize(cs: CrustSize): Pizza =
+ p.copy(crustSize = cs)
+
+ def updateCrustType(ct: CrustType): Pizza =
+ p.copy(crustType = ct)
+```
+In the above code, we define the different methods on pizzas as _extension methods_.
+With `extension (p: Pizza)` we say that we want to make the methods available on instances of `Pizza`. The receiver
+in this case is `p`.
+
+{% endtab %}
+{% endtabs %}
+
+Using our extension methods, we can obtain the same API as before:
+
+{% tabs module_8 %}
+{% tab 'Scala 2 and 3' for=module_8 %}
+
+```scala
+Pizza(Small, Thin, Seq(Cheese))
+ .addTopping(Pepperoni)
+ .updateCrustType(Thick)
+ .price
+```
+
+{% endtab %}
+{% endtabs %}
+
+while being able to define extensions in any other module.
+Typically, if you are the designer of the data model, you will define your extension methods in the companion object.
+This way, they are already available to all users.
+Otherwise, extension methods need to be imported explicitly to be usable.
+
+## Summary of this Approach
+
+Defining a data model in Scala/FP tends to be simple: Just model variants of the data with enumerations and compound data with `case` classes.
+Then, to model the behavior, define functions that operate on values of your data model.
+We have seen different ways to organize your functions:
+
+- You can put your methods in companion objects
+- You can use a modular programming style, separating interface and implementation
+- You can use a “functional objects” approach and store the methods on the defined data type
+- You can use extension methods to equip your data model with functionality
+
+[adts]: {% link _overviews/scala3-book/types-adts-gadts.md %}
+[modeling-tools]: {% link _overviews/scala3-book/domain-modeling-tools.md %}
diff --git a/_overviews/scala3-book/domain-modeling-intro.md b/_overviews/scala3-book/domain-modeling-intro.md
new file mode 100644
index 0000000000..fada05d5f3
--- /dev/null
+++ b/_overviews/scala3-book/domain-modeling-intro.md
@@ -0,0 +1,15 @@
+---
+title: Domain Modeling
+type: chapter
+description: This chapter provides an introduction to domain modeling in Scala 3.
+languages: [ru, zh-cn]
+num: 20
+previous-page: control-structures
+next-page: domain-modeling-tools
+---
+
+This chapter shows how you can model the world around you with Scala 3:
+
+- The Tools section introduces the tools that are available to you, including classes, traits, enums, and more
+- The OOP Modeling section looks at modeling attributes and behaviors in an object-oriented programming (OOP) style
+- The FP Modeling section looks at domain modeling in a functional programming (FP) style
diff --git a/_overviews/scala3-book/domain-modeling-oop.md b/_overviews/scala3-book/domain-modeling-oop.md
new file mode 100644
index 0000000000..948504139e
--- /dev/null
+++ b/_overviews/scala3-book/domain-modeling-oop.md
@@ -0,0 +1,593 @@
+---
+title: OOP Modeling
+type: section
+description: This chapter provides an introduction to OOP domain modeling with Scala 3.
+languages: [ru, zh-cn]
+num: 22
+previous-page: domain-modeling-tools
+next-page: domain-modeling-fp
+---
+
+
+This chapter provides an introduction to domain modeling using object-oriented programming (OOP) in Scala 3.
+
+## Introduction
+
+Scala provides all the necessary tools for object-oriented design:
+
+- **Traits** let you specify (abstract) interfaces, as well as concrete implementations.
+- **Mixin Composition** gives you the tools to compose components from smaller parts.
+- **Classes** can implement the interfaces specified by traits.
+- **Instances** of classes can have their own private state.
+- **Subtyping** lets you use an instance of one class where an instance of a superclass is expected.
+- **Access modifiers** lets you control which members of a class can be accessed by which part of the code.
+
+## Traits
+
+Perhaps different from other languages with support for OOP, such as Java, the primary tool of decomposition in Scala is not classes, but traits.
+They can serve to describe abstract interfaces like:
+
+{% tabs traits_1 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait Showable {
+ def show: String
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+trait Showable:
+ def show: String
+```
+{% endtab %}
+{% endtabs %}
+
+and can also contain concrete implementations:
+
+{% tabs traits_2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait Showable {
+ def show: String
+ def showHtml = "
"
+```
+{% endtab %}
+{% endtabs %}
+
+You can see that we define the method `showHtml` _in terms_ of the abstract method `show`.
+
+[Odersky and Zenger][scalable] present the _service-oriented component model_ and view:
+
+- **abstract members** as _required_ services: they still need to be implemented by a subclass.
+- **concrete members** as _provided_ services: they are provided to the subclass.
+
+We can already see this with our example of `Showable`: defining a class `Document` that extends `Showable`, we still have to define `show`, but are provided with `showHtml`:
+
+{% tabs traits_3 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+class Document(text: String) extends Showable {
+ def show = text
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+class Document(text: String) extends Showable:
+ def show = text
+```
+
+{% endtab %}
+{% endtabs %}
+
+#### Abstract Members
+
+Abstract methods are not the only thing that can be left abstract in a trait.
+A trait can contain:
+
+- abstract methods (`def m(): T`)
+- abstract value definitions (`val x: T`)
+- abstract type members (`type T`), potentially with bounds (`type T <: S`)
+- abstract givens (`given t: T`)
+Scala 3 only
+
+Each of the above features can be used to specify some form of requirement on the implementor of the trait.
+
+## Mixin Composition
+
+Not only can traits contain abstract and concrete definitions, Scala also provides a powerful way to compose multiple traits: a feature which is often referred to as _mixin composition_.
+
+Let us assume the following two (potentially independently defined) traits:
+
+{% tabs traits_4 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait GreetingService {
+ def translate(text: String): String
+ def sayHello = translate("Hello")
+}
+
+trait TranslationService {
+ def translate(text: String): String = "..."
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+trait GreetingService:
+ def translate(text: String): String
+ def sayHello = translate("Hello")
+
+trait TranslationService:
+ def translate(text: String): String = "..."
+```
+
+{% endtab %}
+{% endtabs %}
+
+To compose the two services, we can simply create a new trait extending them:
+
+{% tabs traits_5 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait ComposedService extends GreetingService with TranslationService
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+trait ComposedService extends GreetingService, TranslationService
+```
+
+{% endtab %}
+{% endtabs %}
+
+Abstract members in one trait (such as `translate` in `GreetingService`) are automatically matched with concrete members in another trait.
+This not only works with methods as in this example, but also with all the other abstract members mentioned above (that is, types, value definitions, etc.).
+
+## Classes
+
+Traits are great to modularize components and describe interfaces (required and provided).
+But at some point we’ll want to create instances of them.
+When designing software in Scala, it’s often helpful to only consider using classes at the leafs of your inheritance model:
+
+{% comment %}
+NOTE: I think “leaves” may technically be the correct word to use, but I prefer “leafs.”
+{% endcomment %}
+
+{% tabs table-traits-cls-summary class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+| Traits | `T1`, `T2`, `T3`
+| Composed traits | `S1 extends T1 with T2`, `S2 extends T2 with T3`
+| Classes | `C extends S1 with T3`
+| Instances | `new C()`
+{% endtab %}
+{% tab 'Scala 3' %}
+| Traits | `T1`, `T2`, `T3`
+| Composed traits | `S1 extends T1, T2`, `S2 extends T2, T3`
+| Classes | `C extends S1, T3`
+| Instances | `C()`
+{% endtab %}
+{% endtabs %}
+
+This is even more the case in Scala 3, where traits now can also take parameters, further eliminating the need for classes.
+
+#### Defining Classes
+
+Like traits, classes can extend multiple traits (but only one super class):
+
+{% tabs class_1 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+class MyService(name: String) extends ComposedService with Showable {
+ def show = s"$name says $sayHello"
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+class MyService(name: String) extends ComposedService, Showable:
+ def show = s"$name says $sayHello"
+```
+
+{% endtab %}
+{% endtabs %}
+
+#### Subtyping
+
+We can create an instance of `MyService` as follows:
+
+{% tabs class_2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+val s1: MyService = new MyService("Service 1")
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+val s1: MyService = MyService("Service 1")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Through the means of subtyping, our instance `s1` can be used everywhere that any of the extended traits is expected:
+
+{% tabs class_3 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val s2: GreetingService = s1
+val s3: TranslationService = s1
+val s4: Showable = s1
+// ... and so on ...
+```
+{% endtab %}
+{% endtabs %}
+
+#### Planning for Extension
+
+As mentioned before, it is possible to extend another class:
+
+{% tabs class_4 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+class Person(name: String)
+class SoftwareDeveloper(name: String, favoriteLang: String)
+ extends Person(name)
+```
+
+{% endtab %}
+{% endtabs %}
+
+However, since _traits_ are designed as the primary means of decomposition,
+it is not recommended to extend a class that is defined in one file from another file.
+
+
Open Classes Scala 3 only
+
+In Scala 3 extending non-abstract classes in other files is restricted. In order to allow this, the base class needs to
+be marked as `open`:
+
+{% tabs class_5 %}
+{% tab 'Scala 3 Only' %}
+
+```scala
+open class Person(name: String)
+```
+{% endtab %}
+{% endtabs %}
+
+Marking classes with [`open`][open] is a new feature of Scala 3. Having to explicitly mark classes as open avoids many common pitfalls in OO design.
+In particular, it requires library designers to explicitly plan for extension and for instance document the classes that are marked as open with additional extension contracts.
+
+{% comment %}
+NOTE/FWIW: In his book, “Effective Java,” Joshua Bloch describes this as “Item 19: Design and document for inheritance or else prohibit it.”
+Unfortunately I can’t find any good links to this on the internet.
+I only mention this because I think that book and phrase is pretty well known in the Java world.
+{% endcomment %}
+
+## Instances and Private Mutable State
+
+Like in other languages with support for OOP, traits and classes in Scala can define mutable fields:
+
+{% tabs instance_6 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+class Counter {
+ // can only be observed by the method `count`
+ private var currentCount = 0
+
+ def tick(): Unit = currentCount += 1
+ def count: Int = currentCount
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+class Counter:
+ // can only be observed by the method `count`
+ private var currentCount = 0
+
+ def tick(): Unit = currentCount += 1
+ def count: Int = currentCount
+```
+
+{% endtab %}
+{% endtabs %}
+
+Every instance of the class `Counter` has its own private state that can only be observed through the method `count`, as the following interaction illustrates:
+
+{% tabs instance_7 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+val c1 = new Counter()
+c1.count // 0
+c1.tick()
+c1.tick()
+c1.count // 2
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+val c1 = Counter()
+c1.count // 0
+c1.tick()
+c1.tick()
+c1.count // 2
+```
+
+{% endtab %}
+{% endtabs %}
+
+#### Access Modifiers
+
+By default, all member definitions in Scala are publicly visible.
+To hide implementation details, it’s possible to define members (methods, fields, types, etc.) to be `private` or `protected`.
+This way you can control how they are accessed or overridden.
+Private members are only visible to the class/trait itself and to its companion object.
+Protected members are also visible to subclasses of the class.
+
+## Advanced Example: Service Oriented Design
+
+In the following, we illustrate some advanced features of Scala and show how they can be used to structure larger software components.
+The examples are adapted from the paper ["Scalable Component Abstractions"][scalable] by Martin Odersky and Matthias Zenger.
+Don’t worry if you don’t understand all the details of the example; it’s primarily intended to demonstrate how to use several type features to construct larger components.
+
+Our goal is to define a software component with a _family of types_ that can be refined later in implementations of the component.
+Concretely, the following code defines the component `SubjectObserver` as a trait with two abstract type members, `S` (for subjects) and `O` (for observers):
+
+{% tabs example_1 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait SubjectObserver {
+
+ type S <: Subject
+ type O <: Observer
+
+ trait Subject { self: S =>
+ private var observers: List[O] = List()
+ def subscribe(obs: O): Unit = {
+ observers = obs :: observers
+ }
+ def publish() = {
+ for ( obs <- observers ) obs.notify(this)
+ }
+ }
+
+ trait Observer {
+ def notify(sub: S): Unit
+ }
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+trait SubjectObserver:
+
+ type S <: Subject
+ type O <: Observer
+
+ trait Subject:
+ self: S =>
+ private var observers: List[O] = List()
+ def subscribe(obs: O): Unit =
+ observers = obs :: observers
+ def publish() =
+ for obs <- observers do obs.notify(this)
+
+ trait Observer:
+ def notify(sub: S): Unit
+```
+
+{% endtab %}
+{% endtabs %}
+
+There are a few things that need explanation.
+
+#### Abstract Type Members
+
+The declaration `type S <: Subject` says that within the trait `SubjectObserver` we can refer to some _unknown_ (that is, abstract) type that we call `S`.
+However, the type is not completely unknown: we know at least that it is _some subtype_ of the trait `Subject`.
+All traits and classes extending `SubjectObserver` are free to choose any type for `S` as long as the chosen type is a subtype of `Subject`.
+The `<: Subject` part of the declaration is also referred to as an _upper bound on `S`_.
+
+#### Nested Traits
+
+_Within_ trait `SubjectObserver`, we define two other traits.
+Let us begin with trait `Observer`, which only defines one abstract method `notify` that takes an argument of type `S`.
+As we will see momentarily, it is important that the argument has type `S` and not type `Subject`.
+
+The second trait, `Subject`, defines one private field `observers` to store all observers that subscribed to this particular subject.
+Subscribing to a subject simply stores the object into this list.
+Again, the type of parameter `obs` is `O`, not `Observer`.
+
+#### Self-type Annotations
+
+Finally, you might have wondered what the `self: S =>` on trait `Subject` is supposed to mean.
+This is called a _self-type annotation_.
+It requires subtypes of `Subject` to also be subtypes of `S`.
+This is necessary to be able to call `obs.notify` with `this` as an argument, since it requires a value of type `S`.
+If `S` was a _concrete_ type, the self-type annotation could be replaced by `trait Subject extends S`.
+
+### Implementing the Component
+
+We can now implement the above component and define the abstract type members to be concrete types:
+
+{% tabs example_2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+object SensorReader extends SubjectObserver {
+ type S = Sensor
+ type O = Display
+
+ class Sensor(val label: String) extends Subject {
+ private var currentValue = 0.0
+ def value = currentValue
+ def changeValue(v: Double) = {
+ currentValue = v
+ publish()
+ }
+ }
+
+ class Display extends Observer {
+ def notify(sub: Sensor) =
+ println(s"${sub.label} has value ${sub.value}")
+ }
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+object SensorReader extends SubjectObserver:
+ type S = Sensor
+ type O = Display
+
+ class Sensor(val label: String) extends Subject:
+ private var currentValue = 0.0
+ def value = currentValue
+ def changeValue(v: Double) =
+ currentValue = v
+ publish()
+
+ class Display extends Observer:
+ def notify(sub: Sensor) =
+ println(s"${sub.label} has value ${sub.value}")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Specifically, we define a _singleton_ object `SensorReader` that extends `SubjectObserver`.
+In the implementation of `SensorReader`, we say that type `S` is now defined as type `Sensor`, and type `O` is defined to be equal to type `Display`.
+Both `Sensor` and `Display` are defined as nested classes within `SensorReader`, implementing the traits `Subject` and `Observer`, correspondingly.
+
+Besides, being an example of a service oriented design, this code also highlights many aspects of object-oriented programming:
+
+- The class `Sensor` introduces its own private state (`currentValue`) and encapsulates modification of the state behind the method `changeValue`.
+- The implementation of `changeValue` uses the method `publish` defined in the extended trait.
+- The class `Display` extends the trait `Observer`, and implements the missing method `notify`.
+{% comment %}
+NOTE: You might say “the abstract method `notify`” in that last sentence, but I like “missing.”
+{% endcomment %}
+
+It is important to point out that the implementation of `notify` can only safely access the label and value of `sub`, since we originally declared the parameter to be of type `S`.
+
+### Using the Component
+
+Finally, the following code illustrates how to use our `SensorReader` component:
+
+{% tabs example_3 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+import SensorReader._
+
+// setting up a network
+val s1 = new Sensor("sensor1")
+val s2 = new Sensor("sensor2")
+val d1 = new Display()
+val d2 = new Display()
+s1.subscribe(d1)
+s1.subscribe(d2)
+s2.subscribe(d1)
+
+// propagating updates through the network
+s1.changeValue(2)
+s2.changeValue(3)
+
+// prints:
+// sensor1 has value 2.0
+// sensor1 has value 2.0
+// sensor2 has value 3.0
+
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+import SensorReader.*
+
+// setting up a network
+val s1 = Sensor("sensor1")
+val s2 = Sensor("sensor2")
+val d1 = Display()
+val d2 = Display()
+s1.subscribe(d1)
+s1.subscribe(d2)
+s2.subscribe(d1)
+
+// propagating updates through the network
+s1.changeValue(2)
+s2.changeValue(3)
+
+// prints:
+// sensor1 has value 2.0
+// sensor1 has value 2.0
+// sensor2 has value 3.0
+```
+
+{% endtab %}
+{% endtabs %}
+
+With all the object-oriented programming utilities under our belt, in the next section we will demonstrate how to design programs in a functional style.
+
+{% comment %}
+NOTE: One thing I occasionally do is flip things like this around, so I first show how to use a component, and then show how to implement that component. I don’t have a rule of thumb about when to do this, but sometimes it’s motivational to see the use first, and then see how to create the code to make that work.
+{% endcomment %}
+
+[scalable]: https://doi.org/10.1145/1094811.1094815
+[open]: {{ site.scala3ref }}/other-new-features/open-classes.html
+[trait-params]: {{ site.scala3ref }}/other-new-features/trait-parameters.html
diff --git a/_overviews/scala3-book/domain-modeling-tools.md b/_overviews/scala3-book/domain-modeling-tools.md
new file mode 100644
index 0000000000..c1475ce161
--- /dev/null
+++ b/_overviews/scala3-book/domain-modeling-tools.md
@@ -0,0 +1,1359 @@
+---
+title: Tools
+type: section
+description: This chapter provides an introduction to the available domain modeling tools in Scala 3, including classes, traits, enums, and more.
+languages: [ru, zh-cn]
+num: 21
+previous-page: domain-modeling-intro
+next-page: domain-modeling-oop
+---
+
+
+Scala provides many different constructs so we can model the world around us:
+
+- Classes
+- Objects
+- Companion objects
+- Traits
+- Abstract classes
+- Enums
+Scala 3 only
+- Case classes
+- Case objects
+
+This section briefly introduces each of these language features.
+
+## Classes
+
+As with other languages, a _class_ in Scala is a template for the creation of object instances.
+Here are some examples of classes:
+
+{% tabs class_1 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+class Person(var name: String, var vocation: String)
+class Book(var title: String, var author: String, var year: Int)
+class Movie(var name: String, var director: String, var year: Int)
+```
+
+{% endtab %}
+{% endtabs %}
+
+These examples show that Scala has a very lightweight way to declare classes.
+
+All the parameters of our example classes are defined as `var` fields, which means they are mutable: you can read them, and also modify them.
+If you want them to be immutable---read only---create them as `val` fields instead, or use a case class.
+
+Prior to Scala 3, you used the `new` keyword to create a new instance of a class:
+
+{% tabs class_2 %}
+{% tab 'Scala 2 Only' %}
+
+```scala
+val p = new Person("Robert Allen Zimmerman", "Harmonica Player")
+// ---
+```
+
+{% endtab %}
+{% endtabs %}
+
+However, with [universal apply methods][creator] this isn’t required in Scala 3:
+Scala 3 only
+
+{% tabs class_3 %}
+{% tab 'Scala 3 Only' %}
+
+```scala
+val p = Person("Robert Allen Zimmerman", "Harmonica Player")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Once you have an instance of a class such as `p`, you can access its fields, which in this example are all constructor parameters:
+
+{% tabs class_4 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+p.name // "Robert Allen Zimmerman"
+p.vocation // "Harmonica Player"
+```
+
+{% endtab %}
+{% endtabs %}
+
+As mentioned, all of these parameters were created as `var` fields, so you can also mutate them:
+
+{% tabs class_5 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+p.name = "Bob Dylan"
+p.vocation = "Musician"
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Fields and methods
+
+Classes can also have methods and additional fields that are not part of constructors.
+They are defined in the body of the class.
+The body is initialized as part of the default constructor:
+
+{% tabs method class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+class Person(var firstName: String, var lastName: String) {
+
+ println("initialization begins")
+ val fullName = firstName + " " + lastName
+
+ // a class method
+ def printFullName: Unit =
+ // access the `fullName` field, which is created above
+ println(fullName)
+
+ printFullName
+ println("initialization ends")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+class Person(var firstName: String, var lastName: String):
+
+ println("initialization begins")
+ val fullName = firstName + " " + lastName
+
+ // a class method
+ def printFullName: Unit =
+ // access the `fullName` field, which is created above
+ println(fullName)
+
+ printFullName
+ println("initialization ends")
+```
+
+{% endtab %}
+{% endtabs %}
+
+The following REPL session shows how to create a new `Person` instance with this class:
+
+{% tabs demo-person class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+````scala
+scala> val john = new Person("John", "Doe")
+initialization begins
+John Doe
+initialization ends
+val john: Person = Person@55d8f6bb
+
+scala> john.printFullName
+John Doe
+````
+{% endtab %}
+{% tab 'Scala 3' %}
+````scala
+scala> val john = Person("John", "Doe")
+initialization begins
+John Doe
+initialization ends
+val john: Person = Person@55d8f6bb
+
+scala> john.printFullName
+John Doe
+````
+{% endtab %}
+{% endtabs %}
+
+Classes can also extend traits and abstract classes, which we cover in dedicated sections below.
+
+### Default parameter values
+
+As a quick look at a few other features, class constructor parameters can also have default values:
+
+{% tabs default-values_1 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+class Socket(val timeout: Int = 5_000, val linger: Int = 5_000) {
+ override def toString = s"timeout: $timeout, linger: $linger"
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+class Socket(val timeout: Int = 5_000, val linger: Int = 5_000):
+ override def toString = s"timeout: $timeout, linger: $linger"
+```
+
+{% endtab %}
+{% endtabs %}
+
+A great thing about this feature is that it lets consumers of your code create classes in a variety of different ways, as though the class had alternate constructors:
+
+{% tabs default-values_2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+val s = new Socket() // timeout: 5000, linger: 5000
+val s = new Socket(2_500) // timeout: 2500, linger: 5000
+val s = new Socket(10_000, 10_000) // timeout: 10000, linger: 10000
+val s = new Socket(timeout = 10_000) // timeout: 10000, linger: 5000
+val s = new Socket(linger = 10_000) // timeout: 5000, linger: 10000
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+val s = Socket() // timeout: 5000, linger: 5000
+val s = Socket(2_500) // timeout: 2500, linger: 5000
+val s = Socket(10_000, 10_000) // timeout: 10000, linger: 10000
+val s = Socket(timeout = 10_000) // timeout: 10000, linger: 5000
+val s = Socket(linger = 10_000) // timeout: 5000, linger: 10000
+```
+
+{% endtab %}
+{% endtabs %}
+
+When creating a new instance of a class, you can also use named parameters.
+This is particularly helpful when many of the parameters have the same type, as shown in this comparison:
+
+{% tabs default-values_3 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+// option 1
+val s = new Socket(10_000, 10_000)
+
+// option 2
+val s = new Socket(
+ timeout = 10_000,
+ linger = 10_000
+)
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+// option 1
+val s = Socket(10_000, 10_000)
+
+// option 2
+val s = Socket(
+ timeout = 10_000,
+ linger = 10_000
+)
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Auxiliary constructors
+
+You can define a class to have multiple constructors so consumers of your class can build it in different ways.
+For example, let’s assume that you need to write some code to model students in a college admission system.
+While analyzing the requirements you’ve seen that you need to be able to construct a `Student` instance in three ways:
+
+- With a name and government ID, for when they first start the admissions process
+- With a name, government ID, and an additional application date, for when they submit their application
+- With a name, government ID, and their student ID, for after they’ve been admitted
+
+One way to handle this situation in an OOP style is with this code:
+
+{% tabs structor_1 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+import java.time._
+
+// [1] the primary constructor
+class Student(
+ var name: String,
+ var govtId: String
+) {
+ private var _applicationDate: Option[LocalDate] = None
+ private var _studentId: Int = 0
+
+ // [2] a constructor for when the student has completed
+ // their application
+ def this(
+ name: String,
+ govtId: String,
+ applicationDate: LocalDate
+ ) = {
+ this(name, govtId)
+ _applicationDate = Some(applicationDate)
+ }
+
+ // [3] a constructor for when the student is approved
+ // and now has a student id
+ def this(
+ name: String,
+ govtId: String,
+ studentId: Int
+ ) = {
+ this(name, govtId)
+ _studentId = studentId
+ }
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+import java.time.*
+
+// [1] the primary constructor
+class Student(
+ var name: String,
+ var govtId: String
+):
+ private var _applicationDate: Option[LocalDate] = None
+ private var _studentId: Int = 0
+
+ // [2] a constructor for when the student has completed
+ // their application
+ def this(
+ name: String,
+ govtId: String,
+ applicationDate: LocalDate
+ ) =
+ this(name, govtId)
+ _applicationDate = Some(applicationDate)
+
+ // [3] a constructor for when the student is approved
+ // and now has a student id
+ def this(
+ name: String,
+ govtId: String,
+ studentId: Int
+ ) =
+ this(name, govtId)
+ _studentId = studentId
+```
+
+{% endtab %}
+{% endtabs %}
+
+{% comment %}
+// for testing that code
+override def toString = s"""
+|Name: $name
+|GovtId: $govtId
+|StudentId: $_studentId
+|Date Applied: $_applicationDate
+""".trim.stripMargin
+{% endcomment %}
+
+The class has three constructors, given by the numbered comments in the code:
+
+1. The primary constructor, given by the `name` and `govtId` in the class definition
+2. An auxiliary constructor with the parameters `name`, `govtId`, and `applicationDate`
+3. Another auxiliary constructor with the parameters `name`, `govtId`, and `studentId`
+
+Those constructors can be called like this:
+
+{% tabs structor_2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+val s1 = new Student("Mary", "123")
+val s2 = new Student("Mary", "123", LocalDate.now())
+val s3 = new Student("Mary", "123", 456)
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+val s1 = Student("Mary", "123")
+val s2 = Student("Mary", "123", LocalDate.now())
+val s3 = Student("Mary", "123", 456)
+```
+
+{% endtab %}
+{% endtabs %}
+
+While this technique can be used, bear in mind that constructor parameters can also have default values, which make it seem that a class has multiple constructors.
+This is shown in the previous `Socket` example.
+
+## Objects
+
+An object is a class that has exactly one instance.
+It’s initialized lazily when its members are referenced, similar to a `lazy val`.
+Objects in Scala allow grouping methods and fields under one namespace, similar to how you use `static` members on a class in Java, Javascript (ES6), or `@staticmethod` in Python.
+
+Declaring an `object` is similar to declaring a `class`.
+Here’s an example of a “string utilities” object that contains a set of methods for working with strings:
+
+{% tabs object_1 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+object StringUtils {
+ def truncate(s: String, length: Int): String = s.take(length)
+ def containsWhitespace(s: String): Boolean = s.matches(".*\\s.*")
+ def isNullOrEmpty(s: String): Boolean = s == null || s.trim.isEmpty
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+object StringUtils:
+ def truncate(s: String, length: Int): String = s.take(length)
+ def containsWhitespace(s: String): Boolean = s.matches(".*\\s.*")
+ def isNullOrEmpty(s: String): Boolean = s == null || s.trim.isEmpty
+```
+
+{% endtab %}
+{% endtabs %}
+
+We can use the object as follows:
+
+{% tabs object_2 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+StringUtils.truncate("Chuck Bartowski", 5) // "Chuck"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Importing in Scala is very flexible, and allows us to import _all_ members of an object:
+
+{% tabs object_3 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+import StringUtils._
+truncate("Chuck Bartowski", 5) // "Chuck"
+containsWhitespace("Sarah Walker") // true
+isNullOrEmpty("John Casey") // false
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+import StringUtils.*
+truncate("Chuck Bartowski", 5) // "Chuck"
+containsWhitespace("Sarah Walker") // true
+isNullOrEmpty("John Casey") // false
+```
+
+{% endtab %}
+{% endtabs %}
+
+or just _some_ members:
+
+{% tabs object_4 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+import StringUtils.{truncate, containsWhitespace}
+truncate("Charles Carmichael", 7) // "Charles"
+containsWhitespace("Captain Awesome") // true
+isNullOrEmpty("Morgan Grimes") // Not found: isNullOrEmpty (error)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Objects can also contain fields, which are also accessed like static members:
+
+{% tabs object_5 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+object MathConstants {
+ val PI = 3.14159
+ val E = 2.71828
+}
+
+println(MathConstants.PI) // 3.14159
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+object MathConstants:
+ val PI = 3.14159
+ val E = 2.71828
+
+println(MathConstants.PI) // 3.14159
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Companion objects
+
+An `object` that has the same name as a class, and is declared in the same file as the class, is called a _"companion object_."
+Similarly, the corresponding class is called the object’s companion class.
+A companion class or object can access the private members of its companion.
+
+Companion objects are used for methods and values that are not specific to instances of the companion class.
+For instance, in the following example the class `Circle` has a member named `area` which is specific to each instance, and its companion object has a method named `calculateArea` that’s (a) not specific to an instance, and (b) is available to every instance:
+
+{% tabs companion class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+import scala.math._
+
+class Circle(val radius: Double) {
+ def area: Double = Circle.calculateArea(radius)
+}
+
+object Circle {
+ private def calculateArea(radius: Double): Double = Pi * pow(radius, 2.0)
+}
+
+val circle1 = new Circle(5.0)
+circle1.area
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+import scala.math.*
+
+class Circle(val radius: Double):
+ def area: Double = Circle.calculateArea(radius)
+
+object Circle:
+ private def calculateArea(radius: Double): Double = Pi * pow(radius, 2.0)
+
+val circle1 = Circle(5.0)
+circle1.area
+```
+
+{% endtab %}
+{% endtabs %}
+
+In this example the `area` method that’s available to each instance uses the `calculateArea` method that’s defined in the companion object.
+Once again, `calculateArea` is similar to a static method in Java.
+Also, because `calculateArea` is private, it can’t be accessed by other code, but as shown, it can be seen by instances of the `Circle` class.
+
+### Other uses
+
+Companion objects can be used for several purposes:
+
+- As shown, they can be used to group “static” methods under a namespace
+ - These methods can be public or private
+ - If `calculateArea` was public, it would be accessed as `Circle.calculateArea`
+- They can contain `apply` methods, which---thanks to some syntactic sugar---work as factory methods to construct new instances
+- They can contain `unapply` methods, which are used to deconstruct objects, such as with pattern matching
+
+Here’s a quick look at how `apply` methods can be used as factory methods to create new objects:
+
+{% tabs companion-use class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+class Person {
+ var name = ""
+ var age = 0
+ override def toString = s"$name is $age years old"
+}
+
+object Person {
+ // a one-arg factory method
+ def apply(name: String): Person = {
+ var p = new Person
+ p.name = name
+ p
+ }
+
+ // a two-arg factory method
+ def apply(name: String, age: Int): Person = {
+ var p = new Person
+ p.name = name
+ p.age = age
+ p
+ }
+}
+
+val joe = Person("Joe")
+val fred = Person("Fred", 29)
+
+//val joe: Person = Joe is 0 years old
+//val fred: Person = Fred is 29 years old
+```
+
+The `unapply` method isn’t covered here, but it’s covered in the [Language Specification](https://scala-lang.org/files/archive/spec/2.13/08-pattern-matching.html#extractor-patterns).
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+class Person:
+ var name = ""
+ var age = 0
+ override def toString = s"$name is $age years old"
+
+object Person:
+
+ // a one-arg factory method
+ def apply(name: String): Person =
+ var p = new Person
+ p.name = name
+ p
+
+ // a two-arg factory method
+ def apply(name: String, age: Int): Person =
+ var p = new Person
+ p.name = name
+ p.age = age
+ p
+
+end Person
+
+val joe = Person("Joe")
+val fred = Person("Fred", 29)
+
+//val joe: Person = Joe is 0 years old
+//val fred: Person = Fred is 29 years old
+```
+
+The `unapply` method isn’t covered here, but it’s covered in the [Reference documentation]({{ site.scala3ref }}/changed-features/pattern-matching.html).
+
+{% endtab %}
+{% endtabs %}
+
+## Traits
+
+If you’re familiar with Java, a Scala trait is similar to an interface in Java 8+. Traits can contain:
+
+- Abstract methods and fields
+- Concrete methods and fields
+
+In a basic use, a trait can be used as an interface, defining only abstract members that will be implemented by other classes:
+
+{% tabs traits_1 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait Employee {
+ def id: Int
+ def firstName: String
+ def lastName: String
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+trait Employee:
+ def id: Int
+ def firstName: String
+ def lastName: String
+```
+
+{% endtab %}
+{% endtabs %}
+
+However, traits can also contain concrete members.
+For instance, the following trait defines two abstract members---`numLegs` and `walk()`---and also has a concrete implementation of a `stop()` method:
+
+{% tabs traits_2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait HasLegs {
+ def numLegs: Int
+ def walk(): Unit
+ def stop() = println("Stopped walking")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+trait HasLegs:
+ def numLegs: Int
+ def walk(): Unit
+ def stop() = println("Stopped walking")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Here’s another trait with an abstract member and two concrete implementations:
+
+{% tabs traits_3 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait HasTail {
+ def tailColor: String
+ def wagTail() = println("Tail is wagging")
+ def stopTail() = println("Tail is stopped")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+trait HasTail:
+ def tailColor: String
+ def wagTail() = println("Tail is wagging")
+ def stopTail() = println("Tail is stopped")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Notice how each trait only handles very specific attributes and behaviors: `HasLegs` deals only with legs, and `HasTail` deals only with tail-related functionality.
+Traits let you build small modules like this.
+
+Later in your code, classes can mix multiple traits to build larger components:
+
+{% tabs traits_4 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+class IrishSetter(name: String) extends HasLegs with HasTail {
+ val numLegs = 4
+ val tailColor = "Red"
+ def walk() = println("I’m walking")
+ override def toString = s"$name is a Dog"
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+class IrishSetter(name: String) extends HasLegs, HasTail:
+ val numLegs = 4
+ val tailColor = "Red"
+ def walk() = println("I’m walking")
+ override def toString = s"$name is a Dog"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Notice that the `IrishSetter` class implements the abstract members that are defined in `HasLegs` and `HasTail`.
+Now you can create new `IrishSetter` instances:
+
+{% tabs traits_5 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+val d = new IrishSetter("Big Red") // "Big Red is a Dog"
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+val d = IrishSetter("Big Red") // "Big Red is a Dog"
+```
+
+{% endtab %}
+{% endtabs %}
+
+This is just a taste of what you can accomplish with traits.
+For more details, see the remainder of these modeling lessons.
+
+## Abstract classes
+
+{% comment %}
+LATER: If anyone wants to update this section, our comments about abstract classes and traits are on Slack. The biggest points seem to be:
+
+- The `super` of a trait is dynamic
+- At the use site, people can mix in traits but not classes
+- It remains easier to extend a class than a trait from Java, if the trait has at least a field
+- Similarly, in Scala.js, a class can be imported from or exported to JavaScript. A trait cannot
+- There are also some point that unrelated classes can’t be mixed together, and this can be a modeling advantage
+{% endcomment %}
+
+When you want to write a class, but you know it will have abstract members, you can either create a trait or an abstract class.
+In most situations you’ll use traits, but historically there have been two situations where it’s better to use an abstract class than a trait:
+
+- You want to create a base class that takes constructor arguments
+- The code will be called from Java code
+
+### A base class that takes constructor arguments
+
+Prior to Scala 3, when a base class needed to take constructor arguments, you’d declare it as an `abstract class`:
+
+{% tabs abstract_1 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+abstract class Pet(name: String) {
+ def greeting: String
+ def age: Int
+ override def toString = s"My name is $name, I say $greeting, and I’m $age"
+}
+
+class Dog(name: String, var age: Int) extends Pet(name) {
+ val greeting = "Woof"
+}
+
+val d = new Dog("Fido", 1)
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+abstract class Pet(name: String):
+ def greeting: String
+ def age: Int
+ override def toString = s"My name is $name, I say $greeting, and I’m $age"
+
+class Dog(name: String, var age: Int) extends Pet(name):
+ val greeting = "Woof"
+
+val d = Dog("Fido", 1)
+```
+
+{% endtab %}
+{% endtabs %}
+
+
Trait Parameters Scala 3 only
+
+However, with Scala 3, traits can now have [parameters][trait-params], so you can now use traits in the same situation:
+
+{% tabs abstract_2 %}
+
+{% tab 'Scala 3 Only' %}
+
+```scala
+trait Pet(name: String):
+ def greeting: String
+ def age: Int
+ override def toString = s"My name is $name, I say $greeting, and I’m $age"
+
+class Dog(name: String, var age: Int) extends Pet(name):
+ val greeting = "Woof"
+
+val d = Dog("Fido", 1)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Traits are more flexible to compose---you can mix in multiple traits, but only extend one class---and should be preferred to classes and abstract classes most of the time.
+The rule of thumb is to use classes whenever you want to create instances of a particular type, and traits when you want to decompose and reuse behaviour.
+
+
Enums Scala 3 only
+
+An enumeration can be used to define a type that consists of a finite set of named values (in the section on [FP modeling][fp-modeling], we will see that enums are much more flexible than this).
+Basic enumerations are used to define sets of constants, like the months in a year, the days in a week, directions like north/south/east/west, and more.
+
+As an example, these enumerations define sets of attributes related to pizzas:
+
+{% tabs enum_1 %}
+{% tab 'Scala 3 Only' %}
+
+```scala
+enum CrustSize:
+ case Small, Medium, Large
+
+enum CrustType:
+ case Thin, Thick, Regular
+
+enum Topping:
+ case Cheese, Pepperoni, BlackOlives, GreenOlives, Onions
+```
+
+{% endtab %}
+{% endtabs %}
+
+To use them in other code, first import them, and then use them:
+
+{% tabs enum_2 %}
+{% tab 'Scala 3 Only' %}
+
+```scala
+import CrustSize.*
+val currentCrustSize = Small
+```
+
+{% endtab %}
+{% endtabs %}
+
+Enum values can be compared using equals (`==`), and also matched on:
+
+{% tabs enum_3 %}
+{% tab 'Scala 3 Only' %}
+
+```scala
+// if/then
+if currentCrustSize == Large then
+ println("You get a prize!")
+
+// match
+currentCrustSize match
+ case Small => println("small")
+ case Medium => println("medium")
+ case Large => println("large")
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Additional Enum Features
+
+Enumerations can also be parameterized:
+
+{% tabs enum_4 %}
+{% tab 'Scala 3 Only' %}
+
+```scala
+enum Color(val rgb: Int):
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+```
+
+{% endtab %}
+{% endtabs %}
+
+And they can also have members (like fields and methods):
+
+{% tabs enum_5 %}
+{% tab 'Scala 3 Only' %}
+
+```scala
+enum Planet(mass: Double, radius: Double):
+ private final val G = 6.67300E-11
+ def surfaceGravity = G * mass / (radius * radius)
+ def surfaceWeight(otherMass: Double) =
+ otherMass * surfaceGravity
+
+ case Mercury extends Planet(3.303e+23, 2.4397e6)
+ case Earth extends Planet(5.976e+24, 6.37814e6)
+ // more planets here ...
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Compatibility with Java Enums
+
+If you want to use Scala-defined enums as Java enums, you can do so by extending the class `java.lang.Enum` (which is imported by default) as follows:
+
+{% tabs enum_6 %}
+{% tab 'Scala 3 Only' %}
+
+```scala
+enum Color extends Enum[Color] { case Red, Green, Blue }
+```
+
+{% endtab %}
+{% endtabs %}
+
+The type parameter comes from the Java `enum` definition, and should be the same as the type of the enum.
+There’s no need to provide constructor arguments (as defined in the Java API docs) to `java.lang.Enum` when extending it---the compiler generates them automatically.
+
+After defining `Color` like that, you can use it like you would a Java enum:
+
+````
+scala> Color.Red.compareTo(Color.Green)
+val res0: Int = -1
+````
+
+The section on [algebraic datatypes][adts] and the [reference documentation][ref-enums] cover enumerations in more detail.
+
+## Case classes
+
+Case classes are used to model immutable data structures.
+Take the following example:
+
+{% tabs case-classes_1 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala:
+case class Person(name: String, relation: String)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Since we declare `Person` as a case class, the fields `name` and `relation` are public and immutable by default.
+We can create instances of case classes as follows:
+
+{% tabs case-classes_2 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val christina = Person("Christina", "niece")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Note that the fields can’t be mutated:
+
+{% tabs case-classes_3 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+christina.name = "Fred" // error: reassignment to val
+```
+
+{% endtab %}
+{% endtabs %}
+
+Since the fields of a case class are assumed to be immutable, the Scala compiler can generate many helpful methods for you:
+
+- An `unapply` method is generated, which allows you to perform pattern matching on a case class (that is, `case Person(n, r) => ...`).
+- A `copy` method is generated in the class, which is very useful to create modified copies of an instance.
+- `equals` and `hashCode` methods using structural equality are generated, allowing you to use instances of case classes in `Map`s.
+- A default `toString` method is generated, which is helpful for debugging.
+
+These additional features are demonstrated in the below example:
+
+{% tabs case-classes_4 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+// Case classes can be used as patterns
+christina match {
+ case Person(n, r) => println("name is " + n)
+}
+
+// `equals` and `hashCode` methods generated for you
+val hannah = Person("Hannah", "niece")
+christina == hannah // false
+
+// `toString` method
+println(christina) // Person(Christina,niece)
+
+// built-in `copy` method
+case class BaseballTeam(name: String, lastWorldSeriesWin: Int)
+val cubs1908 = BaseballTeam("Chicago Cubs", 1908)
+val cubs2016 = cubs1908.copy(lastWorldSeriesWin = 2016)
+// result:
+// cubs2016: BaseballTeam = BaseballTeam(Chicago Cubs,2016)
+
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+// Case classes can be used as patterns
+christina match
+ case Person(n, r) => println("name is " + n)
+
+// `equals` and `hashCode` methods generated for you
+val hannah = Person("Hannah", "niece")
+christina == hannah // false
+
+// `toString` method
+println(christina) // Person(Christina,niece)
+
+// built-in `copy` method
+case class BaseballTeam(name: String, lastWorldSeriesWin: Int)
+val cubs1908 = BaseballTeam("Chicago Cubs", 1908)
+val cubs2016 = cubs1908.copy(lastWorldSeriesWin = 2016)
+// result:
+// cubs2016: BaseballTeam = BaseballTeam(Chicago Cubs,2016)
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Support for functional programming
+
+As mentioned, case classes support functional programming (FP):
+
+- In FP, you try to avoid mutating data structures.
+ It thus makes sense that constructor fields default to `val`.
+ Since instances of case classes can’t be changed, they can easily be shared without fearing mutation or race conditions.
+- Instead of mutating an instance, you can use the `copy` method as a template to create a new (potentially changed) instance.
+ This process can be referred to as “update as you copy.”
+- Having an `unapply` method auto-generated for you also lets case classes be used in advanced ways with pattern matching.
+
+{% comment %}
+NOTE: We can use this following text, if desired. If it’s used, it needs to be updated a little bit.
+
+### An `unapply` method
+
+A great thing about a case class is that it automatically generates an `unapply` method for your class, so you don’t have to write one.
+
+To demonstrate this, imagine that you have this trait:
+
+{% tabs case-classes_5 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait Person {
+ def name: String
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+trait Person:
+ def name: String
+```
+
+{% endtab %}
+{% endtabs %}
+
+Then, create these case classes to extend that trait:
+
+{% tabs case-classes_6 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+case class Student(name: String, year: Int) extends Person
+case class Teacher(name: String, specialty: String) extends Person
+```
+
+{% endtab %}
+{% endtabs %}
+
+Because those are defined as case classes---and they have built-in `unapply` methods---you can write a match expression like this:
+
+{% tabs case-classes_7 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+def getPrintableString(p: Person): String = p match {
+ case Student(name, year) =>
+ s"$name is a student in Year $year."
+ case Teacher(name, whatTheyTeach) =>
+ s"$name teaches $whatTheyTeach."
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+def getPrintableString(p: Person): String = p match
+ case Student(name, year) =>
+ s"$name is a student in Year $year."
+ case Teacher(name, whatTheyTeach) =>
+ s"$name teaches $whatTheyTeach."
+```
+
+{% endtab %}
+{% endtabs %}
+
+Notice these two patterns in the `case` statements:
+
+{% tabs case-classes_8 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+case Student(name, year) =>
+case Teacher(name, whatTheyTeach) =>
+```
+
+{% endtab %}
+{% endtabs %}
+
+Those patterns work because `Student` and `Teacher` are defined as case classes that have `unapply` methods whose type signature conforms to a certain standard.
+Technically, the specific type of pattern matching shown in these examples is known as a _constructor pattern_.
+
+> The Scala standard is that an `unapply` method returns the case class constructor fields in a tuple that’s wrapped in an `Option`.
+> The “tuple” part of the solution was shown in the previous lesson.
+
+To show how that code works, create an instance of `Student` and `Teacher`:
+
+{% tabs case-classes_9 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+val s = new Student("Al", 1)
+val t = new Teacher("Bob Donnan", "Mathematics")
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+val s = Student("Al", 1)
+val t = Teacher("Bob Donnan", "Mathematics")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Next, this is what the output looks like in the REPL when you call `getPrintableString` with those two instances:
+
+{% tabs case-classes_10 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+scala> getPrintableString(s)
+res0: String = Al is a student in Year 1.
+
+scala> getPrintableString(t)
+res1: String = Bob Donnan teaches Mathematics.
+```
+
+{% endtab %}
+{% endtabs %}
+
+> All of this content on `unapply` methods and extractors is a little advanced for an introductory book like this, but because case classes are an important FP topic, it seems better to cover them, rather than skipping over them.
+
+#### Add pattern matching to any type with unapply
+
+A great Scala feature is that you can add pattern matching to any type by writing your own `unapply` method.
+As an example, this class defines an `unapply` method in its companion object:
+
+{% tabs case-classes_11 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+class Person(var name: String, var age: Int)
+object Person {
+ def unapply(p: Person): Tuple2[String, Int] = (p.name, p.age)
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+class Person(var name: String, var age: Int)
+object Person:
+ def unapply(p: Person): Tuple2[String, Int] = (p.name, p.age)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Because it defines an `unapply` method, and because that method returns a tuple, you can now use `Person` with a `match` expression:
+
+{% tabs case-classes_12 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+val p = new Person("Astrid", 33)
+
+p match {
+ case Person(n,a) => println(s"name: $n, age: $a")
+ case null => println("No match")
+}
+
+// that code prints: "name: Astrid, age: 33"
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+val p = Person("Astrid", 33)
+
+p match
+ case Person(n,a) => println(s"name: $n, age: $a")
+ case null => println("No match")
+
+// that code prints: "name: Astrid, age: 33"
+```
+
+{% endtab %}
+{% endtabs %}
+
+{% endcomment %}
+
+## Case objects
+
+Case objects are to objects what case classes are to classes: they provide a number of automatically-generated methods to make them more powerful.
+They’re particularly useful whenever you need a singleton object that needs a little extra functionality, such as being used with pattern matching in `match` expressions.
+
+Case objects are useful when you need to pass immutable messages around.
+For instance, if you’re working on a music player project, you’ll create a set of commands or messages like this:
+
+{% tabs case-objects_1 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+sealed trait Message
+case class PlaySong(name: String) extends Message
+case class IncreaseVolume(amount: Int) extends Message
+case class DecreaseVolume(amount: Int) extends Message
+case object StopPlaying extends Message
+```
+
+{% endtab %}
+{% endtabs %}
+
+Then in other parts of your code, you can write methods like this, which use pattern matching to handle the incoming message (assuming the methods `playSong`, `changeVolume`, and `stopPlayingSong` are defined somewhere else):
+
+{% tabs case-objects_2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+def handleMessages(message: Message): Unit = message match {
+ case PlaySong(name) => playSong(name)
+ case IncreaseVolume(amount) => changeVolume(amount)
+ case DecreaseVolume(amount) => changeVolume(-amount)
+ case StopPlaying => stopPlayingSong()
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+def handleMessages(message: Message): Unit = message match
+ case PlaySong(name) => playSong(name)
+ case IncreaseVolume(amount) => changeVolume(amount)
+ case DecreaseVolume(amount) => changeVolume(-amount)
+ case StopPlaying => stopPlayingSong()
+```
+
+{% endtab %}
+{% endtabs %}
+
+[ref-enums]: {{ site.scala3ref }}/enums/enums.html
+[adts]: {% link _overviews/scala3-book/types-adts-gadts.md %}
+[fp-modeling]: {% link _overviews/scala3-book/domain-modeling-fp.md %}
+[creator]: {{ site.scala3ref }}/other-new-features/creator-applications.html
+[unapply]: {{ site.scala3ref }}/changed-features/pattern-matching.html
+[trait-params]: {{ site.scala3ref }}/other-new-features/trait-parameters.html
diff --git a/_overviews/scala3-book/first-look-at-types.md b/_overviews/scala3-book/first-look-at-types.md
new file mode 100644
index 0000000000..5cdb32e57f
--- /dev/null
+++ b/_overviews/scala3-book/first-look-at-types.md
@@ -0,0 +1,303 @@
+---
+title: A First Look at Types
+type: chapter
+description: This page provides a brief introduction to Scala's built-in data types, including Int, Double, String, Long, Any, AnyRef, Nothing, and Null.
+languages: [ru, zh-cn]
+num: 17
+previous-page: taste-summary
+next-page: string-interpolation
+---
+
+
+## All values have a type
+
+In Scala, all values have a type, including numerical values and functions.
+The diagram below illustrates a subset of the type hierarchy.
+
+
+
+## Scala type hierarchy
+
+`Any` is the supertype of all types, also called the **top type**.
+It defines certain universal methods such as `equals`, `hashCode`, and `toString`.
+
+The top-type `Any` has a subtype [`Matchable`][matchable], which is used to mark all types that we can perform pattern matching on. It is important to guarantee a property call _"parametricity"_.
+We will not go into details here, but in summary, it means that we cannot pattern match on values of type `Any`, but only on values that are a subtype of `Matchable`.
+The [reference documentation][matchable] contains more information about `Matchable`.
+
+`Matchable` has two important subtypes: `AnyVal` and `AnyRef`.
+
+*`AnyVal`* represents value types.
+There are a couple of predefined value types, and they are non-nullable: `Double`, `Float`, `Long`, `Int`, `Short`, `Byte`, `Char`, `Unit`, and `Boolean`.
+`Unit` is a value type which carries no meaningful information.
+There is exactly one instance of `Unit` which we can refer to as: `()`.
+
+*`AnyRef`* represents reference types.
+All non-value types are defined as reference types.
+Every user-defined type in Scala is a subtype of `AnyRef`.
+If Scala is used in the context of a Java runtime environment, `AnyRef` corresponds to `java.lang.Object`.
+
+In statement-based languages, `void` is used for methods that don’t return anything.
+If you write methods in Scala that have no return value, such as the following method, `Unit` is used for the same purpose:
+
+{% tabs unit %}
+{% tab 'Scala 2 and 3' for=unit %}
+```scala
+def printIt(a: Any): Unit = println(a)
+```
+{% endtab %}
+{% endtabs %}
+
+Here’s an example that demonstrates that strings, integers, characters, boolean values, and functions are all instances of `Any` and can be treated just like every other object:
+
+{% tabs any %}
+{% tab 'Scala 2 and 3' for=any %}
+```scala
+val list: List[Any] = List(
+ "a string",
+ 732, // an integer
+ 'c', // a character
+ '\'', // a character with a backslash escape
+ true, // a boolean value
+ () => "an anonymous function returning a string"
+)
+
+list.foreach(element => println(element))
+```
+{% endtab %}
+{% endtabs %}
+
+The code defines a value `list` of type `List[Any]`.
+The list is initialized with elements of various types, but each is an instance of `scala.Any`, so we can add them to the list.
+
+Here’s the output of the program:
+
+```
+a string
+732
+c
+'
+true
+
+```
+
+## Scala’s “value types”
+
+As shown above, Scala’s numeric types extend `AnyVal`, and they’re all full-blown objects.
+These examples show how to declare variables of these numeric types:
+
+{% tabs anyval %}
+{% tab 'Scala 2 and 3' for=anyval %}
+```scala
+val b: Byte = 1
+val i: Int = 1
+val l: Long = 1
+val s: Short = 1
+val d: Double = 2.0
+val f: Float = 3.0
+```
+{% endtab %}
+{% endtabs %}
+
+In the first four examples, if you don’t explicitly specify a type, the number `1` will default to an `Int`, so if you want one of the other data types---`Byte`, `Long`, or `Short`---you need to explicitly declare those types, as shown.
+Numbers with a decimal (like 2.0) will default to a `Double`, so if you want a `Float` you need to declare a `Float`, as shown in the last example.
+
+Because `Int` and `Double` are the default numeric types, you typically create them without explicitly declaring the data type:
+
+{% tabs anynum %}
+{% tab 'Scala 2 and 3' for=anynum %}
+```scala
+val i = 123 // defaults to Int
+val x = 1.0 // defaults to Double
+```
+{% endtab %}
+{% endtabs %}
+
+In your code you can also append the characters `L`, `D`, and `F` (and their lowercase equivalents) to numbers to specify that they are `Long`, `Double`, or `Float` values:
+
+{% tabs type-post %}
+{% tab 'Scala 2 and 3' for=type-post %}
+```scala
+val x = 1_000L // val x: Long = 1000
+val y = 2.2D // val y: Double = 2.2
+val z = -3.3F // val z: Float = -3.3
+```
+
+You may also use hexadecimal notation to format integer numbers (normally `Int`, but which also support the
+`L` suffix to specify that they are `Long`):
+
+```scala
+val a = 0xACE // val a: Int = 2766
+val b = 0xfd_3aL // val b: Long = 64826
+```
+
+Scala supports many different ways to format the same floating point number, e.g.
+```scala
+val q = .25 // val q: Double = 0.25
+val r = 2.5e-1 // val r: Double = 0.25
+val s = .0025e2F // val s: Float = 0.25
+```
+{% endtab %}
+{% endtabs %}
+
+Scala also has `String` and `Char` types, which you can generally declare with the implicit form:
+
+{% tabs type-string %}
+{% tab 'Scala 2 and 3' for=type-string %}
+```scala
+val s = "Bill"
+val c = 'a'
+```
+{% endtab %}
+{% endtabs %}
+
+As shown, enclose strings in double-quotes---or triple-quotes for multiline strings---and enclose a character in single-quotes.
+
+Those data types and their ranges are:
+
+| Data Type | Possible Values |
+|-----------|--------------------------------------------------------------------------------------------------|
+| Boolean | `true` or `false` |
+| Byte | 8-bit signed two’s complement integer (-2^7 to 2^7-1, inclusive) -128 to 127 |
+| Short | 16-bit signed two’s complement integer (-2^15 to 2^15-1, inclusive) -32,768 to 32,767 |
+| Int | 32-bit two’s complement integer (-2^31 to 2^31-1, inclusive) -2,147,483,648 to 2,147,483,647 |
+| Long | 64-bit two’s complement integer (-2^63 to 2^63-1, inclusive) (-2^63 to 2^63-1, inclusive) |
+| Float | 32-bit IEEE 754 single-precision float 1.40129846432481707e-45 to 3.40282346638528860e+38 |
+| Double | 64-bit IEEE 754 double-precision float 4.94065645841246544e-324 to 1.79769313486231570e+308 |
+| Char | 16-bit unsigned Unicode character (0 to 2^16-1, inclusive) 0 to 65,535 |
+| String | a sequence of `Char` |
+
+## Strings
+
+Scala strings are similar to Java strings though unlike Java (at least before Java 15),
+it's easy to create multiline strings with triple quotes:
+
+{% tabs string-mlines1 %}
+{% tab 'Scala 2 and 3' for=string-mlines1 %}
+```scala
+val quote = """The essence of Scala:
+ Fusion of functional and object-oriented
+ programming in a typed setting."""
+```
+{% endtab %}
+{% endtabs %}
+
+One drawback of this basic approach is that the lines after the first line are indented, and look like this:
+
+{% tabs string-mlines2 %}
+{% tab 'Scala 2 and 3' for=string-mlines2 %}
+```scala
+"The essence of Scala:
+ Fusion of functional and object-oriented
+ programming in a typed setting."
+```
+{% endtab %}
+{% endtabs %}
+
+When spacing is important, put a `|` symbol in front of all lines after the first line, and call the `stripMargin` method after the string:
+
+{% tabs string-mlines3 %}
+{% tab 'Scala 2 and 3' for=string-mlines3 %}
+```scala
+val quote = """The essence of Scala:
+ |Fusion of functional and object-oriented
+ |programming in a typed setting.""".stripMargin
+```
+{% endtab %}
+{% endtabs %}
+
+Now all of the lines are left-justified inside the string:
+
+{% tabs string-mlines4 %}
+{% tab 'Scala 2 and 3' for=string-mlines4 %}
+```scala
+"The essence of Scala:
+Fusion of functional and object-oriented
+programming in a typed setting."
+```
+{% endtab %}
+{% endtabs %}
+
+Scala strings also support powerful string interpolation methods, which we'll talk about
+in the [next chapter][string-interpolation].
+
+## `BigInt` and `BigDecimal`
+
+When you need really large numbers, use the `BigInt` and `BigDecimal` types:
+
+{% tabs type-bigint %}
+{% tab 'Scala 2 and 3' for=type-bigint %}
+```scala
+val a = BigInt(1_234_567_890_987_654_321L)
+val b = BigDecimal(123_456.789)
+```
+{% endtab %}
+{% endtabs %}
+
+Where `Double` and `Float` are approximate decimal numbers, `BigDecimal` is used for precise arithmetic, such as when working with currency.
+
+A great thing about `BigInt` and `BigDecimal` is that they support all the operators you’re used to using with numeric types:
+
+{% tabs type-bigint2 %}
+{% tab 'Scala 2 and 3' for=type-bigint2 %}
+```scala
+val b = BigInt(1234567890) // scala.math.BigInt = 1234567890
+val c = b + b // scala.math.BigInt = 2469135780
+val d = b * b // scala.math.BigInt = 1524157875019052100
+```
+{% endtab %}
+{% endtabs %}
+
+## Type casting
+
+Value types can be cast in the following way:
+
+
+For example:
+
+{% tabs cast1 %}
+{% tab 'Scala 2 and 3' for=cast1 %}
+```scala
+val b: Byte = 127
+val i: Int = b // 127
+
+val face: Char = '☺'
+val number: Int = face // 9786
+```
+{% endtab %}
+{% endtabs %}
+
+You can only cast to a type if there is no loss of information. Otherwise, you need to be explicit about the cast:
+
+{% tabs cast2 %}
+{% tab 'Scala 2 and 3' for=cast2 %}
+```scala
+val x: Long = 987654321
+val y: Float = x.toFloat // 9.8765434E8 (note that `.toFloat` is required because the cast results in precision loss)
+val z: Long = y // Error
+```
+{% endtab %}
+{% endtabs %}
+
+You can also cast a reference type to a subtype.
+This will be covered later in the tour.
+
+## `Nothing` and `null`
+
+`Nothing` is a subtype of all types, also called the **bottom type**.
+There is no value that has the type `Nothing`.
+A common use is to signal non-termination, such as a thrown exception, program exit, or an infinite loop---i.e., it is the type of an expression which does not evaluate to a value, or a method that does not return normally.
+
+`Null` is a subtype of all reference types (i.e. any subtype of `AnyRef`).
+It has a single value identified by the keyword literal `null`.
+Currently, the usage of `null` is considered bad practice. It should be used mostly for interoperability with other JVM languages. An opt-in compiler option changes the status of `Null` to fix the caveats related to its usage. This option might become the default in a future version of Scala. You can learn more about it [here][safe-null].
+
+In the meantime, `null` should almost never be used in Scala code.
+Alternatives to `null` are discussed in the [Functional Programming chapter][fp] of this book, and the [API documentation][option-api].
+
+[reference]: {{ site.scala3ref }}/overview.html
+[matchable]: {{ site.scala3ref }}/other-new-features/matchable.html
+[fp]: {% link _overviews/scala3-book/fp-intro.md %}
+[string-interpolation]: {% link _overviews/scala3-book/string-interpolation.md %}
+[option-api]: https://scala-lang.org/api/3.x/scala/Option.html
+[safe-null]: {{ site.scala3ref }}/experimental/explicit-nulls.html
diff --git a/_overviews/scala3-book/fp-functional-error-handling.md b/_overviews/scala3-book/fp-functional-error-handling.md
new file mode 100644
index 0000000000..e22fc2b4bb
--- /dev/null
+++ b/_overviews/scala3-book/fp-functional-error-handling.md
@@ -0,0 +1,542 @@
+---
+title: Functional Error Handling
+type: section
+description: This section provides an introduction to functional error handling in Scala 3.
+languages: [ru, zh-cn]
+num: 46
+previous-page: fp-functions-are-values
+next-page: fp-summary
+---
+
+
+
+Functional programming is like writing a series of algebraic equations, and because algebra doesn’t have null values or throw exceptions, you don’t use these features in FP.
+This brings up an interesting question: In the situations where you might normally use a null value or exception in OOP code, what do you do?
+
+Scala’s solution is to use constructs like the `Option`/`Some`/`None` classes.
+This lesson provides an introduction to using these techniques.
+
+Two notes before we jump in:
+
+- The `Some` and `None` classes are subclasses of `Option`.
+- Instead of repeatedly saying “`Option`/`Some`/`None`,” the following text generally just refers to “`Option`” or “the `Option` classes.”
+
+
+
+## A first example
+
+While this first example doesn’t deal with null values, it’s a good way to introduce the `Option` classes, so we’ll start with it.
+
+Imagine that you want to write a method that makes it easy to convert strings to integer values, and you want an elegant way to handle the exception that’s thrown when your method gets a string like `"Hello"` instead of `"1"`.
+A first guess at such a method might look like this:
+
+
+{% tabs fp-java-try class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+def makeInt(s: String): Int =
+ try {
+ Integer.parseInt(s.trim)
+ } catch {
+ case e: Exception => 0
+ }
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+def makeInt(s: String): Int =
+ try
+ Integer.parseInt(s.trim)
+ catch
+ case e: Exception => 0
+```
+{% endtab %}
+
+{% endtabs %}
+
+If the conversion works, this method returns the correct `Int` value, but if it fails, the method returns `0`.
+This might be okay for some purposes, but it’s not really accurate.
+For instance, the method might have received `"0"`, but it may have also received `"foo"`, `"bar"`, or an infinite number of other strings that will throw an exception.
+This is a real problem: How do you know when the method really received a `"0"`, or when it received something else?
+The answer is that with this approach, there’s no way to know.
+
+
+
+## Using Option/Some/None
+
+A common solution to this problem in Scala is to use a trio of classes known as `Option`, `Some`, and `None`.
+The `Some` and `None` classes are subclasses of `Option`, so the solution works like this:
+
+- You declare that `makeInt` returns an `Option` type
+- If `makeInt` receives a string it *can* convert to an `Int`, the answer is wrapped inside a `Some`
+- If `makeInt` receives a string it *can’t* convert, it returns a `None`
+
+Here’s the revised version of `makeInt`:
+
+
+{% tabs fp--try-option class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+def makeInt(s: String): Option[Int] =
+ try {
+ Some(Integer.parseInt(s.trim))
+ } catch {
+ case e: Exception => None
+ }
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+def makeInt(s: String): Option[Int] =
+ try
+ Some(Integer.parseInt(s.trim))
+ catch
+ case e: Exception => None
+```
+{% endtab %}
+
+{% endtabs %}
+
+This code can be read as, “When the given string converts to an integer, return the `Int` wrapped inside a `Some`, such as `Some(1)`.
+When the string can’t be converted to an integer, an exception is thrown and caught, and the method returns a `None` value.”
+
+These examples show how `makeInt` works:
+
+{% tabs fp-try-option-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = makeInt("1") // Some(1)
+val b = makeInt("one") // None
+```
+{% endtab %}
+
+{% endtabs %}
+
+As shown, the string `"1"` results in a `Some(1)`, and the string `"one"` results in a `None`.
+This is the essence of the `Option` approach to error handling.
+As shown, this technique is used so methods can return *values* instead of *exceptions*.
+In other situations, `Option` values are also used to replace `null` values.
+
+Two notes:
+
+- You’ll find this approach used throughout Scala library classes, and in third-party Scala libraries.
+- A key point of this example is that functional methods don’t throw exceptions; instead they return values like `Option`.
+
+
+
+## Being a consumer of makeInt
+
+Now imagine that you’re a consumer of the `makeInt` method.
+You know that it returns a subclass of `Option[Int]`, so the question becomes, how do you work with these return types?
+
+There are two common answers, depending on your needs:
+
+- Use a `match` expression
+- Use a `for` expression
+
+## Using a `match` expression
+
+One possible solution is to use a `match` expression:
+
+{% tabs fp-option-match class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+makeInt(x) match {
+ case Some(i) => println(i)
+ case None => println("That didn’t work.")
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+makeInt(x) match
+ case Some(i) => println(i)
+ case None => println("That didn’t work.")
+```
+{% endtab %}
+
+{% endtabs %}
+
+In this example, if `x` can be converted to an `Int`, the expression on the right-hand side of the first `case` clause is evaluated; if `x` can’t be converted to an `Int`, the expression on the right-hand side of the second `case` clause is evaluated.
+
+
+
+## Using a `for` expression
+
+Another common solution is to use a `for` expression---i.e., the `for`/`yield` combination that was shown earlier in this book.
+For instance, imagine that you want to convert three strings to integer values, and then add them together.
+This is how you do that with a `for` expression and `makeInt`:
+
+
+{% tabs fp-for-comprehension class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+val y = for {
+ a <- makeInt(stringA)
+ b <- makeInt(stringB)
+ c <- makeInt(stringC)
+} yield {
+ a + b + c
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val y = for
+ a <- makeInt(stringA)
+ b <- makeInt(stringB)
+ c <- makeInt(stringC)
+yield
+ a + b + c
+```
+{% endtab %}
+
+{% endtabs %}
+
+After that expression runs, `y` will be one of two things:
+
+- If *all* three strings convert to `Int` values, `y` will be a `Some[Int]`, i.e., an integer wrapped inside a `Some`
+- If *any* of the three strings can’t be converted to an `Int`, `y` will be a `None`
+
+You can test this for yourself:
+
+{% tabs fp-for-comprehension-evaluation class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+val stringA = "1"
+val stringB = "2"
+val stringC = "3"
+
+val y = for {
+ a <- makeInt(stringA)
+ b <- makeInt(stringB)
+ c <- makeInt(stringC)
+} yield {
+ a + b + c
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val stringA = "1"
+val stringB = "2"
+val stringC = "3"
+
+val y = for
+ a <- makeInt(stringA)
+ b <- makeInt(stringB)
+ c <- makeInt(stringC)
+yield
+ a + b + c
+```
+{% endtab %}
+
+{% endtabs %}
+
+With that sample data, the variable `y` will have the value `Some(6)`.
+
+To see the failure case, change any of those strings to something that won’t convert to an integer.
+When you do that, you’ll see that `y` is a `None`:
+
+{% tabs fp-for-comprehension-failure-result %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+y: Option[Int] = None
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+## Thinking of Option as a container
+
+Mental models can often help us understand new situations, so if you’re not familiar with the `Option` classes, one way to think about them is as a *container*:
+
+- `Some` is a container with one item in it
+- `None` is a container, but it has nothing in it
+
+If you prefer to think of the `Option` classes as being like a box, `None` is like an empty box.
+It could have had something in it, but it doesn’t.
+
+
+{% comment %}
+NOTE: I commented-out this subsection because it continues to explain Some and None, and I thought it was probably too much for this book.
+
+
+
+## Using `foreach` with `Option`
+
+Because `Some` and `None` can be thought of containers, they’re also like collections classes.
+They have many of the methods you’d expect from a collection class, including `map`, `filter`, `foreach`, etc.
+
+This raises an interesting question: What will these two values print, if anything?
+
+{% tabs fp-option-methods-evaluation %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+makeInt("1").foreach(println)
+makeInt("x").foreach(println)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Answer: The first example prints the number `1`, and the second example doesn’t print anything.
+The first example prints `1` because:
+
+- `makeInt("1")` evaluates to `Some(1)`
+- The expression becomes `Some(1).foreach(println)`
+- The `foreach` method on the `Some` class knows how to reach inside the `Some` container and extract the value (`1`) that’s inside it, so it passes that value to `println`
+
+Similarly, the second example prints nothing because:
+
+- `makeInt("x")` evaluates to `None`
+- The `foreach` method on the `None` class knows that `None` doesn’t contain anything, so it does nothing
+
+In this regard, `None` is similar to an empty `List`.
+
+
+### The happy and unhappy paths
+
+Somewhere in Scala’s history, someone noted that the first example (the `Some`) represents the “Happy Path” of the `Option` approach, and the second example (the `None`) represents the “Unhappy Path.”
+*But* despite having two different possible outcomes, the great thing with `Option` is that there’s really just one path: The code you write to handle the `Some` and `None` possibilities is the same in both cases.
+The `foreach` examples look like this:
+
+{% tabs fp-another-option-method-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+makeInt(aString).foreach(println)
+```
+{% endtab %}
+
+{% endtabs %}
+
+And the `for` expression looks like this:
+
+{% tabs fp-another-for-comprehension-example class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+val y = for {
+ a <- makeInt(stringA)
+ b <- makeInt(stringB)
+ c <- makeInt(stringC)
+} yield {
+ a + b + c
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val y = for
+ a <- makeInt(stringA)
+ b <- makeInt(stringB)
+ c <- makeInt(stringC)
+yield
+ a + b + c
+```
+{% endtab %}
+
+{% endtabs %}
+
+With exceptions you have to worry about handling branching logic, but because `makeInt` returns a value, you only have to write one piece of code to handle both the Happy and Unhappy Paths, and that simplifies your code.
+
+Indeed, the only time you have to think about whether the `Option` is a `Some` or a `None` is when you handle the result value, such as in a `match` expression:
+
+{% tabs fp-option-match-handle class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+makeInt(x) match {
+ case Some(i) => println(i)
+ case None => println("That didn't work.")
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+makeInt(x) match
+ case Some(i) => println(i)
+ case None => println("That didn't work.")
+```
+{% endtab %}
+
+{% endtabs %}
+
+> There are several other ways to handle `Option` values.
+> See the reference documentation for more details.
+{% endcomment %}
+
+
+
+## Using `Option` to replace `null`
+
+Getting back to `null` values, a place where a `null` value can silently creep into your code is with a class like this:
+
+{% tabs fp=case-class-nulls %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+class Address(
+ var street1: String,
+ var street2: String,
+ var city: String,
+ var state: String,
+ var zip: String
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+While every address on Earth has a `street1` value, the `street2` value is optional.
+As a result, the `street2` field can be assigned a `null` value:
+
+
+{% tabs fp-case-class-nulls-example class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+val santa = new Address(
+ "1 Main Street",
+ null, // <-- D’oh! A null value!
+ "North Pole",
+ "Alaska",
+ "99705"
+)
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val santa = Address(
+ "1 Main Street",
+ null, // <-- D’oh! A null value!
+ "North Pole",
+ "Alaska",
+ "99705"
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Historically, developers have used blank strings and null values in this situation, both of which are hacks to work around the root problem: `street2` is an *optional* field.
+In Scala---and other modern languages---the correct solution is to declare up front that `street2` is optional:
+
+
+{% tabs fp-case-class-with-options %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+class Address(
+ var street1: String,
+ var street2: Option[String], // an optional value
+ var city: String,
+ var state: String,
+ var zip: String
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Now developers can write more accurate code like this:
+
+{% tabs fp-case-class-with-options-example-none class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+val santa = new Address(
+ "1 Main Street",
+ None, // 'street2' has no value
+ "North Pole",
+ "Alaska",
+ "99705"
+)
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val santa = Address(
+ "1 Main Street",
+ None, // 'street2' has no value
+ "North Pole",
+ "Alaska",
+ "99705"
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+or this:
+
+{% tabs fp-case-class-with-options-example-some class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+val santa = new Address(
+ "123 Main Street",
+ Some("Apt. 2B"),
+ "Talkeetna",
+ "Alaska",
+ "99676"
+)
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val santa = Address(
+ "123 Main Street",
+ Some("Apt. 2B"),
+ "Talkeetna",
+ "Alaska",
+ "99676"
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+
+## `Option` isn’t the only solution
+
+While this section focuses on the `Option` classes, Scala has a few other alternatives.
+
+For example, a trio of classes known as `Try`/`Success`/`Failure` work in the same manner, but (a) you primarily use these classes when your code can throw exceptions, and (b) you want to use the `Failure` class because it gives you access to the exception message.
+For example, these `Try` classes are commonly used when writing methods that interact with files, databases, and internet services, as those functions can easily throw exceptions.
+
+
+
+## A quick review
+
+This section was long, so let’s give it a quick review:
+
+- Functional programmers don’t use `null` values
+- A main replacement for `null` values is to use the `Option` classes
+- Functional methods don’t throw exceptions; instead they return values like `Option`, `Try`, or `Either`
+- Common ways to work with `Option` values are `match` and `for` expressions
+- Options can be thought of as containers of one item (`Some`) and no items (`None`)
+- Options can also be used for optional constructor or method parameters
+
+
diff --git a/_overviews/scala3-book/fp-functions-are-values.md b/_overviews/scala3-book/fp-functions-are-values.md
new file mode 100644
index 0000000000..e656d3c9f9
--- /dev/null
+++ b/_overviews/scala3-book/fp-functions-are-values.md
@@ -0,0 +1,145 @@
+---
+title: Functions Are Values
+type: section
+description: This section looks at the use of functions as values in functional programming.
+languages: [ru, zh-cn]
+num: 45
+previous-page: fp-pure-functions
+next-page: fp-functional-error-handling
+---
+
+
+While every programming language ever created probably lets you write pure functions, a second important Scala FP feature is that *you can create functions as values*, just like you create `String` and `Int` values.
+
+This feature has many benefits, the most common of which are (a) you can define methods to accept function parameters, and (b) you can pass functions as parameters into methods.
+You’ve seen this in multiple places in this book, whenever methods like `map` and `filter` are demonstrated:
+
+{% tabs fp-function-as-values-anonymous %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val nums = (1 to 10).toList
+
+val doubles = nums.map(_ * 2) // double each value
+val lessThanFive = nums.filter(_ < 5) // List(1,2,3,4)
+```
+{% endtab %}
+
+{% endtabs %}
+
+In those examples, anonymous functions are passed into `map` and `filter`.
+
+> Anonymous functions are also known as *lambdas*.
+
+In addition to passing anonymous functions into `filter` and `map`, you can also supply them with *methods*:
+
+{% tabs fp-function-as-values-defined %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+// two methods
+def double(i: Int): Int = i * 2
+def underFive(i: Int): Boolean = i < 5
+
+// pass those methods into filter and map
+val doubles = nums.filter(underFive).map(double)
+```
+{% endtab %}
+
+{% endtabs %}
+
+This ability to treat methods and functions as values is a powerful feature that functional programming languages provide.
+
+> Technically, a function that takes another function as an input parameter is known as a *Higher-Order Function*.
+> (If you like humor, as someone once wrote, that’s like saying that a class that takes an instance of another class as a constructor parameter is a Higher-Order Class.)
+
+
+
+## Functions, anonymous functions, and methods
+
+As you saw in those examples, this is an anonymous function:
+
+{% tabs fp-anonymous-function-short %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+_ * 2
+```
+{% endtab %}
+
+{% endtabs %}
+
+As shown in the [higher-order functions][hofs] discussion, that’s a shorthand version of this syntax:
+
+{% tabs fp-anonymous-function-full %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+(i: Int) => i * 2
+```
+{% endtab %}
+
+{% endtabs %}
+
+Functions like these are called “anonymous” because they don’t have names.
+If you want to give one a name, just assign it to a variable:
+
+{% tabs fp-function-assignement %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val double = (i: Int) => i * 2
+```
+{% endtab %}
+
+{% endtabs %}
+
+Now you have a named function, one that’s assigned to a variable.
+You can use this function just like you use a method:
+
+{% tabs fp-function-used-like-method %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+double(2) // 4
+```
+{% endtab %}
+
+{% endtabs %}
+
+In most scenarios it doesn’t matter if `double` is a function or a method; Scala lets you treat them the same way.
+Behind the scenes, the Scala technology that lets you treat methods just like functions is known as [Eta Expansion][eta].
+
+This ability to seamlessly pass functions around as variables is a distinguishing feature of functional programming languages like Scala.
+And as you’ve seen in the `map` and `filter` examples throughout this book, the ability to pass functions into other functions helps you create code that is concise and still readable---*expressive*.
+
+If you’re not comfortable with the process of passing functions as parameters into other functions, here are a few more examples you can experiment with:
+
+{% tabs fp-function-as-values-example %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+List("bob", "joe").map(_.toUpperCase) // List(BOB, JOE)
+List("bob", "joe").map(_.capitalize) // List(Bob, Joe)
+List("plum", "banana").map(_.length) // List(4, 6)
+
+val fruits = List("apple", "pear")
+fruits.map(_.toUpperCase) // List(APPLE, PEAR)
+fruits.flatMap(_.toUpperCase) // List(A, P, P, L, E, P, E, A, R)
+
+val nums = List(5, 1, 3, 11, 7)
+nums.map(_ * 2) // List(10, 2, 6, 22, 14)
+nums.filter(_ > 3) // List(5, 11, 7)
+nums.takeWhile(_ < 6) // List(5, 1, 3)
+nums.sortWith(_ < _) // List(1, 3, 5, 7, 11)
+nums.sortWith(_ > _) // List(11, 7, 5, 3, 1)
+
+nums.takeWhile(_ < 6).sortWith(_ < _) // List(1, 3, 5)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+[hofs]: {% link _overviews/scala3-book/fun-hofs.md %}
+[eta]: {% link _overviews/scala3-book/fun-eta-expansion.md %}
diff --git a/_overviews/scala3-book/fp-immutable-values.md b/_overviews/scala3-book/fp-immutable-values.md
new file mode 100644
index 0000000000..2226ceac95
--- /dev/null
+++ b/_overviews/scala3-book/fp-immutable-values.md
@@ -0,0 +1,103 @@
+---
+title: Immutable Values
+type: section
+description: This section looks at the use of immutable values in functional programming.
+languages: [ru, zh-cn]
+num: 43
+previous-page: fp-what-is-fp
+next-page: fp-pure-functions
+---
+
+
+In pure functional programming, only immutable values are used.
+In Scala this means:
+
+- All variables are created as `val` fields
+- Only immutable collections classes are used, such as `List`, `Vector`, and the immutable `Map` and `Set` classes
+
+Using only immutable variables raises an interesting question: If everything is immutable, how does anything ever change?
+
+When it comes to using collections, one answer is that you don’t mutate an existing collection; instead, you apply a function to an existing collection to create a new collection.
+This is where higher-order functions like `map` and `filter` come in.
+
+For example, imagine that you have a list of names---a `List[String]`---that are all in lowercase, and you want to find all the names that begin with the letter `"j"`, and then you want to capitalize those names.
+In FP you write this code:
+
+{% tabs fp-list %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = List("jane", "jon", "mary", "joe")
+val b = a.filter(_.startsWith("j"))
+ .map(_.capitalize)
+```
+{% endtab %}
+
+{% endtabs %}
+
+As shown, you don’t mutate the original list `a`.
+Instead, you apply filtering and transformation functions to `a` to create a new collection, and assign that result to the new immutable variable `b`.
+
+Similarly, in FP you don’t create classes with mutable `var` constructor parameters.
+That is, you don’t write this:
+
+{% tabs fp--class-variables %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+// don’t do this in FP
+class Person(var firstName: String, var lastName: String)
+ --- ---
+```
+{% endtab %}
+
+{% endtabs %}
+
+Instead, you typically create `case` classes, whose constructor parameters are `val` by default:
+
+{% tabs fp-immutable-case-class %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+case class Person(firstName: String, lastName: String)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Now you create a `Person` instance as a `val` field:
+
+{% tabs fp-case-class-creation %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val reginald = Person("Reginald", "Dwight")
+```
+{% endtab %}
+
+{% endtabs %}
+
+Then, when you need to make a change to the data, you use the `copy` method that comes with a `case` class to “update the data as you make a copy,” like this:
+
+
+{% tabs fp-case-class-copy %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+val elton = reginald.copy(
+ firstName = "Elton", // update the first name
+ lastName = "John" // update the last name
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+There are other techniques for working with immutable collections and variables, but hopefully these examples give you a taste of the techniques.
+
+> Depending on your needs, you may create enums, traits, or classes instead of `case` classes.
+> See the [Data Modeling][modeling] chapter for more details.
+
+
+
+[modeling]: {% link _overviews/scala3-book/domain-modeling-intro.md %}
diff --git a/_overviews/scala3-book/fp-intro.md b/_overviews/scala3-book/fp-intro.md
new file mode 100644
index 0000000000..99f02ca759
--- /dev/null
+++ b/_overviews/scala3-book/fp-intro.md
@@ -0,0 +1,26 @@
+---
+title: Functional Programming
+type: chapter
+description: This chapter provides an introduction to functional programming in Scala 3.
+languages: [ru, zh-cn]
+num: 41
+previous-page: collections-summary
+next-page: fp-what-is-fp
+---
+
+
+Scala lets you write code in an object-oriented programming (OOP) style, a functional programming (FP) style, and also in a hybrid style---using both approaches in combination.
+As stated by Martin Odersky, the creator of Scala, the essence of Scala is a fusion of functional and object-oriented programming in a typed setting:
+
+- Functions for the logic
+- Objects for the modularity
+
+This chapter assumes that you’re comfortable with OOP and less comfortable with FP, so it provides a gentle introduction to several main functional programming concepts:
+
+- What is functional programming?
+- Immutable values
+- Pure functions
+- Functions are values
+- Functional error handling
+
+
diff --git a/_overviews/scala3-book/fp-pure-functions.md b/_overviews/scala3-book/fp-pure-functions.md
new file mode 100644
index 0000000000..641eee59ce
--- /dev/null
+++ b/_overviews/scala3-book/fp-pure-functions.md
@@ -0,0 +1,140 @@
+---
+title: Pure Functions
+type: section
+description: This section looks at the use of pure functions in functional programming.
+languages: [ru, zh-cn]
+num: 44
+previous-page: fp-immutable-values
+next-page: fp-functions-are-values
+---
+
+
+Another feature that Scala offers to help you write functional code is the ability to write pure functions.
+A _pure function_ can be defined like this:
+
+- A function `f` is pure if, given the same input `x`, it always returns the same output `f(x)`
+- The function’s output depends _only_ on its input variables and its implementation
+- It only computes the output and does not modify the world around it
+
+This implies:
+- It doesn’t modify its input parameters
+- It doesn’t mutate any hidden state
+- It doesn’t have any “back doors”: It doesn’t read data from the outside world (including the console, web services, databases, files, etc.), or write data to the outside world
+
+As a result of this definition, any time you call a pure function with the same input value(s), you’ll always get the same result.
+For example, you can call a `double` function an infinite number of times with the input value `2`, and you’ll always get the result `4`.
+
+
+
+## Examples of pure functions
+
+Given that definition, as you can imagine, methods like these in the *scala.math._* package are pure functions:
+
+- `abs`
+- `ceil`
+- `max`
+
+These `String` methods are also pure functions:
+
+- `isEmpty`
+- `length`
+- `substring`
+
+Most methods on the Scala collections classes also work as pure functions, including `drop`, `filter`, `map`, and many more.
+
+> In Scala, _functions_ and _methods_ are almost completely interchangeable, so even though we use the common industry term “pure function,” this term can be used to describe both functions and methods.
+> If you’re interested in how methods can be used like functions, see the [Eta Expansion][eta] discussion.
+
+
+
+## Examples of impure functions
+
+Conversely, the following functions are _impure_ because they violate the definition.
+
+- `println` -- methods that interact with the console, files, databases, web services, sensors, etc., are all impure.
+- `currentTimeMillis ` -- date and time related methods are all impure because their output depends on something other than their input parameters
+- `sys.error` -- exception throwing methods are impure because they do not simply return a result
+
+Impure functions often do one or more of these things:
+
+- Read from hidden state, i.e., they access variables and data not explicitly passed into the function as input parameters
+- Write to hidden state
+- Mutate the parameters they’re given, or mutate hidden variables, such as fields in their containing class
+- Perform some sort of I/O with the outside world
+
+> In general, you should watch out for functions with a return type of `Unit`.
+> Because those functions do not return anything, logically the only reason you ever call it is to achieve some side effect.
+> In consequence, often the usage of those functions is impure.
+
+
+## But impure functions are needed ...
+
+Of course an application isn’t very useful if it can’t read or write to the outside world, so people make this recommendation:
+
+> Write the core of your application using pure functions, and then write an impure “wrapper” around that core to interact with the outside world.
+> As someone once said, this is like putting a layer of impure icing on top of a pure cake.
+
+It’s important to note that there are ways to make impure interactions with the outside world feel more pure.
+For instance, you’ll hear about using an `IO` Monad to deal with input and output.
+These topics are beyond the scope of this document, so to keep things simple it can help to think that FP applications have a core of pure functions that are wrapped with other functions to interact with the outside world.
+
+
+
+## Writing pure functions
+
+**Note**: In this section the common industry term “pure function” is often used to refer to Scala methods.
+
+To write pure functions in Scala, just write them using Scala’s method syntax (though you can also use Scala’s function syntax, as well).
+For instance, here’s a pure function that doubles the input value it’s given:
+
+
+{% tabs fp-pure-function %}
+
+{% tab 'Scala 2 and 3' %}
+```scala
+def double(i: Int): Int = i * 2
+```
+{% endtab %}
+
+{% endtabs %}
+
+If you’re comfortable with recursion, here’s a pure function that calculates the sum of a list of integers:
+
+{% tabs fp-pure-recursive-function class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+def sum(xs: List[Int]): Int = xs match {
+ case Nil => 0
+ case head :: tail => head + sum(tail)
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+def sum(xs: List[Int]): Int = xs match
+ case Nil => 0
+ case head :: tail => head + sum(tail)
+```
+{% endtab %}
+
+{% endtabs %}
+
+If you understand that code, you’ll see that it meets the pure function definition.
+
+
+
+## Key points
+
+The first key point of this section is the definition of a pure function:
+
+> A _pure function_ is a function that depends only on its declared inputs and its implementation to produce its output.
+> It only computes its output and does not depend on or modify the outside world.
+
+A second key point is that every real-world application interacts with the outside world.
+Therefore, a simplified way to think about functional programs is that they consist of a core of pure functions that are wrapped with other functions that interact with the outside world.
+
+
+
+[eta]: {% link _overviews/scala3-book/fun-eta-expansion.md %}
diff --git a/_overviews/scala3-book/fp-summary.md b/_overviews/scala3-book/fp-summary.md
new file mode 100644
index 0000000000..7695293e9d
--- /dev/null
+++ b/_overviews/scala3-book/fp-summary.md
@@ -0,0 +1,27 @@
+---
+title: Summary
+type: section
+description: This section summarizes the previous functional programming sections.
+languages: [ru, zh-cn]
+num: 47
+previous-page: fp-functional-error-handling
+next-page: types-introduction
+---
+
+
+This chapter provides a high-level introduction to functional programming in Scala.
+The topics covered are:
+
+- What is functional programming?
+- Immutable values
+- Pure functions
+- Functions are values
+- Functional error handling
+
+As mentioned, functional programming is a big topic, so all we can do in this book is to touch on these introductory concepts.
+See the [Reference documentation][reference] for more details.
+
+
+
+[reference]: {{ site.scala3ref }}/overview.html
+
diff --git a/_overviews/scala3-book/fp-what-is-fp.md b/_overviews/scala3-book/fp-what-is-fp.md
new file mode 100644
index 0000000000..2eca848e60
--- /dev/null
+++ b/_overviews/scala3-book/fp-what-is-fp.md
@@ -0,0 +1,31 @@
+---
+title: What is Functional Programming?
+type: section
+description: This section provides an answer to the question, what is functional programming?
+languages: [ru, zh-cn]
+num: 42
+previous-page: fp-intro
+next-page: fp-immutable-values
+---
+
+
+
+[Wikipedia defines _functional programming_](https://en.wikipedia.org/wiki/Functional_programming) like this:
+
+
+
Functional programming is a programming paradigm where programs are constructed by applying and composing functions.
+It is a declarative programming paradigm in which function definitions are trees of expressions that each return a value, rather than a sequence of imperative statements which change the state of the program.
+
+
In functional programming, functions are treated as first-class citizens, meaning that they can be bound to names (including local identifiers), passed as arguments, and returned from other functions, just as any other data type can.
+This allows programs to be written in a declarative and composable style, where small functions are combined in a modular manner.
+
+
+It can also be helpful to know that experienced functional programmers have a strong desire to see their code as math, that combining pure functions together is like combining a series of algebraic equations.
+
+When you write functional code you feel like a mathematician, and once you understand the paradigm, you want to write pure functions that always return _values_---not exceptions or null values---so you can combine (compose) them together to create solutions.
+The feeling that you’re writing math-like equations (expressions) is the driving desire that leads you to use _only_ pure functions and immutable values, because that’s what you use in algebra and other forms of math.
+
+Functional programming is a large topic, and there’s no simple way to condense the entire topic into one chapter, but hopefully the following sections will provide an overview of the main topics, and show some of the tools Scala provides for writing functional code.
+
+
+
diff --git a/_overviews/scala3-book/fun-anonymous-functions.md b/_overviews/scala3-book/fun-anonymous-functions.md
new file mode 100644
index 0000000000..428186b968
--- /dev/null
+++ b/_overviews/scala3-book/fun-anonymous-functions.md
@@ -0,0 +1,196 @@
+---
+title: Anonymous Functions
+type: section
+description: This page shows how to use anonymous functions in Scala, including examples with the List class 'map' and 'filter' functions.
+languages: [ru, zh-cn]
+num: 29
+previous-page: fun-intro
+next-page: fun-function-variables
+---
+
+An anonymous function---also referred to as a *lambda*---is a block of code that’s passed as an argument to a higher-order function.
+Wikipedia defines an [anonymous function](https://en.wikipedia.org/wiki/Anonymous_function) as, “a function definition that is not bound to an identifier.”
+
+For example, given a list like this:
+
+{% tabs fun-anonymous-1 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val ints = List(1, 2, 3)
+```
+{% endtab %}
+{% endtabs %}
+
+You can create a new list by doubling each element in `ints`, using the `List` class `map` method and your custom anonymous function:
+
+{% tabs fun-anonymous-2 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val doubledInts = ints.map(_ * 2) // List(2, 4, 6)
+```
+{% endtab %}
+{% endtabs %}
+
+As the comment shows, `doubledInts` contains the list, `List(2, 4, 6)`.
+In that example, this portion of the code is an anonymous function:
+
+{% tabs fun-anonymous-3 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+_ * 2
+```
+{% endtab %}
+{% endtabs %}
+
+This is a shorthand way of saying, “Multiply a given element by 2.”
+
+## Longer forms
+
+Once you’re comfortable with Scala, you’ll use that form all the time to write anonymous functions that use one variable at one spot in the function.
+But if you prefer, you can also write them using longer forms, so in addition to writing this code:
+
+{% tabs fun-anonymous-4 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val doubledInts = ints.map(_ * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+you can also write it using these forms:
+
+{% tabs fun-anonymous-5 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val doubledInts = ints.map((i: Int) => i * 2)
+val doubledInts = ints.map((i) => i * 2)
+val doubledInts = ints.map(i => i * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+All of these lines have the exact same meaning: Double each element in `ints` to create a new list, `doubledInts`.
+(The syntax of each form is explained in a few moments.)
+
+If you’re familiar with Java, it may help to know that those `map` examples are the equivalent of this Java code:
+
+{% tabs fun-anonymous-5-b %}
+{% tab 'Java' %}
+```java
+List ints = List.of(1, 2, 3);
+List doubledInts = ints.stream()
+ .map(i -> i * 2)
+ .collect(Collectors.toList());
+```
+{% endtab %}
+{% endtabs %}
+
+## Shortening anonymous functions
+
+When you want to be explicit, you can write an anonymous function using this long form:
+
+{% tabs fun-anonymous-6 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val doubledInts = ints.map((i: Int) => i * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+The anonymous function in that expression is this:
+
+{% tabs fun-anonymous-7 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+(i: Int) => i * 2
+```
+{% endtab %}
+{% endtabs %}
+
+If you’re not familiar with this syntax, it helps to think of the `=>` symbol as a transformer, because the expression *transforms* the parameter list on the left side of the symbol (an `Int` variable named `i`) into a new result using the algorithm on the right side of the `=>` symbol (in this case, an expression that doubles the `Int`).
+
+### Shortening that expression
+
+This long form can be shortened, as will be shown in the following steps.
+First, here’s that longest and most explicit form again:
+
+{% tabs fun-anonymous-8 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val doubledInts = ints.map((i: Int) => i * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+Because the Scala compiler can infer from the data in `ints` that `i` is an `Int`, the `Int` declaration can be removed:
+
+{% tabs fun-anonymous-9 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val doubledInts = ints.map((i) => i * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+Because there’s only one argument, the parentheses around the parameter `i` aren’t needed:
+
+{% tabs fun-anonymous-10 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val doubledInts = ints.map(i => i * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+Because Scala lets you use the `_` symbol instead of a variable name when the parameter appears only once in your function, the code can be simplified even more:
+
+{% tabs fun-anonymous-11 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val doubledInts = ints.map(_ * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+### Going even shorter
+
+In other examples, you can simplify your anonymous functions further.
+For instance, beginning with the most explicit form, you can print each element in `ints` using this anonymous function with the `List` class `foreach` method:
+
+{% tabs fun-anonymous-12 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+ints.foreach((i: Int) => println(i))
+```
+{% endtab %}
+{% endtabs %}
+
+As before, the `Int` declaration isn’t required, and because there’s only one argument, the parentheses around `i` aren’t needed:
+
+{% tabs fun-anonymous-13 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+ints.foreach(i => println(i))
+```
+{% endtab %}
+{% endtabs %}
+
+Because `i` is used only once in the body of the function, the expression can be further simplified with the `_` symbol:
+
+{% tabs fun-anonymous-14 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+ints.foreach(println(_))
+```
+{% endtab %}
+{% endtabs %}
+
+Finally, if an anonymous function consists of one method call that takes a single argument, you don’t need to explicitly name and specify the argument, so you can finally write only the name of the method (here, `println`):
+
+{% tabs fun-anonymous-15 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+ints.foreach(println)
+```
+{% endtab %}
+{% endtabs %}
diff --git a/_overviews/scala3-book/fun-eta-expansion.md b/_overviews/scala3-book/fun-eta-expansion.md
new file mode 100644
index 0000000000..a435a4284b
--- /dev/null
+++ b/_overviews/scala3-book/fun-eta-expansion.md
@@ -0,0 +1,134 @@
+---
+title: Eta-Expansion
+type: section
+description: This page discusses Eta-Expansion, the Scala technology that automatically and transparently converts methods into functions.
+languages: [ru, zh-cn]
+num: 32
+previous-page: fun-function-variables
+next-page: fun-hofs
+---
+
+
+When you look at the Scaladoc for the `map` method on Scala collections classes, you see that it’s defined to accept a _function_ value:
+
+{% tabs fun_1 %}
+{% tab 'Scala 2 and 3' for=fun_1 %}
+
+```scala
+def map[B](f: A => B): List[B]
+// ^^^^^^ function type from `A` to `B`
+```
+
+{% endtab %}
+{% endtabs %}
+
+Indeed, the Scaladoc clearly states, “`f` is the _function_ to apply to each element.”
+But despite that, somehow you can pass a _method_ into `map`, and it still works:
+
+{% tabs fun_2 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+def times10(i: Int) = i * 10 // a method
+List(1, 2, 3).map(times10) // List(10,20,30)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Why does this work? The process behind this is known as _eta-expansion_.
+It converts an expression of _method type_ to an equivalent expression of _function type_, and it does so seamlessly and quietly.
+
+## The differences between methods and functions
+
+The key difference between methods and functions is that _a function is an object_, i.e. it is an instance of a class, and in turn has its own methods (e.g. try `f.apply` on a function `f`).
+
+_Methods_ are not values that can be passed around, i.e. they can only be called via method application (e.g. `foo(arg1, arg2, ...)`). Methods can be _converted_ to a value by creating a function value that will call the method when supplied with the required arguments. This is known as eta-expansion.
+
+More concretely: with automatic eta-expansion, the compiler automatically converts any _method reference_, without supplied arguments, to an equivalent _anonymous function_ that will call the method. For example, the reference to `times10` in the code above gets rewritten to `x => times10(x)`, as seen here:
+
+{% tabs fun_2_expanded %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+def times10(i: Int) = i * 10
+List(1, 2, 3).map(x => times10(x)) // eta expansion of `.map(times10)`
+```
+
+{% endtab %}
+{% endtabs %}
+
+> For the curious, the term eta-expansion has its origins in the [Lambda Calculus](https://en.wikipedia.org/wiki/Lambda_calculus).
+
+## When does eta-expansion happen?
+
+Automatic eta-expansion is a desugaring that is context-dependent (i.e. the expansion conditionally activates, depending on the surrounding code of the method reference.)
+
+{% tabs fun_5 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+In Scala 2 eta-expansion only occurs automatically when the expected type is a function type.
+For example, the following will fail:
+```scala
+def isLessThan(x: Int, y: Int): Boolean = x < y
+
+val methods = List(isLessThan)
+// ^^^^^^^^^^
+// error: missing argument list for method isLessThan
+// Unapplied methods are only converted to functions when a function type is expected.
+// You can make this conversion explicit by writing `isLessThan _` or `isLessThan(_,_)` instead of `isLessThan`.
+```
+
+See [below](#manual-eta-expansion) for how to solve this issue with manual eta-expansion.
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+New to Scala 3, method references can be used everywhere as a value, they will be automatically converted to a function object with a matching type. e.g.
+
+```scala
+def isLessThan(x: Int, y: Int): Boolean = x < y
+
+val methods = List(isLessThan) // works
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Manual eta-expansion
+
+You can always manually eta-expand a method to a function value, here are some examples how:
+
+{% tabs fun_6 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+val methodsA = List(isLessThan _) // way 1: expand all parameters
+val methodsB = List(isLessThan(_, _)) // way 2: wildcard application
+val methodsC = List((x, y) => isLessThan(x, y)) // way 3: anonymous function
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+val methodsA = List(isLessThan(_, _)) // way 1: wildcard application
+val methodsB = List((x, y) => isLessThan(x, y)) // way 2: anonymous function
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Summary
+
+For the purpose of this introductory book, the important things to know are:
+
+- eta-expansion is a helpful desugaring that lets you use methods just like functions,
+- the automatic eta-expansion been improved in Scala 3 to be almost completely seamless.
+
+For more details on how this works, see the [Eta Expansion page][eta_expansion] in the Reference documentation.
+
+[eta_expansion]: {{ site.scala3ref }}/changed-features/eta-expansion.html
+[extension]: {% link _overviews/scala3-book/ca-extension-methods.md %}
+[toplevel]: {% link _overviews/scala3-book/taste-toplevel-definitions.md %}
diff --git a/_overviews/scala3-book/fun-function-variables.md b/_overviews/scala3-book/fun-function-variables.md
new file mode 100644
index 0000000000..248a334edf
--- /dev/null
+++ b/_overviews/scala3-book/fun-function-variables.md
@@ -0,0 +1,167 @@
+---
+title: Function Variables
+type: section
+description: This page shows how to use function variables in Scala.
+languages: [ru, zh-cn]
+num: 30
+previous-page: fun-anonymous-functions
+next-page: fun-partial-functions
+---
+
+
+
+Going back to this example from the previous section:
+
+{% tabs fun-function-variables-1 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val doubledInts = ints.map((i: Int) => i * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+We noted that this part of the expression is an anonymous function:
+
+{% tabs fun-function-variables-2 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+(i: Int) => i * 2
+```
+{% endtab %}
+{% endtabs %}
+
+The reason it’s called *anonymous* is because it’s not assigned to a variable, and therefore doesn’t have a name.
+
+However, an anonymous function---also known as a *function literal*---can be assigned to a variable to create a *function variable*:
+
+{% tabs fun-function-variables-3 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val double = (i: Int) => i * 2
+```
+{% endtab %}
+{% endtabs %}
+
+This creates a function variable named `double`.
+In this expression, the original function literal is on the right side of the `=` symbol:
+
+{% tabs fun-function-variables-4 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val double = (i: Int) => i * 2
+ -----------------
+```
+{% endtab %}
+{% endtabs %}
+
+the new variable name is on the left side:
+
+{% tabs fun-function-variables-5 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val double = (i: Int) => i * 2
+ ------
+```
+{% endtab %}
+{% endtabs %}
+
+and the function’s parameter list is underlined here:
+
+{% tabs fun-function-variables-6 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val double = (i: Int) => i * 2
+ --------
+```
+{% endtab %}
+{% endtabs %}
+
+Like the parameter list for a method, this means that the `double` function takes one parameter, an `Int` named `i`.
+You can see in the REPL that `double` has the type `Int => Int`, meaning that it takes a single `Int` parameter and returns an `Int`:
+
+{% tabs fun-function-variables-7 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> val double = (i: Int) => i * 2
+val double: Int => Int = ...
+```
+{% endtab %}
+{% endtabs %}
+
+
+### Invoking the function
+
+Now you can call the `double` function like this:
+
+{% tabs fun-function-variables-8 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val x = double(2) // 4
+```
+{% endtab %}
+{% endtabs %}
+
+You can also pass `double` into a `map` call:
+
+{% tabs fun-function-variables-9 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+List(1, 2, 3).map(double) // List(2, 4, 6)
+```
+{% endtab %}
+{% endtabs %}
+
+Furthermore, when you have other functions of the `Int => Int` type:
+
+{% tabs fun-function-variables-10 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val triple = (i: Int) => i * 3
+```
+{% endtab %}
+{% endtabs %}
+
+you can store them in a `List` or `Map`:
+
+{% tabs fun-function-variables-11 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val functionList = List(double, triple)
+
+val functionMap = Map(
+ "2x" -> double,
+ "3x" -> triple
+)
+```
+{% endtab %}
+{% endtabs %}
+
+If you paste those expressions into the REPL, you’ll see that they have these types:
+
+{% tabs fun-function-variables-12 %}
+{% tab 'Scala 2 and 3' %}
+````
+// a List that contains functions of the type `Int => Int`
+functionList: List[Int => Int]
+
+// a Map whose keys have the type `String`, and whose
+// values have the type `Int => Int`
+functionMap: Map[String, Int => Int]
+````
+{% endtab %}
+{% endtabs %}
+
+
+
+## Key points
+
+The important parts here are:
+
+- To create a function variable, just assign a variable name to a function literal
+- Once you have a function, you can treat it like any other variable, i.e., like a `String` or `Int` variable
+
+And thanks to the improved [Eta Expansion][eta_expansion] functionality in Scala 3, you can treat *methods* in the same way.
+
+
+
+[eta_expansion]: {% link _overviews/scala3-book/fun-eta-expansion.md %}
diff --git a/_overviews/scala3-book/fun-hofs.md b/_overviews/scala3-book/fun-hofs.md
new file mode 100644
index 0000000000..943845cfc6
--- /dev/null
+++ b/_overviews/scala3-book/fun-hofs.md
@@ -0,0 +1,381 @@
+---
+title: Higher-Order Functions
+type: section
+description: This page demonstrates how to create and use higher-order functions in Scala.
+languages: [ru, zh-cn]
+num: 33
+previous-page: fun-eta-expansion
+next-page: fun-write-map-function
+---
+
+
+A higher-order function (HOF) is often defined as a function that (a) takes other functions as input parameters or (b) returns a function as a result.
+In Scala, HOFs are possible because functions are first-class values.
+
+As an important note, while we use the common industry term “higher-order function” in this document, in Scala this phrase applies to both *methods* and *functions*.
+Thanks to Scala’s [Eta Expansion technology][eta_expansion], they can generally be used in the same places.
+
+## From consumer to creator
+
+In the examples so far in this book you’ve seen how to be a *consumer* of methods that take other functions as input parameters, such as using HOFs like `map` and `filter`.
+In the next few sections you’ll see how to be a *creator* of HOFs, including:
+
+- How to write methods that take functions as input parameters
+- How to return a function from a method
+
+In the process you’ll see:
+
+- The syntax you use to define function input parameters
+- How to call a function once you have a reference to it
+
+As a beneficial side effect of this discussion, once you’re comfortable with this syntax, you’ll use it to define function parameters, anonymous functions, and function variables, and it also becomes easier to read the Scaladoc for higher-order functions.
+
+## Understanding filter’s Scaladoc
+
+To understand how higher-order functions work, it helps to dig into an example.
+For instance, you can understand the type of functions `filter` accepts by looking at its Scaladoc.
+Here’s the `filter` definition in the `List[A]` class:
+
+{% tabs filter-definition %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def filter(p: A => Boolean): List[A]
+```
+{% endtab %}
+{% endtabs %}
+
+This states that `filter` is a method that takes a function parameter named `p`.
+By convention, `p` stands for a *predicate*, which is just a function that returns a `Boolean` value.
+So `filter` takes a predicate `p` as an input parameter, and returns a `List[A]`, where `A` is the type held in the list; if you call `filter` on a `List[Int]`, `A` is the type `Int`.
+
+At this point, if you don’t know the purpose of the `filter` method, all you’d know is that its algorithm somehow uses the predicate `p` to create and return the `List[A]`.
+
+Looking specifically at the function parameter `p`, this part of `filter`’s description:
+
+{% tabs filter-definition_1 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+p: A => Boolean
+```
+{% endtab %}
+{% endtabs %}
+
+means that whatever function you pass in must take the type `A` as an input parameter and return a `Boolean`.
+So if your list is a `List[Int]`, you can replace the type parameter `A` with `Int`, and read that signature like this:
+
+{% tabs filter-definition_2 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+p: Int => Boolean
+```
+{% endtab %}
+{% endtabs %}
+
+Because `isEven` has this type---it transforms an input `Int` into a resulting `Boolean`---it can be used with `filter`.
+
+{% comment %}
+NOTE: (A low-priority issue): The next several sections can be condensed.
+{% endcomment %}
+
+## Writing methods that take function parameters
+
+Given that background, let’s start writing methods that take functions as input parameters.
+
+**Note:** To make the following discussion clear, we’ll refer to the code you’re writing as a *method*, and the code you’re accepting as an input parameter as a *function*.
+
+
+### A first example
+
+To create a method that takes a function parameter, all you have to do is:
+
+1. In your method’s parameter list, define the signature of the function you want to accept
+2. Use that function inside your method
+
+To demonstrate this, here’s a method that takes an input parameter named `f`, where `f` is a function:
+
+{% tabs sayHello-definition %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def sayHello(f: () => Unit): Unit = f()
+```
+{% endtab %}
+{% endtabs %}
+
+This portion of the code---the *type signature*---states that `f` is a function, and defines the types of functions the `sayHello` method will accept:
+
+{% tabs sayHello-definition_1 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+f: () => Unit
+```
+{% endtab %}
+{% endtabs %}
+
+Here’s how this works:
+
+- `f` is the name of the function input parameter.
+ It’s just like naming a `String` parameter `s` or an `Int` parameter `i`.
+- The type signature of `f` specifies the *type* of the functions this method will accept.
+- The `()` portion of `f`’s signature (on the left side of the `=>` symbol) states that `f` takes no input parameters.
+- The `Unit` portion of the signature (on the right side of the `=>` symbol) indicates that `f` should not return a meaningful result.
+- Looking back at the body of the `sayHello` method (on the right side of the `=` symbol), the `f()` statement there invokes the function that’s passed in.
+
+Now that we’ve defined `sayHello`, let’s create a function to match `f`’s signature so we can test it.
+The following function takes no input parameters and returns nothing, so it matches `f`’s type signature:
+
+{% tabs helloJoe-definition %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def helloJoe(): Unit = println("Hello, Joe")
+```
+{% endtab %}
+{% endtabs %}
+
+Because the type signatures match, you can pass `helloJoe` into `sayHello`:
+
+{% tabs sayHello-usage %}
+{% tab 'Scala 2 and 3' %}
+```scala
+sayHello(helloJoe) // prints "Hello, Joe"
+```
+{% endtab %}
+{% endtabs %}
+
+If you’ve never done this before, congratulations:
+You just defined a method named `sayHello` that takes a function as an input parameter, and then invokes that function in its method body.
+
+### sayHello can take many functions
+
+It’s important to know that the beauty of this approach is not that `sayHello` can take *one* function as an input parameter; the beauty is that it can take *any* function that matches `f`’s signature.
+For instance, because this next function takes no input parameters and returns nothing, it also works with `sayHello`:
+
+{% tabs bonjourJulien-definition %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def bonjourJulien(): Unit = println("Bonjour, Julien")
+```
+{% endtab %}
+{% endtabs %}
+
+Here it is in the REPL:
+
+{% tabs bonjourJulien-usage %}
+{% tab 'Scala 2 and 3' %}
+````
+scala> sayHello(bonjourJulien)
+Bonjour, Julien
+````
+{% endtab %}
+{% endtabs %}
+
+This is a good start.
+The only thing to do now is see a few more examples of how to define different type signatures for function parameters.
+
+## The general syntax for defining function input parameters
+
+In this method:
+
+{% tabs sayHello-definition-2 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def sayHello(f: () => Unit): Unit
+```
+{% endtab %}
+{% endtabs %}
+
+We noted that the type signature for `f` is:
+
+{% tabs sayHello-definition-2_1 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+() => Unit
+```
+{% endtab %}
+{% endtabs %}
+
+We know that this means, “a function that takes no input parameters and returns nothing meaningful (given by `Unit`).”
+
+To demonstrate more type signature examples, here’s a function that takes a `String` parameter and returns an `Int`:
+
+{% tabs sayHello-definition-2_2 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+f: String => Int
+```
+{% endtab %}
+{% endtabs %}
+
+What kinds of functions take a string and return an integer?
+Functions like “string length” and checksum are two examples.
+
+Similarly, this function takes two `Int` parameters and returns an `Int`:
+
+{% tabs sayHello-definition-2_3 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+f: (Int, Int) => Int
+```
+{% endtab %}
+{% endtabs %}
+
+Can you imagine what sort of functions match that signature?
+
+The answer is that any function that takes two `Int` input parameters and returns an `Int` matches that signature, so all of these “functions” (methods, really) are a match:
+
+{% tabs add-sub-mul-definitions %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def add(a: Int, b: Int): Int = a + b
+def subtract(a: Int, b: Int): Int = a - b
+def multiply(a: Int, b: Int): Int = a * b
+```
+{% endtab %}
+{% endtabs %}
+
+As you can infer from these examples, the general syntax for defining function parameter type signatures is:
+
+{% tabs add-sub-mul-definitions_1 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+variableName: (parameterTypes ...) => returnType
+```
+{% endtab %}
+{% endtabs %}
+
+> Because functional programming is like creating and combining a series of algebraic equations, it’s common to think about types a *lot* when designing functions and applications.
+> You might say that you “think in types.”
+
+## Taking a function parameter along with other parameters
+
+For HOFs to be really useful, they also need some data to work on.
+For a class like `List`, its `map` method already has data to work on: the data in the `List`.
+But for a standalone HOF that doesn’t have its own data, it should also accept data as other input parameters.
+
+For instance, here’s a method named `executeNTimes` that has two input parameters: a function, and an `Int`:
+
+{% tabs executeNTimes-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+def executeNTimes(f: () => Unit, n: Int): Unit =
+ for (i <- 1 to n) f()
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+def executeNTimes(f: () => Unit, n: Int): Unit =
+ for i <- 1 to n do f()
+```
+{% endtab %}
+{% endtabs %}
+
+As the code shows, `executeNTimes` executes the `f` function `n` times.
+Because a simple `for` loop like this has no return value, `executeNTimes` returns `Unit`.
+
+To test `executeNTimes`, define a method that matches `f`’s signature:
+
+{% tabs helloWorld-definition %}
+{% tab 'Scala 2 and 3' %}
+```scala
+// a method of type `() => Unit`
+def helloWorld(): Unit = println("Hello, world")
+```
+{% endtab %}
+{% endtabs %}
+
+Then pass that method into `executeNTimes` along with an `Int`:
+
+{% tabs helloWorld-usage %}
+{% tab 'Scala 2 and 3' %}
+```
+scala> executeNTimes(helloWorld, 3)
+Hello, world
+Hello, world
+Hello, world
+```
+{% endtab %}
+{% endtabs %}
+
+Excellent.
+The `executeNTimes` method executes the `helloWorld` function three times.
+### As many parameters as needed
+
+Your methods can continue to get as complicated as necessary.
+For example, this method takes a function of type `(Int, Int) => Int`, along with two input parameters:
+
+{% tabs executeAndPrint-definition %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def executeAndPrint(f: (Int, Int) => Int, i: Int, j: Int): Unit =
+ println(f(i, j))
+```
+{% endtab %}
+{% endtabs %}
+
+Because these `sum` and `multiply` methods match that type signature, they can be passed into `executeAndPrint` along with two `Int` values:
+
+{% tabs executeAndPrint-usage %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def sum(x: Int, y: Int) = x + y
+def multiply(x: Int, y: Int) = x * y
+
+executeAndPrint(sum, 3, 11) // prints 14
+executeAndPrint(multiply, 3, 9) // prints 27
+```
+{% endtab %}
+{% endtabs %}
+
+## Function type signature consistency
+
+A great thing about learning about Scala’s function type signatures is that the syntax you use to define function input parameters is the same syntax you use to write function literals.
+
+For instance, if you were to write a function that calculates the sum of two integers, you’d write it like this:
+
+{% tabs f-val-definition %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val f: (Int, Int) => Int = (a, b) => a + b
+```
+{% endtab %}
+{% endtabs %}
+
+That code consists of the type signature:
+
+````
+val f: (Int, Int) => Int = (a, b) => a + b
+ -----------------
+````
+
+The input parameters:
+
+````
+val f: (Int, Int) => Int = (a, b) => a + b
+ ------
+````
+
+and the body of the function:
+
+````
+val f: (Int, Int) => Int = (a, b) => a + b
+ -----
+````
+
+Scala’s consistency is shown here, where this function type:
+
+````
+val f: (Int, Int) => Int = (a, b) => a + b
+ -----------------
+````
+
+is the same as the type signature you use to define a function input parameter:
+
+````
+def executeAndPrint(f: (Int, Int) => Int, ...
+ -----------------
+````
+
+Once you’re comfortable with this syntax, you’ll use it to define function parameters, anonymous functions, and function variables, and it becomes easier to read the Scaladoc for higher-order functions.
+
+
+
+[eta_expansion]: {% link _overviews/scala3-book/fun-eta-expansion.md %}
diff --git a/_overviews/scala3-book/fun-intro.md b/_overviews/scala3-book/fun-intro.md
new file mode 100644
index 0000000000..66cb6bad81
--- /dev/null
+++ b/_overviews/scala3-book/fun-intro.md
@@ -0,0 +1,14 @@
+---
+title: Functions
+type: chapter
+description: This chapter looks at all topics related to functions in Scala 3.
+languages: [ru, zh-cn]
+num: 28
+previous-page: methods-summary
+next-page: fun-anonymous-functions
+---
+
+
+Where the previous chapter introduced Scala *methods*, this chapter digs into *functions*.
+The topics that are covered include anonymous functions, partial functions, function variables, and higher-order functions (HOFs), including how to create your own HOFs.
+
diff --git a/_overviews/scala3-book/fun-partial-functions.md b/_overviews/scala3-book/fun-partial-functions.md
new file mode 100644
index 0000000000..fe8aaa50eb
--- /dev/null
+++ b/_overviews/scala3-book/fun-partial-functions.md
@@ -0,0 +1,81 @@
+---
+title: Partial Functions
+type: section
+description: This page shows how to use partial functions in Scala.
+num: 31
+previous-page: fun-function-variables
+next-page: fun-eta-expansion
+---
+
+A partial function is a function that may not be defined for all values of its argument type. In Scala, partial functions
+are unary functions implementing the `PartialFunction[A, B]` trait, where `A` is the argument type and `B` the result type.
+
+To define a partial function, use a `case` identical to those used in `match` expressions:
+
+{% tabs fun-partial-1 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val doubledOdds: PartialFunction[Int, Int] = {
+ case i if i % 2 == 1 => i * 2
+}
+```
+{% endtab %}
+{% endtabs %}
+
+To check if a partial function is defined for an argument, use the `isDefinedAt` method:
+
+{% tabs fun-partial-2 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+doubledOdds.isDefinedAt(3) // true
+doubledOdds.isDefinedAt(4) // false
+```
+{% endtab %}
+{% endtabs %}
+
+Trying to apply a partial function to an argument not belonging to its domain results in `MatchError`:
+
+{% tabs fun-partial-3 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+doubledOdds(4) // Exception in thread "main" scala.MatchError: 4
+```
+{% endtab %}
+{% endtabs %}
+
+### Using partial functions
+
+A partial function can be passed as an argument to a method:
+
+{% tabs fun-partial-4 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val res = List(1, 2, 3).collect({ case i if i % 2 == 1 => i * 2 }) // List(2, 6)
+```
+{% endtab %}
+{% endtabs %}
+
+You can define a default value for arguments not in domain with `applyOrElse`:
+
+{% tabs fun-partial-5 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+doubledOdds.applyOrElse(4, _ + 1) // 5
+```
+{% endtab %}
+{% endtabs %}
+
+Two partial function can be composed with `orElse`, the second function will be applied for arguments where the first
+one is not defined:
+
+{% tabs fun-partial-6 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val incrementedEvens: PartialFunction[Int, Int] = {
+ case i if i % 2 == 0 => i + 1
+}
+
+val res2 = List(1, 2, 3).collect(doubledOdds.orElse(incrementedEvens)) // List(2, 3, 6)
+```
+{% endtab %}
+{% endtabs %}
\ No newline at end of file
diff --git a/_overviews/scala3-book/fun-summary.md b/_overviews/scala3-book/fun-summary.md
new file mode 100644
index 0000000000..50eb480c27
--- /dev/null
+++ b/_overviews/scala3-book/fun-summary.md
@@ -0,0 +1,36 @@
+---
+title: Summary
+type: section
+description: This page provides a summary of the previous 'Functions' sections.
+languages: [ru, zh-cn]
+num: 36
+previous-page: fun-write-method-returns-function
+next-page: packaging-imports
+---
+
+This was a long chapter, so let’s review the key points that are covered.
+
+A higher-order function (HOF) is often defined as a function that takes other functions as input parameters or returns a function as its value.
+In Scala this is possible because functions are first-class values.
+
+Moving through the sections, first you saw:
+
+- You can write anonymous functions as small code fragments
+- You can pass them into the dozens of HOFs (methods) on the collections classes, i.e., methods like `filter`, `map`, etc.
+- With these small code fragments and powerful HOFs, you create a lot of functionality with just a little code
+
+After looking at anonymous functions and HOFs, you saw:
+
+- Function variables are simply anonymous functions that have been bound to a variable
+
+After seeing how to be a *consumer* of HOFs, you then saw how to be a *creator* of HOFs.
+Specifically, you saw:
+
+- How to write methods that take functions as input parameters
+- How to return a function from a method
+
+A beneficial side effect of this chapter is that you saw many examples of how to declare type signatures for functions.
+The benefits of that are that you use that same syntax to define function parameters, anonymous functions, and function variables, and it also becomes easier to read the Scaladoc for higher-order functions like `map`, `filter`, and others.
+
+
+
diff --git a/_overviews/scala3-book/fun-write-map-function.md b/_overviews/scala3-book/fun-write-map-function.md
new file mode 100644
index 0000000000..85fd13b248
--- /dev/null
+++ b/_overviews/scala3-book/fun-write-map-function.md
@@ -0,0 +1,136 @@
+---
+title: Write Your Own map Method
+type: section
+description: This page demonstrates how to create and use higher-order functions in Scala.
+languages: [ru, zh-cn]
+num: 34
+previous-page: fun-hofs
+next-page: fun-write-method-returns-function
+---
+
+
+Now that you’ve seen how to write your own higher-order functions, let’s take a quick look at a more real-world example.
+
+Imagine for a moment that the `List` class doesn’t have its own `map` method, and you want to write your own.
+A good first step when creating functions is to accurately state the problem.
+Focusing only on a `List[Int]`, you state:
+
+> I want to write a `map` method that can be used to apply a function to each element in a `List[Int]` that it’s given, returning the transformed elements as a new list.
+
+Given that statement, you start to write the method signature.
+First, you know that you want to accept a function as a parameter, and that function should transform an `Int` into some type `A`, so you write:
+
+{% tabs map-accept-func-definition %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def map(f: (Int) => A)
+```
+{% endtab %}
+{% endtabs %}
+
+The syntax for using a type parameter requires declaring it in square brackets `[]` before the parameter list, so you add that:
+
+{% tabs map-type-symbol-definition %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def map[A](f: (Int) => A)
+```
+{% endtab %}
+{% endtabs %}
+
+Next, you know that `map` should also accept a `List[Int]`:
+
+{% tabs map-list-int-param-definition %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def map[A](f: (Int) => A, xs: List[Int])
+```
+{% endtab %}
+{% endtabs %}
+
+Finally, you also know that `map` returns a transformed `List` that contains elements of the type `A`:
+
+{% tabs map-with-return-type-definition %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def map[A](f: (Int) => A, xs: List[Int]): List[A] = ???
+```
+{% endtab %}
+{% endtabs %}
+
+That takes care of the method signature.
+Now all you have to do is write the method body.
+A `map` method applies the function it’s given to every element in the list it’s given to produce a new, transformed list.
+One way to do this is with a `for` expression:
+{% tabs for-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+for (x <- xs) yield f(x)
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+for x <- xs yield f(x)
+```
+{% endtab %}
+{% endtabs %}
+
+`for` expressions often make code surprisingly simple, and for our purposes, that ends up being the entire method body.
+
+Putting it together with the method signature, you now have a standalone `map` method that works with a `List[Int]`:
+
+{% tabs map-function class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+def map[A](f: (Int) => A, xs: List[Int]): List[A] =
+ for (x <- xs) yield f(x)
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+def map[A](f: (Int) => A, xs: List[Int]): List[A] =
+ for x <- xs yield f(x)
+```
+{% endtab %}
+{% endtabs %}
+
+
+### Make it generic
+
+As a bonus, notice that the `for` expression doesn’t do anything that depends on the type inside the `List` being `Int`.
+Therefore, you can replace `Int` in the type signature with the type parameter `B`:
+
+{% tabs map-function-full-generic class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+def map[A, B](f: (B) => A, xs: List[B]): List[A] =
+ for (x <- xs) yield f(x)
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+def map[A, B](f: (B) => A, xs: List[B]): List[A] =
+ for x <- xs yield f(x)
+```
+{% endtab %}
+{% endtabs %}
+
+Now you have a `map` method that works with any `List`.
+
+These examples demonstrate that `map` works as desired:
+
+{% tabs map-use-example %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def double(i : Int): Int = i * 2
+map(double, List(1, 2, 3)) // List(2, 4, 6)
+
+def strlen(s: String): Int = s.length
+map(strlen, List("a", "bb", "ccc")) // List(1, 2, 3)
+```
+{% endtab %}
+{% endtabs %}
+
+Now that you’ve seen how to write methods that accept functions as input parameters, let’s look at methods that return functions.
+
+
diff --git a/_overviews/scala3-book/fun-write-method-returns-function.md b/_overviews/scala3-book/fun-write-method-returns-function.md
new file mode 100644
index 0000000000..28c05b9cf2
--- /dev/null
+++ b/_overviews/scala3-book/fun-write-method-returns-function.md
@@ -0,0 +1,245 @@
+---
+title: Creating a Method That Returns a Function
+type: section
+description: This page demonstrates how to create and use higher-order functions in Scala.
+languages: [ru, zh-cn]
+num: 35
+previous-page: fun-write-map-function
+next-page: fun-summary
+---
+
+
+Thanks to Scala’s consistency, writing a method that returns a function is similar to everything you’ve seen in the previous sections.
+For example, imagine that you want to write a `greet` method that returns a function.
+Once again we start with a problem statement:
+
+> I want to create a `greet` method that returns a function.
+> That function will take a string parameter and print it using `println`.
+> To simplify this first example, `greet` won’t take any input parameters; it will just build a function and return it.
+
+Given that statement, you can start building `greet`.
+You know it’s going to be a method:
+
+{% tabs fun-write-method-returns-function-1 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def greet()
+```
+{% endtab %}
+{% endtabs %}
+
+You also know this method will return a function that (a) takes a `String` parameter, and (b) prints that string using `println`.
+Therefore that function has the type, `String => Unit`:
+
+{% tabs fun-write-method-returns-function-2 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def greet(): String => Unit = ???
+ ----------------
+```
+{% endtab %}
+{% endtabs %}
+
+Now you just need a method body.
+You know that the method needs to return a function, and that function takes a `String` and prints it.
+This anonymous function matches that description:
+
+{% tabs fun-write-method-returns-function-3 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+(name: String) => println(s"Hello, $name")
+```
+{% endtab %}
+{% endtabs %}
+
+Now you just return that function from the method:
+
+{% tabs fun-write-method-returns-function-4 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+// a method that returns a function
+def greet(): String => Unit =
+ (name: String) => println(s"Hello, $name")
+```
+{% endtab %}
+{% endtabs %}
+
+Because this method returns a function, you get the function by calling `greet()`.
+This is a good step to do in the REPL because it verifies the type of the new function:
+
+{% tabs fun-write-method-returns-function-5 %}
+{% tab 'Scala 2 and 3' %}
+````
+scala> val greetFunction = greet()
+val greetFunction: String => Unit = Lambda....
+ -----------------------------
+````
+{% endtab %}
+{% endtabs %}
+
+Now you can call `greetFunction`:
+
+{% tabs fun-write-method-returns-function-6 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+greetFunction("Joe") // prints "Hello, Joe"
+```
+{% endtab %}
+{% endtabs %}
+
+Congratulations, you just created a method that returns a function, and then executed that function.
+
+
+
+## Improving the method
+
+Our method would be more useful if you could pass in a greeting, so let’s do that.
+All you have to do is pass the greeting in as a parameter to the `greet` method, and use it in the string inside `println`:
+
+{% tabs fun-write-method-returns-function-7 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def greet(theGreeting: String): String => Unit =
+ (name: String) => println(s"$theGreeting, $name")
+```
+{% endtab %}
+{% endtabs %}
+
+Now when you call your method, the process is more flexible because you can change the greeting.
+This is what it looks like when you create a function from this method:
+
+{% tabs fun-write-method-returns-function-8 %}
+{% tab 'Scala 2 and 3' %}
+````
+scala> val sayHello = greet("Hello")
+val sayHello: String => Unit = Lambda.....
+ ------------------------
+````
+{% endtab %}
+{% endtabs %}
+
+The REPL type signature output shows that `sayHello` is a function that takes a `String` input parameter and returns `Unit` (nothing).
+So now when you give `sayHello` a `String`, it prints the greeting:
+
+{% tabs fun-write-method-returns-function-9 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+sayHello("Joe") // prints "Hello, Joe"
+```
+{% endtab %}
+{% endtabs %}
+
+You can also change the greeting to create new functions, as desired:
+
+{% tabs fun-write-method-returns-function-10 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val sayCiao = greet("Ciao")
+val sayHola = greet("Hola")
+
+sayCiao("Isabella") // prints "Ciao, Isabella"
+sayHola("Carlos") // prints "Hola, Carlos"
+```
+{% endtab %}
+{% endtabs %}
+
+
+
+## A more real-world example
+
+This technique can be even more useful when your method returns one of many possible functions, like a factory that returns custom-built functions.
+
+For instance, imagine that you want to write a method that returns functions that greet people in different languages.
+We’ll limit this to functions that greet in English or French, depending on a parameter that’s passed into the method.
+
+A first thing you know is that you want to create a method that (a) takes a “desired language” as an input, and (b) returns a function as its result.
+Furthermore, because that function prints a string that it’s given, you know it has the type `String => Unit`.
+With that information you write the method signature:
+
+{% tabs fun-write-method-returns-function-11 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def createGreetingFunction(desiredLanguage: String): String => Unit = ???
+```
+{% endtab %}
+{% endtabs %}
+
+Next, because you know that the possible functions you’ll return take a string and print it, you can write two anonymous functions for the English and French languages:
+
+{% tabs fun-write-method-returns-function-12 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+(name: String) => println(s"Hello, $name")
+(name: String) => println(s"Bonjour, $name")
+```
+{% endtab %}
+{% endtabs %}
+
+Inside a method it might be a little more readable if you give those anonymous functions some names, so let’s assign them to two variables:
+
+{% tabs fun-write-method-returns-function-13 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val englishGreeting = (name: String) => println(s"Hello, $name")
+val frenchGreeting = (name: String) => println(s"Bonjour, $name")
+```
+{% endtab %}
+{% endtabs %}
+
+Now all you need to do is (a) return `englishGreeting` if the `desiredLanguage` is English, and (b) return `frenchGreeting` if the `desiredLanguage` is French.
+One way to do that is with a `match` expression:
+
+{% tabs fun-write-method-returns-function-14 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+def createGreetingFunction(desiredLanguage: String): String => Unit = {
+ val englishGreeting = (name: String) => println(s"Hello, $name")
+ val frenchGreeting = (name: String) => println(s"Bonjour, $name")
+ desiredLanguage match {
+ case "english" => englishGreeting
+ case "french" => frenchGreeting
+ }
+}
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+def createGreetingFunction(desiredLanguage: String): String => Unit =
+ val englishGreeting = (name: String) => println(s"Hello, $name")
+ val frenchGreeting = (name: String) => println(s"Bonjour, $name")
+ desiredLanguage match
+ case "english" => englishGreeting
+ case "french" => frenchGreeting
+```
+{% endtab %}
+{% endtabs %}
+
+And that’s the final method.
+Notice that returning a function value from a method is no different than returning a string or integer value.
+
+This is how `createGreetingFunction` builds a French-greeting function:
+
+{% tabs fun-write-method-returns-function-15 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val greetInFrench = createGreetingFunction("french")
+greetInFrench("Jonathan") // prints "Bonjour, Jonathan"
+```
+{% endtab %}
+{% endtabs %}
+
+And this is how it builds an English-greeting function:
+
+{% tabs fun-write-method-returns-function-16 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val greetInEnglish = createGreetingFunction("english")
+greetInEnglish("Joe") // prints "Hello, Joe"
+```
+{% endtab %}
+{% endtabs %}
+
+If you’re comfortable with that code---congratulations---you now know how to write methods that return functions.
+
+
+
diff --git a/_overviews/scala3-book/interacting-with-java.md b/_overviews/scala3-book/interacting-with-java.md
new file mode 100644
index 0000000000..00a3c5aa8a
--- /dev/null
+++ b/_overviews/scala3-book/interacting-with-java.md
@@ -0,0 +1,483 @@
+---
+title: Interacting with Java
+type: chapter
+description: This page demonstrates how Scala code can interact with Java, and how Java code can interact with Scala code.
+languages: [ru, zh-cn]
+num: 73
+previous-page: tools-worksheets
+next-page: scala-for-java-devs
+---
+
+
+## Introduction
+
+This section looks at how to use Java code in Scala, and the opposite, how to use Scala code in Java.
+
+In general, using Java code in Scala is pretty seamless.
+There are only a few points where you’ll want to use Scala utilities to convert Java concepts to Scala, including:
+
+- Java collections classes
+- The Java `Optional` class
+
+Similarly, if you’re writing Java code and want to use Scala concepts, you’ll want to convert Scala collections and the Scala `Option` class.
+
+These following sections demonstrate the most common conversions you’ll need:
+
+- How to use Java collections in Scala
+- How to use Java `Optional` in Scala
+- Extending Java interfaces in Scala
+- How to use Scala collections in Java
+- How to use Scala `Option` in Java
+- How to use Scala traits in Java
+- How to handle Scala methods that throw exceptions in Java code
+- How to use Scala varargs parameters in Java
+- Create alternate names to use Scala methods in Java
+
+Note that the Java examples in this section assume that you’re using Java 11 or newer.
+
+
+
+## How to use Java collections in Scala
+
+When you’re writing Scala code and an API either requires or produces a Java collection class (from the `java.util` package), then it is valid to directly use or create the collection as you would in Java.
+
+However, for idiomatic usage in Scala, such as `for` loops over the collection, or to apply higher-order functions such as `map` and `filter`, you can create a proxy that behaves like a Scala collection.
+
+Here’s an example of how this works.
+Given this API that returns `java.util.List[String]`:
+
+{% tabs foo-definition %}
+{% tab Java %}
+```java
+public interface Foo {
+ static java.util.List getStrings() {
+ return List.of("a", "b", "c");
+ }
+}
+```
+{% endtab %}
+{% endtabs %}
+
+You can convert that Java list to a Scala `Seq`, using the conversion utilities in the Scala `scala.jdk.CollectionConverters` object:
+
+
+{% tabs foo-usage class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+import scala.jdk.CollectionConverters._
+import scala.collection.mutable
+
+def testList() = {
+ println("Using a Java List in Scala")
+ val javaList: java.util.List[String] = Foo.getStrings()
+ val scalaSeq: mutable.Seq[String] = javaList.asScala
+ for (s <- scalaSeq) println(s)
+}
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+import scala.jdk.CollectionConverters.*
+import scala.collection.mutable
+
+def testList() =
+ println("Using a Java List in Scala")
+ val javaList: java.util.List[String] = Foo.getStrings()
+ val scalaSeq: mutable.Seq[String] = javaList.asScala
+ for s <- scalaSeq do println(s)
+```
+{% endtab %}
+{% endtabs %}
+
+In the above code `javaList.asScala` creates a wrapper that adapts a `java.util.List` to Scala's `mutable.Seq` collection.
+
+
+## How to use Java `Optional` in Scala
+
+When you are interacting with an API that uses the `java.util.Optional` class in your Scala code, it is fine to construct and use as in Java.
+
+However, for idiomatic usage in Scala, such as use with `for`, you can convert it to a Scala `Option`.
+
+To demonstrate this, here’s a Java API that returns an `Optional[String]` value:
+
+{% tabs bar-definition %}
+{% tab Java %}
+```java
+public interface Bar {
+ static java.util.Optional optionalString() {
+ return Optional.of("hello");
+ }
+}
+```
+{% endtab %}
+{% endtabs %}
+
+First import all members from the `scala.jdk.OptionConverters` object, and then use the `toScala` method to convert the `Optional` value to a Scala `Option`:
+
+{% tabs bar-usage class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+import java.util.Optional
+import scala.jdk.OptionConverters._
+
+val javaOptString: Optional[String] = Bar.optionalString
+val scalaOptString: Option[String] = javaOptString.toScala
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+import java.util.Optional
+import scala.jdk.OptionConverters.*
+
+val javaOptString: Optional[String] = Bar.optionalString
+val scalaOptString: Option[String] = javaOptString.toScala
+```
+{% endtab %}
+{% endtabs %}
+
+## Extending Java interfaces in Scala
+
+If you need to use Java interfaces in your Scala code, extend them just as though they are Scala traits.
+For example, given these three Java interfaces:
+
+{% tabs animal-definition %}
+{% tab Java %}
+```java
+public interface Animal {
+ void speak();
+}
+
+public interface Wagging {
+ void wag();
+}
+
+public interface Running {
+ // an implemented method
+ default void run() {
+ System.out.println("I’m running");
+ }
+}
+```
+{% endtab %}
+{% endtabs %}
+
+you can create a `Dog` class in Scala just as though you were using traits.
+Because `run` has a default implementation, you only need to implement the `speak` and `wag` methods:
+
+{% tabs animal-usage class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+class Dog extends Animal with Wagging with Running {
+ def speak = println("Woof")
+ def wag = println("Tail is wagging")
+}
+
+def useJavaInterfaceInScala = {
+ val d = new Dog()
+ d.speak
+ d.wag
+ d.run
+}
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+class Dog extends Animal, Wagging, Running:
+ def speak = println("Woof")
+ def wag = println("Tail is wagging")
+
+def useJavaInterfaceInScala =
+ val d = Dog()
+ d.speak
+ d.wag
+ d.run
+```
+{% endtab %}
+{% endtabs %}
+
+Also notice that in Scala, Java methods defined with empty parameter lists can be called either as in Java, `.wag()`, or you can choose to not use parentheses `.wag`.
+
+## How to use Scala collections in Java
+
+When you need to use a Scala collection class in your Java code, use the methods of Scala’s `scala.jdk.javaapi.CollectionConverters` object in your Java code to make the conversions work.
+
+For example, suppose that a Scala API returns a `List[String]` like this:
+
+{% tabs baz-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+object Baz {
+ val strings: List[String] = List("a", "b", "c")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+object Baz:
+ val strings: List[String] = List("a", "b", "c")
+```
+{% endtab %}
+{% endtabs %}
+
+You can access that Scala `List` in your Java code like this:
+
+{% tabs baz-usage %}
+{% tab Java %}
+```java
+import scala.jdk.javaapi.CollectionConverters;
+
+// access the `strings` method with `Baz.strings()`
+scala.collection.immutable.List xs = Baz.strings();
+
+java.util.List listOfStrings = CollectionConverters.asJava(xs);
+
+for (String s: listOfStrings) {
+ System.out.println(s);
+}
+```
+{% endtab %}
+{% endtabs %}
+
+That code can be shortened, but the full steps are shown to demonstrate how the process works.
+Be sure to notice that while `Baz` has a field named `strings`, from Java the field appears as a method, so must be called with parentheses `.strings()`.
+
+
+## How to use Scala `Option` in Java
+
+When you need to use a Scala `Option` in your Java code, you can convert the `Option` to a Java `Optional` value using the `toJava` method of the Scala `scala.jdk.javaapi.OptionConverters` object.
+
+For example, suppose that a Scala API returns an `Option[String]` like this:
+
+{% tabs qux-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+object Qux {
+ val optString: Option[String] = Option("hello")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+object Qux:
+ val optString: Option[String] = Option("hello")
+```
+{% endtab %}
+{% endtabs %}
+
+Then you can access that Scala `Option` in your Java code like this:
+
+{% tabs qux-usage %}
+{% tab Java %}
+```java
+import java.util.Optional;
+import scala.Option;
+import scala.jdk.javaapi.OptionConverters;
+
+Option scalaOptString = Qux.optString();
+Optional javaOptString = OptionConverters.toJava(scalaOptString);
+```
+{% endtab %}
+{% endtabs %}
+
+That code can be shortened, but the full steps are shown to demonstrate how the process works.
+Be sure to notice that while `Qux` has a field named `optString`, from Java the field appears as a method, so must be called with parentheses `.optString()`.
+
+## How to use Scala traits in Java
+
+From Java 8 you can use a Scala trait just like a Java interface, even if the trait has implemented methods.
+For example, given these two Scala traits, one with an implemented method and one with only an interface:
+
+{% tabs scala-trait-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+trait ScalaAddTrait {
+ def sum(x: Int, y: Int) = x + y // implemented
+}
+
+trait ScalaMultiplyTrait {
+ def multiply(x: Int, y: Int): Int // abstract
+}
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+trait ScalaAddTrait:
+ def sum(x: Int, y: Int) = x + y // implemented
+
+trait ScalaMultiplyTrait:
+ def multiply(x: Int, y: Int): Int // abstract
+```
+{% endtab %}
+{% endtabs %}
+
+A Java class can implement both of those interfaces, and define the `multiply` method:
+
+{% tabs scala-trait-usage %}
+{% tab Java %}
+```java
+class JavaMath implements ScalaAddTrait, ScalaMultiplyTrait {
+ public int multiply(int a, int b) {
+ return a * b;
+ }
+}
+
+JavaMath jm = new JavaMath();
+System.out.println(jm.sum(3,4)); // 7
+System.out.println(jm.multiply(3,4)); // 12
+```
+{% endtab %}
+{% endtabs %}
+
+
+
+## How to handle Scala methods that throw exceptions in Java code
+
+When you’re writing Scala code using Scala programming idioms, you’ll never write a method that throws an exception.
+But if for some reason you have a Scala method that does throw an exception, and you want Java developers to be able to use that method, add the `@throws` annotation to your Scala method so Java consumers will know the exceptions it can throw.
+
+For example, this Scala `exceptionThrower` method is annotated to declare that it throws an `Exception`:
+
+{% tabs except-throw-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+object SExceptionThrower {
+ @throws[Exception]
+ def exceptionThrower =
+ throw new Exception("Idiomatic Scala methods don’t throw exceptions")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+object SExceptionThrower:
+ @throws[Exception]
+ def exceptionThrower =
+ throw Exception("Idiomatic Scala methods don’t throw exceptions")
+```
+{% endtab %}
+{% endtabs %}
+
+As a result, you’ll need to handle the exception in your Java code.
+For instance, this code won’t compile because I don’t handle the exception:
+
+{% tabs except-throw-usage %}
+{% tab Java %}
+```java
+// won’t compile because the exception isn’t handled
+public class ScalaExceptionsInJava {
+ public static void main(String[] args) {
+ SExceptionThrower.exceptionThrower();
+ }
+}
+```
+{% endtab %}
+{% endtabs %}
+
+The compiler gives this error:
+
+````plain
+[error] ScalaExceptionsInJava: unreported exception java.lang.Exception;
+ must be caught or declared to be thrown
+[error] SExceptionThrower.exceptionThrower()
+````
+
+This is good---it’s what you want: the annotation tells the Java compiler that `exceptionThrower` can throw an exception.
+Now when you’re writing Java code you must handle the exception with a `try` block or declare that your Java method throws an exception.
+
+Conversely, if you leave the annotation off of the Scala `exceptionThrower` method, the Java code _will compile_.
+This is probably not what you want, because the Java code may not account for the Scala method throwing the exception.
+
+
+
+## How to use Scala varargs parameters in Java
+
+When a Scala method has a varargs parameter and you want to use that method in Java, mark the Scala method with the `@varargs` annotation.
+For example, the `printAll` method in this Scala class declares a `String*` varargs field:
+
+{% tabs vararg-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+import scala.annotation.varargs
+
+object VarargsPrinter {
+ @varargs def printAll(args: String*): Unit = args.foreach(println)
+}
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+import scala.annotation.varargs
+
+object VarargsPrinter:
+ @varargs def printAll(args: String*): Unit = args.foreach(println)
+```
+{% endtab %}
+{% endtabs %}
+
+Because `printAll` is declared with the `@varargs` annotation, it can be called from a Java program with a variable number of parameters, as shown in this example:
+
+{% tabs vararg-usage %}
+{% tab Java %}
+```java
+public class JVarargs {
+ public static void main(String[] args) {
+ VarargsPrinter.printAll("Hello", "world");
+ }
+}
+```
+{% endtab %}
+{% endtabs %}
+
+When this code is run, it results in the following output:
+
+````plain
+Hello
+world
+````
+
+
+
+## Create alternate names to use Scala methods in Java
+
+In Scala you might want to create a method name using a symbolic character:
+
+{% tabs add-definition %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def +(a: Int, b: Int) = a + b
+```
+{% endtab %}
+{% endtabs %}
+
+That method name won’t work well in Java, but what you can do in Scala is provide an “alternate” name for the method with the `targetName` annotation, which will be the name of the method when used from Java:
+
+{% tabs add-2-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+import scala.annotation.targetName
+
+object Adder {
+ @targetName("add") def +(a: Int, b: Int) = a + b
+}
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+import scala.annotation.targetName
+
+object Adder:
+ @targetName("add") def +(a: Int, b: Int) = a + b
+```
+{% endtab %}
+{% endtabs %}
+
+Now in your Java code you can use the aliased method name `add`:
+
+{% tabs add-2-usage %}
+{% tab Java %}
+```java
+int x = Adder.add(1,1);
+System.out.printf("x = %d\n", x);
+```
+{% endtab %}
+{% endtabs %}
diff --git a/_overviews/scala3-book/introduction.md b/_overviews/scala3-book/introduction.md
new file mode 100644
index 0000000000..b3798aeabb
--- /dev/null
+++ b/_overviews/scala3-book/introduction.md
@@ -0,0 +1,33 @@
+---
+title: Introduction
+type: chapter
+description: This page begins the overview documentation of the Scala 3 language.
+languages: [ru, zh-cn]
+num: 1
+previous-page:
+next-page: scala-features
+---
+
+Welcome to the Scala 3 Book.
+The goal of this book is to provide an informal introduction to the Scala language.
+It touches on all Scala topics, in a relatively light manner.
+If at any time while you’re reading this book and want more information on a specific feature, you’ll find links to our [_Reference_ documentation][reference], which covers many new features of the Scala language in more detail.
+
+
+ If you are interested in the archived Scala 2 edition of the book, you
+can access it here. We are currently in the process of
+merging the two books and you can help us.
+
+
+Over the course of this book, we hope to demonstrate that Scala is a beautiful, expressive programming language, with a clean, modern syntax, which supports functional programming (FP) and object-oriented programming (OOP), and that provides a safe static type system.
+Scala’s syntax, grammar, and features have been re-thought, debated in an open process, and updated in 2020 to be clearer and easier to understand than ever before.
+
+The book begins with a whirlwind tour of many of Scala’s features in the [“A Taste of Scala” section][taste].
+After that tour, the sections that follow it provide more details on those language features.
+
+## A bit of background
+
+Scala was created by [Martin Odersky](https://en.wikipedia.org/wiki/Martin_Odersky), who studied under [Niklaus Wirth](https://en.wikipedia.org/wiki/Niklaus_Wirth), who created Pascal and several other languages. Mr. Odersky is one of the co-designers of Generic Java, and is also known as the “father” of the `javac` compiler.
+
+[reference]: {{ site.scala3ref }}/overview.html
+[taste]: {% link _overviews/scala3-book/taste-intro.md %}
diff --git a/_overviews/scala3-book/methods-intro.md b/_overviews/scala3-book/methods-intro.md
new file mode 100644
index 0000000000..59e91c3c6c
--- /dev/null
+++ b/_overviews/scala3-book/methods-intro.md
@@ -0,0 +1,20 @@
+---
+title: Methods
+type: chapter
+description: This section introduces methods in Scala 3.
+languages: [ru, zh-cn]
+num: 24
+previous-page: domain-modeling-fp
+next-page: methods-most
+---
+
+
+In Scala 2, _methods_ can be defined inside classes, traits, objects, case classes, and case objects.
+But it gets better: In Scala 3 they can also be defined _outside_ any of those constructs; we say that they are "top-level" definitions, since they are not nested in another definition.
+In short, methods can now be defined anywhere.
+
+Many features of methods are demonstrated in the next section.
+Because `main` methods require a little more explanation, they’re described in the separate section that follows.
+
+
+
diff --git a/_overviews/scala3-book/methods-main-methods.md b/_overviews/scala3-book/methods-main-methods.md
new file mode 100644
index 0000000000..78071efb49
--- /dev/null
+++ b/_overviews/scala3-book/methods-main-methods.md
@@ -0,0 +1,186 @@
+---
+title: Main Methods in Scala 3
+type: section
+description: This page describes how 'main' methods and the '@main' annotation work in Scala 3.
+languages: [ru, zh-cn]
+num: 26
+previous-page: methods-most
+next-page: methods-summary
+scala3: true
+versionSpecific: true
+---
+
+
Writing one line programs
+
+Scala 3 offers a new way to define programs that can be invoked from the command line: Adding a `@main` annotation to a method turns it into entry point of an executable program:
+
+{% tabs method_1 %}
+{% tab 'Scala 3 Only' for=method_1 %}
+
+```scala
+@main def hello() = println("Hello, World")
+```
+
+{% endtab %}
+{% endtabs %}
+
+To run this program, save the line of code in a file named as e.g. *Hello.scala*---the filename doesn’t have to match the method name---and run it with `scala`:
+
+```bash
+$ scala run Hello.scala
+Hello, World
+```
+
+A `@main` annotated method can be written either at the top-level (as shown), or inside a statically accessible object.
+In either case, the name of the program is in each case the name of the method, without any object prefixes.
+
+Learn more about the `@main` annotation by reading the following sections, or by watching this video:
+
+
+
+
+
+### Command line arguments
+
+With this approach your `@main` method can handle command line arguments, and those arguments can have different types.
+For example, given this `@main` method that takes an `Int`, a `String`, and a varargs `String*` parameter:
+
+{% tabs method_2 %}
+{% tab 'Scala 3 Only' for=method_2 %}
+
+```scala
+@main def happyBirthday(age: Int, name: String, others: String*) =
+ val suffix = (age % 100) match
+ case 11 | 12 | 13 => "th"
+ case _ => (age % 10) match
+ case 1 => "st"
+ case 2 => "nd"
+ case 3 => "rd"
+ case _ => "th"
+
+ val sb = StringBuilder(s"Happy $age$suffix birthday, $name")
+ for other <- others do sb.append(" and ").append(other)
+ println(sb.toString)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Pass the arguments after `--`:
+
+```
+$ scala run happyBirthday.scala -- 23 Lisa Peter
+Happy 23rd Birthday, Lisa and Peter!
+```
+
+As shown, the `@main` method can have an arbitrary number of parameters.
+For each parameter type there must be a [given instance]({% link _overviews/scala3-book/ca-context-parameters.md %}) of the `scala.util.CommandLineParser.FromString` type class that converts an argument `String` to the required parameter type.
+Also as shown, a main method’s parameter list can end in a repeated parameter like `String*` that takes all remaining arguments given on the command line.
+
+The program implemented from an `@main` method checks that there are enough arguments on the command line to fill in all parameters, and that the argument strings can be converted to the required types.
+If a check fails, the program is terminated with an error message:
+
+```
+$ scala run happyBirthday.scala -- 22
+Illegal command line after first argument: more arguments expected
+
+$ scala run happyBirthday.scala -- sixty Fred
+Illegal command line: java.lang.NumberFormatException: For input string: "sixty"
+```
+
+## User-defined types as parameters
+
+As mentioned up above, the compiler looks for a given instance of the
+`scala.util.CommandLineParser.FromString` typeclass for the type of the
+argument. For example, let's say you have a custom `Color` type that you want to
+use as a parameter. You would do this like you see below:
+
+{% tabs method_3 %}
+{% tab 'Scala 3 Only' for=method_3 %}
+
+```scala
+enum Color:
+ case Red, Green, Blue
+
+given CommandLineParser.FromString[Color] with
+ def fromString(value: String): Color = Color.valueOf(value)
+
+@main def run(color: Color): Unit =
+ println(s"The color is ${color.toString}")
+```
+
+{% endtab %}
+{% endtabs %}
+
+This works the same for your own user types in your program as well as types you
+might be using from another library.
+
+## The details
+
+The Scala compiler generates a program from an `@main` method `f` as follows:
+
+- It creates a class named `f` in the package where the `@main` method was found.
+- The class has a static method `main` with the usual signature of a Java `main` method: it takes an `Array[String]` as argument and returns `Unit`.
+- The generated `main` method calls method `f` with arguments converted using methods in the `scala.util.CommandLineParser.FromString` object.
+
+For instance, the `happyBirthday` method above generates additional code equivalent to the following class:
+
+{% tabs method_4 %}
+{% tab 'Scala 3 Only' for=method_4 %}
+
+```scala
+final class happyBirthday {
+ import scala.util.{CommandLineParser as CLP}
+ def main(args: Array[String]): Unit =
+ try
+ happyBirthday(
+ CLP.parseArgument[Int](args, 0),
+ CLP.parseArgument[String](args, 1),
+ CLP.parseRemainingArguments[String](args, 2)*)
+ catch {
+ case error: CLP.ParseError => CLP.showError(error)
+ }
+}
+```
+
+> **Note**: In this generated code, the `` modifier expresses that the `main` method is generated as a static method of class `happyBirthday`.
+> This feature is not available for user programs in Scala.
+> Regular “static” members are generated in Scala using objects instead.
+
+{% endtab %}
+{% endtabs %}
+
+## Backwards Compatibility with Scala 2
+
+`@main` methods are the recommended way to generate programs that can be invoked from the command line in Scala 3.
+They replace the previous approach in Scala 2, which was to create an `object` that extends the `App` class:
+
+The previous functionality of `App`, which relied on the “magic” `DelayedInit` trait, is no longer available.
+`App` still exists in limited form for now, but it doesn’t support command line arguments and will be deprecated in the future.
+
+If programs need to cross-build between Scala 2 and Scala 3, it’s recommended to use an `object` with an explicit `main` method and a single `Array[String]` argument instead:
+
+{% tabs method_5 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+object happyBirthday {
+ private def happyBirthday(age: Int, name: String, others: String*) = {
+ ... // same as before
+ }
+ def main(args: Array[String]): Unit =
+ happyBirthday(args(0).toInt, args(1), args.drop(2).toIndexedSeq:_*)
+}
+```
+
+> note that here we use `:_*` to pass a vararg argument, which remains in Scala 3 for backwards compatibility.
+
+{% endtab %}
+{% endtabs %}
+
+If you place that code in a file named *happyBirthday.scala*, you can then compile and run it with `scala`, as shown previously:
+
+```bash
+$ scala run happyBirthday.scala -- 23 Lisa Peter
+Happy 23rd Birthday, Lisa and Peter!
+```
diff --git a/_overviews/scala3-book/methods-most.md b/_overviews/scala3-book/methods-most.md
new file mode 100644
index 0000000000..2a282cdf28
--- /dev/null
+++ b/_overviews/scala3-book/methods-most.md
@@ -0,0 +1,702 @@
+---
+title: Method Features
+type: section
+description: This section introduces Scala 3 methods, including main methods, extension methods, and more.
+languages: [ru, zh-cn]
+num: 25
+previous-page: methods-intro
+next-page: methods-main-methods
+---
+
+This section introduces the various aspects of how to define and call methods in Scala 3.
+
+## Defining Methods
+
+Scala methods have many features, including these:
+
+- Type parameters
+- Default parameter values
+- Multiple parameter groups
+- Context-provided parameters
+- By-name parameters
+- and more...
+
+Some of these features are demonstrated in this section, but when you’re defining a “simple” method that doesn’t use those features, the syntax looks like this:
+
+{% tabs method_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_1 %}
+
+```scala
+def methodName(param1: Type1, param2: Type2): ReturnType = {
+ // the method body
+ // goes here
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_1 %}
+
+```scala
+def methodName(param1: Type1, param2: Type2): ReturnType =
+ // the method body
+ // goes here
+end methodName // this is optional
+```
+
+{% endtab %}
+{% endtabs %}
+
+In that syntax:
+
+- The keyword `def` is used to define a method
+- The Scala standard is to name methods using the camel case convention
+- Method parameters are always defined with their type
+- Declaring the method return type is optional
+- Methods can consist of many lines, or just one line
+- Providing the `end methodName` portion after the method body is also optional, and is only recommended for long methods
+
+Here are two examples of a one-line method named `add` that takes two `Int` input parameters.
+The first version explicitly shows the method’s `Int` return type, and the second does not:
+
+{% tabs method_2 %}
+{% tab 'Scala 2 and 3' for=method_2 %}
+
+```scala
+def add(a: Int, b: Int): Int = a + b
+def add(a: Int, b: Int) = a + b
+```
+
+{% endtab %}
+{% endtabs %}
+
+It is recommended to annotate publicly visible methods with their return type.
+Declaring the return type can make it easier to understand it when you look at it months or years later, or when you look at another person’s code.
+
+## Calling methods
+
+Invoking a method is straightforward:
+
+{% tabs method_3 %}
+{% tab 'Scala 2 and 3' for=method_3 %}
+
+```scala
+val x = add(1, 2) // 3
+```
+
+{% endtab %}
+{% endtabs %}
+
+The Scala collections classes have dozens of built-in methods.
+These examples show how to call them:
+
+{% tabs method_4 %}
+{% tab 'Scala 2 and 3' for=method_4 %}
+
+```scala
+val x = List(1, 2, 3)
+
+x.size // 3
+x.contains(1) // true
+x.map(_ * 10) // List(10, 20, 30)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Notice:
+
+- `size` takes no arguments, and returns the number of elements in the list
+- The `contains` method takes one argument, the value to search for
+- `map` takes one argument, a function; in this case an anonymous function is passed into it
+
+## Multiline methods
+
+When a method is longer than one line, start the method body on the second line, indented to the right:
+
+{% tabs method_5 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_5 %}
+
+```scala
+def addThenDouble(a: Int, b: Int): Int = {
+ // imagine that this body requires multiple lines
+ val sum = a + b
+ sum * 2
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_5 %}
+
+```scala
+def addThenDouble(a: Int, b: Int): Int =
+ // imagine that this body requires multiple lines
+ val sum = a + b
+ sum * 2
+```
+
+{% endtab %}
+{% endtabs %}
+
+In that method:
+
+- `sum` is an immutable local variable; it can’t be accessed outside of the method
+- The last line doubles the value of `sum`; this value is returned from the method
+
+When you paste that code into the REPL, you’ll see that it works as desired:
+
+{% tabs method_6 %}
+{% tab 'Scala 2 and 3' for=method_6 %}
+
+```scala
+scala> addThenDouble(1, 1)
+res0: Int = 4
+```
+
+{% endtab %}
+{% endtabs %}
+
+Notice that there’s no need for a `return` statement at the end of the method.
+Because almost everything in Scala is an _expression_---meaning that each line of code returns (or _evaluates to_) a value---there’s no need to use `return`.
+
+This becomes more clear when you condense that method and write it on one line:
+
+{% tabs method_7 %}
+{% tab 'Scala 2 and 3' for=method_7 %}
+
+```scala
+def addThenDouble(a: Int, b: Int): Int = (a + b) * 2
+```
+
+{% endtab %}
+{% endtabs %}
+
+The body of a method can use all the different features of the language:
+
+- `if`/`else` expressions
+- `match` expressions
+- `while` loops
+- `for` loops and `for` expressions
+- Variable assignments
+- Calls to other methods
+- Definitions of other methods
+
+As an example of a real-world multiline method, this `getStackTraceAsString` method converts its `Throwable` input parameter into a well-formatted `String`:
+
+{% tabs method_8 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_8 %}
+
+```scala
+def getStackTraceAsString(t: Throwable): String = {
+ val sw = new StringWriter()
+ t.printStackTrace(new PrintWriter(sw))
+ sw.toString
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_8 %}
+
+```scala
+def getStackTraceAsString(t: Throwable): String =
+ val sw = StringWriter()
+ t.printStackTrace(PrintWriter(sw))
+ sw.toString
+```
+
+{% endtab %}
+{% endtabs %}
+
+In that method:
+
+- The first line assigns a new instance of `StringWriter` to the value binder `sw`
+- The second line stores the stack trace content into the `StringWriter`
+- The third line yields the `String` representation of the stack trace
+
+## Default parameter values
+
+Method parameters can have default values.
+In this example, default values are given for both the `timeout` and `protocol` parameters:
+
+{% tabs method_9 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_9 %}
+
+```scala
+def makeConnection(timeout: Int = 5_000, protocol: String = "http") = {
+ println(f"timeout = ${timeout}%d, protocol = ${protocol}%s")
+ // more code here ...
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_9 %}
+
+```scala
+def makeConnection(timeout: Int = 5_000, protocol: String = "http") =
+ println(f"timeout = ${timeout}%d, protocol = ${protocol}%s")
+ // more code here ...
+```
+
+{% endtab %}
+{% endtabs %}
+
+Because the parameters have default values, the method can be called in these ways:
+
+{% tabs method_10 %}
+{% tab 'Scala 2 and 3' for=method_10 %}
+
+```scala
+makeConnection() // timeout = 5000, protocol = http
+makeConnection(2_000) // timeout = 2000, protocol = http
+makeConnection(3_000, "https") // timeout = 3000, protocol = https
+```
+
+{% endtab %}
+{% endtabs %}
+
+Here are a few key points about those examples:
+
+- In the first example no arguments are provided, so the method uses the default parameter values of `5_000` and `http`
+- In the second example, `2_000` is supplied for the `timeout` value, so it’s used, along with the default value for the `protocol`
+- In the third example, values are provided for both parameters, so they’re both used
+
+Notice that by using default parameter values, it appears to the consumer that they can use three different overridden methods.
+
+## Named parameters
+
+If you prefer, you can also use the names of the method parameters when calling a method.
+For instance, `makeConnection` can also be called in these ways:
+
+{% tabs method_11 %}
+{% tab 'Scala 2 and 3' for=method_11 %}
+
+```scala
+makeConnection(timeout=10_000)
+makeConnection(protocol="https")
+makeConnection(timeout=10_000, protocol="https")
+makeConnection(protocol="https", timeout=10_000)
+```
+
+{% endtab %}
+{% endtabs %}
+
+In some frameworks named parameters are heavily used.
+They’re also very useful when multiple method parameters have the same type:
+
+{% tabs method_12 %}
+{% tab 'Scala 2 and 3' for=method_12 %}
+
+```scala
+engage(true, true, true, false)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Without help from an IDE that code can be hard to read, but this code is much more clear and obvious:
+
+{% tabs method_13 %}
+{% tab 'Scala 2 and 3' for=method_13 %}
+
+```scala
+engage(
+ speedIsSet = true,
+ directionIsSet = true,
+ picardSaidMakeItSo = true,
+ turnedOffParkingBrake = false
+)
+```
+
+{% endtab %}
+{% endtabs %}
+
+## A suggestion about methods that take no parameters
+
+When a method takes no parameters, it’s said to have an _arity_ level of _arity-0_.
+Similarly, when a method takes one parameter it’s an _arity-1_ method.
+When you create arity-0 methods:
+
+- If the method performs side effects, such as calling `println`, declare the method with empty parentheses
+- If the method does not perform side effects---such as getting the size of a collection, which is similar to accessing a field on the collection---leave the parentheses off
+
+For example, this method performs a side effect, so it’s declared with empty parentheses:
+
+{% tabs method_14 %}
+{% tab 'Scala 2 and 3' for=method_14 %}
+
+```scala
+def speak() = println("hi")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Doing this requires callers of the method to use open parentheses when calling the method:
+
+{% tabs method_15 %}
+{% tab 'Scala 2 and 3' for=method_15 %}
+
+```scala
+speak // error: "method speak must be called with () argument"
+speak() // prints "hi"
+```
+
+{% endtab %}
+{% endtabs %}
+
+While this is just a convention, following it dramatically improves code readability: It makes it easier to understand at a glance that an arity-0 method performs side effects.
+
+{% comment %}
+Some of that wording comes from this page: https://docs.scala-lang.org/style/method-invocation.html
+{% endcomment %}
+
+## Using `if` as a method body
+
+Because `if`/`else` expressions return a value, they can be used as the body of a method.
+Here’s a method named `isTruthy` that implements the Perl definitions of `true` and `false`:
+
+{% tabs method_16 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_16 %}
+
+```scala
+def isTruthy(a: Any) = {
+ if (a == 0 || a == "" || a == false)
+ false
+ else
+ true
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_16 %}
+
+```scala
+def isTruthy(a: Any) =
+ if a == 0 || a == "" || a == false then
+ false
+ else
+ true
+```
+
+{% endtab %}
+{% endtabs %}
+
+These examples show how that method works:
+
+{% tabs method_17 %}
+{% tab 'Scala 2 and 3' for=method_17 %}
+
+```scala
+isTruthy(0) // false
+isTruthy("") // false
+isTruthy("hi") // true
+isTruthy(1.0) // true
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Using `match` as a method body
+
+A `match` expression can also be used as the entire method body, and often is.
+Here’s another version of `isTruthy`, written with a `match` expression :
+
+{% tabs method_18 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_18 %}
+
+```scala
+def isTruthy(a: Any) = a match {
+ case 0 | "" | false => false
+ case _ => true
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_18 %}
+
+```scala
+def isTruthy(a: Matchable) = a match
+ case 0 | "" | false => false
+ case _ => true
+```
+
+> This method works just like the previous method that used an `if`/`else` expression. We use `Matchable` instead of `Any` as the parameter's type to accept any value that supports pattern matching.
+
+> For more details on the `Matchable` trait, see the [Reference documentation][reference_matchable].
+
+[reference_matchable]: {{ site.scala3ref }}/other-new-features/matchable.html
+{% endtab %}
+{% endtabs %}
+
+## Controlling visibility in classes
+
+In classes, objects, traits, and enums, Scala methods are public by default, so the `Dog` instance created here can access the `speak` method:
+
+{% tabs method_19 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_19 %}
+
+```scala
+class Dog {
+ def speak() = println("Woof")
+}
+
+val d = new Dog
+d.speak() // prints "Woof"
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_19 %}
+
+```scala
+class Dog:
+ def speak() = println("Woof")
+
+val d = new Dog
+d.speak() // prints "Woof"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Methods can also be marked as `private`.
+This makes them private to the current class, so they can’t be called nor overridden in subclasses:
+
+{% tabs method_20 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_20 %}
+
+```scala
+class Animal {
+ private def breathe() = println("I’m breathing")
+}
+
+class Cat extends Animal {
+ // this method won’t compile
+ override def breathe() = println("Yo, I’m totally breathing")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_20 %}
+
+```scala
+class Animal:
+ private def breathe() = println("I’m breathing")
+
+class Cat extends Animal:
+ // this method won’t compile
+ override def breathe() = println("Yo, I’m totally breathing")
+```
+
+{% endtab %}
+{% endtabs %}
+
+If you want to make a method private to the current class and also allow subclasses to call it or override it, mark the method as `protected`, as shown with the `speak` method in this example:
+
+{% tabs method_21 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_21 %}
+
+```scala
+class Animal {
+ private def breathe() = println("I’m breathing")
+ def walk() = {
+ breathe()
+ println("I’m walking")
+ }
+ protected def speak() = println("Hello?")
+}
+
+class Cat extends Animal {
+ override def speak() = println("Meow")
+}
+
+val cat = new Cat
+cat.walk()
+cat.speak()
+cat.breathe() // won’t compile because it’s private
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_21 %}
+
+```scala
+class Animal:
+ private def breathe() = println("I’m breathing")
+ def walk() =
+ breathe()
+ println("I’m walking")
+ protected def speak() = println("Hello?")
+
+class Cat extends Animal:
+ override def speak() = println("Meow")
+
+val cat = new Cat
+cat.walk()
+cat.speak()
+cat.breathe() // won’t compile because it’s private
+```
+
+{% endtab %}
+{% endtabs %}
+
+The `protected` setting means:
+
+- The method (or field) can be accessed by other instances of the same class
+- It is not visible by other code in the current package
+- It is available to subclasses
+
+## Objects can contain methods
+
+Earlier you saw that traits and classes can have methods.
+The Scala `object` keyword is used to create a singleton class, and an object can also contain methods.
+This is a nice way to group a set of “utility” methods.
+For instance, this object contains a collection of methods that work on strings:
+
+{% tabs method_22 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_22 %}
+
+```scala
+object StringUtils {
+
+ /**
+ * Returns a string that is the same as the input string, but
+ * truncated to the specified length.
+ */
+ def truncate(s: String, length: Int): String = s.take(length)
+
+ /**
+ * Returns true if the string contains only letters and numbers.
+ */
+ def lettersAndNumbersOnly_?(s: String): Boolean =
+ s.matches("[a-zA-Z0-9]+")
+
+ /**
+ * Returns true if the given string contains any whitespace
+ * at all. Assumes that `s` is not null.
+ */
+ def containsWhitespace(s: String): Boolean =
+ s.matches(".*\\s.*")
+
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_22 %}
+
+```scala
+object StringUtils:
+
+ /**
+ * Returns a string that is the same as the input string, but
+ * truncated to the specified length.
+ */
+ def truncate(s: String, length: Int): String = s.take(length)
+
+ /**
+ * Returns true if the string contains only letters and numbers.
+ */
+ def lettersAndNumbersOnly_?(s: String): Boolean =
+ s.matches("[a-zA-Z0-9]+")
+
+ /**
+ * Returns true if the given string contains any whitespace
+ * at all. Assumes that `s` is not null.
+ */
+ def containsWhitespace(s: String): Boolean =
+ s.matches(".*\\s.*")
+
+end StringUtils
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Extension methods
+
+There are many situations where you would like to add functionality to closed classes.
+For example, imagine that you have a `Circle` class, but you can’t change its source code.
+It could be defined like this in a third-party library:
+
+{% tabs method_23 %}
+{% tab 'Scala 2 and 3' for=method_23 %}
+
+```scala
+case class Circle(x: Double, y: Double, radius: Double)
+```
+
+{% endtab %}
+{% endtabs %}
+
+When you want to add methods to this class, you can define them as extension methods, like this:
+
+{% tabs method_24 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_24 %}
+
+```scala
+implicit class CircleOps(c: Circle) {
+ def circumference: Double = c.radius * math.Pi * 2
+ def diameter: Double = c.radius * 2
+ def area: Double = math.Pi * c.radius * c.radius
+}
+```
+In Scala 2 use an `implicit class`, find out more details [here](/overviews/core/implicit-classes.html).
+
+{% endtab %}
+{% tab 'Scala 3' for=method_24 %}
+
+```scala
+extension (c: Circle)
+ def circumference: Double = c.radius * math.Pi * 2
+ def diameter: Double = c.radius * 2
+ def area: Double = math.Pi * c.radius * c.radius
+```
+In Scala 3 use the new `extension` construct. For more details see chapters in [this book][extension], or the [Scala 3 reference][reference-ext].
+
+[reference-ext]: {{ site.scala3ref }}/contextual/extension-methods.html
+[extension]: {% link _overviews/scala3-book/ca-extension-methods.md %}
+{% endtab %}
+{% endtabs %}
+
+Now when you have a `Circle` instance named `aCircle`, you can call those methods like this:
+
+{% tabs method_25 %}
+{% tab 'Scala 2 and 3' for=method_25 %}
+
+```scala
+aCircle.circumference
+aCircle.diameter
+aCircle.area
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Even more
+
+There’s even more to know about methods, including how to:
+
+- Call methods on superclasses
+- Define and use by-name parameters
+- Write a method that takes a function parameter
+- Create inline methods
+- Handle exceptions
+- Use vararg input parameters
+- Write methods that have multiple parameter groups (partially-applied functions)
+- Create methods that have type parameters
+
+{% comment %}
+Jamie: there really needs better linking here - previously it was to the Scala 3 Reference, which doesnt cover any
+of this
+{% endcomment %}
+See the other chapters in this book for more details on these features.
+
+[reference_extension_methods]: {{ site.scala3ref }}/contextual/extension-methods.html
+[reference_matchable]: {{ site.scala3ref }}/other-new-features/matchable.html
diff --git a/_overviews/scala3-book/methods-summary.md b/_overviews/scala3-book/methods-summary.md
new file mode 100644
index 0000000000..eafac85889
--- /dev/null
+++ b/_overviews/scala3-book/methods-summary.md
@@ -0,0 +1,27 @@
+---
+title: Summary
+type: section
+description: This section summarizes the previous sections on Scala 3 methods.
+languages: [ru, zh-cn]
+num: 27
+previous-page: methods-main-methods
+next-page: fun-intro
+---
+
+
+There’s even more to know about methods, including how to:
+
+- Call methods on superclasses
+- Define and use by-name parameters
+- Write a method that takes a function parameter
+- Create inline methods
+- Handle exceptions
+- Use vararg input parameters
+- Write methods that have multiple parameter groups (partially-applied functions)
+- Create methods that have type parameters
+
+See the [Reference documentation][reference] for more details on these features.
+
+
+
+[reference]: {{ site.scala3ref }}/overview.html
diff --git a/_overviews/scala3-book/packaging-imports.md b/_overviews/scala3-book/packaging-imports.md
new file mode 100644
index 0000000000..f5665c28fa
--- /dev/null
+++ b/_overviews/scala3-book/packaging-imports.md
@@ -0,0 +1,629 @@
+---
+title: Packaging and Imports
+type: chapter
+description: A discussion of using packages and imports to organize your code, build related modules of code, control scope, and help prevent namespace collisions.
+languages: [ru, zh-cn]
+num: 37
+previous-page: fun-summary
+next-page: collections-intro
+---
+
+
+Scala uses *packages* to create namespaces that let you modularize programs and help prevent namespace collisions.
+Scala supports the package-naming style used by Java, and also the “curly brace” namespace notation used by languages like C++ and C#.
+
+The Scala approach to importing members is also similar to Java, and more flexible.
+With Scala you can:
+
+- Import packages, classes, objects, traits, and methods
+- Place import statements anywhere
+- Hide and rename members when you import them
+
+These features are demonstrated in the following examples.
+
+## Creating a package
+
+Packages are created by declaring one or more package names at the top of a Scala file.
+For example, when your domain name is _acme.com_ and you’re working in the _model_ package of an application named _myapp_, your package declaration looks like this:
+
+{% tabs packaging-imports-1 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+package com.acme.myapp.model
+
+class Person ...
+```
+{% endtab %}
+{% endtabs %}
+
+By convention, package names should be all lower case, and the formal naming convention is *\.\.\.\*.
+
+Although it’s not required, package names typically follow directory structure names, so if you follow this convention, a `Person` class in this project will be found in a *MyApp/src/main/scala/com/acme/myapp/model/Person.scala* file.
+
+### Using multiple packages in the same file
+
+The syntax shown above applies to the entire source file: all the definitions in the file
+`Person.scala` belong to package `com.acme.myapp.model`, according to the package clause
+at the beginning of the file.
+
+Alternatively, it is possible to write package clauses that apply only to the definitions
+they contain:
+
+{% tabs packaging-imports-0 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+package users {
+
+ package administrators { // the full name of this package is users.administrators
+ class AdminUser // the full name of this class users.administrators.AdminUser
+ }
+ package normalusers { // the full name of this package is users.normalusers
+ class NormalUser // the full name of this class is users.normalusers.NormalUser
+ }
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+package users:
+
+ package administrators: // the full name of this package is users.administrators
+ class AdminUser // the full name of this class is users.administrators.AdminUser
+
+ package normalusers: // the full name of this package is users.normalusers
+ class NormalUser // the full name of this class is users.normalusers.NormalUser
+```
+{% endtab %}
+{% endtabs %}
+
+Note that the package names are followed by a colon, and that the definitions within
+a package are indented.
+
+The advantages of this approach are that it allows for package nesting, and provides more obvious control of scope and encapsulation, especially within the same file.
+
+## Import statements, Part 1
+
+Import statements are used to access entities in other packages.
+Import statements fall into two main categories:
+
+- Importing classes, traits, objects, functions, and methods
+- Importing `given` clauses
+
+If you’re used to a language like Java, the first class of import statements is similar to what Java uses, with a slightly different syntax that allows for more flexibility.
+These examples demonstrate some of that flexibility:
+
+{% tabs packaging-imports-2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+import users._ // import everything from the `users` package
+import users.User // import only the `User` class
+import users.{User, UserPreferences} // import only two selected members
+import users.{UserPreferences => UPrefs} // rename a member as you import it
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=packaging-imports-2 %}
+
+```scala
+import users.* // import everything from the `users` package
+import users.User // import only the `User` class
+import users.{User, UserPreferences} // import only two selected members
+import users.{UserPreferences as UPrefs} // rename a member as you import it
+```
+
+{% endtab %}
+{% endtabs %}
+
+Those examples are meant to give you a taste of how the first class of `import` statements work.
+They’re explained more in the subsections that follow.
+
+Import statements are also used to import `given` instances into scope.
+Those are discussed at the end of this chapter.
+
+A note before moving on:
+
+> Import clauses are not required for accessing members of the same package.
+
+### Importing one or more members
+
+In Scala you can import one member from a package like this:
+
+{% tabs packaging-imports-3 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+import scala.concurrent.Future
+```
+{% endtab %}
+{% endtabs %}
+
+and multiple members like this:
+
+{% tabs packaging-imports-4 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+import scala.concurrent.Future
+import scala.concurrent.Promise
+import scala.concurrent.blocking
+```
+{% endtab %}
+{% endtabs %}
+
+When importing multiple members, you can import them more concisely like this:
+
+{% tabs packaging-imports-5 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+import scala.concurrent.{Future, Promise, blocking}
+```
+{% endtab %}
+{% endtabs %}
+
+When you want to import everything from the *scala.concurrent* package, use this syntax:
+
+{% tabs packaging-imports-6 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+import scala.concurrent._
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=packaging-imports-6 %}
+
+```scala
+import scala.concurrent.*
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Renaming members on import
+
+Sometimes it can help to rename entities when you import them to avoid name collisions.
+For instance, if you want to use the Scala `List` class and also the *java.util.List* class at the same time, you can rename the *java.util.List* class when you import it:
+
+{% tabs packaging-imports-7 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+import java.util.{List => JavaList}
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=packaging-imports-7 %}
+
+```scala
+import java.util.{List as JavaList}
+```
+{% endtab %}
+{% endtabs %}
+
+Now you use the name `JavaList` to refer to that class, and use `List` to refer to the Scala list class.
+
+You can also rename multiple members at one time using this syntax:
+
+{% tabs packaging-imports-8 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+import java.util.{Date => JDate, HashMap => JHashMap, _}
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=packaging-imports-8 %}
+
+```scala
+import java.util.{Date as JDate, HashMap as JHashMap, *}
+```
+
+{% endtab %}
+{% endtabs %}
+
+That line of code says, “Rename the `Date` and `HashMap` classes as shown, and import everything else in the _java.util_ package without renaming any other members.”
+
+### Hiding members on import
+
+You can also *hide* members during the import process.
+This `import` statement hides the *java.util.Random* class, while importing everything else in the *java.util* package:
+
+{% tabs packaging-imports-9 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+import java.util.{Random => _, _}
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=packaging-imports-9 %}
+
+```scala
+import java.util.{Random as _, *}
+```
+{% endtab %}
+{% endtabs %}
+
+If you try to access the `Random` class it won’t work, but you can access all other members from that package:
+
+{% tabs packaging-imports-10 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val r = new Random // won’t compile
+new ArrayList // works
+```
+{% endtab %}
+{% endtabs %}
+
+#### Hiding multiple members
+
+To hide multiple members during the import process, list them before using the final wildcard import:
+
+{% tabs packaging-imports-11 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+import java.util.{List => _, Map => _, Set => _, _}
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=packaging-imports-11 %}
+
+```scala
+scala> import java.util.{List as _, Map as _, Set as _, *}
+```
+{% endtab %}
+{% endtabs %}
+
+Once again those classes are hidden, but you can use all other classes in *java.util*:
+
+{% tabs packaging-imports-12 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> new ArrayList[String]
+val res0: java.util.ArrayList[String] = []
+```
+{% endtab %}
+{% endtabs %}
+
+Because those Java classes are hidden, you can also use the Scala `List`, `Set`, and `Map` classes without having a naming collision:
+
+{% tabs packaging-imports-13 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> val a = List(1, 2, 3)
+val a: List[Int] = List(1, 2, 3)
+
+scala> val b = Set(1, 2, 3)
+val b: Set[Int] = Set(1, 2, 3)
+
+scala> val c = Map(1 -> 1, 2 -> 2)
+val c: Map[Int, Int] = Map(1 -> 1, 2 -> 2)
+```
+{% endtab %}
+{% endtabs %}
+
+### Use imports anywhere
+
+In Scala, `import` statements can be anywhere.
+They can be used at the top of a source code file:
+
+{% tabs packaging-imports-14 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+package foo
+
+import scala.util.Random
+
+class ClassA {
+ def printRandom(): Unit = {
+ val r = new Random // use the imported class
+ // more code here...
+ }
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=packaging-imports-14 %}
+
+```scala
+package foo
+
+import scala.util.Random
+
+class ClassA:
+ def printRandom(): Unit =
+ val r = new Random // use the imported class
+ // more code here...
+```
+{% endtab %}
+{% endtabs %}
+
+You can also use `import` statements closer to the point where they are needed, if you prefer:
+
+{% tabs packaging-imports-15 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+package foo
+
+class ClassA {
+ import scala.util.Random // inside ClassA
+ def printRandom(): Unit = {
+ val r = new Random
+ // more code here...
+ }
+}
+
+class ClassB {
+ // the Random class is not visible here
+ val r = new Random // this code will not compile
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=packaging-imports-15 %}
+
+```scala
+package foo
+
+class ClassA:
+ import scala.util.Random // inside ClassA
+ def printRandom(): Unit =
+ val r = new Random
+ // more code here...
+
+class ClassB:
+ // the Random class is not visible here
+ val r = new Random // this code will not compile
+```
+
+{% endtab %}
+{% endtabs %}
+
+### “Static” imports
+
+When you want to import members in a way similar to the Java “static import” approach---so you can refer to the member names directly, without having to prefix them with their class name---use the following approach.
+
+Use this syntax to import all static members of the Java `Math` class:
+
+{% tabs packaging-imports-16 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+import java.lang.Math._
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=packaging-imports-16 %}
+
+```scala
+import java.lang.Math.*
+```
+{% endtab %}
+{% endtabs %}
+
+Now you can access static `Math` class methods like `sin` and `cos` without having to precede them with the class name:
+
+{% tabs packaging-imports-17 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+import java.lang.Math._
+
+val a = sin(0) // 0.0
+val b = cos(PI) // -1.0
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=packaging-imports-17 %}
+
+```scala
+import java.lang.Math.*
+
+val a = sin(0) // 0.0
+val b = cos(PI) // -1.0
+```
+{% endtab %}
+{% endtabs %}
+
+### Packages imported by default
+
+Two packages are implicitly imported into the scope of all of your source code files:
+
+- java.lang.*
+- scala.*
+
+The members of the Scala object `Predef` are also imported by default.
+
+> If you ever wondered why you can use classes like `List`, `Vector`, `Map`, etc., without importing them, they’re available because of definitions in the `Predef` object.
+
+### Handling naming conflicts
+
+In the rare event there’s a naming conflict and you need to import something from the root of the project, prefix the package name with `_root_`:
+
+{% tabs packaging-imports-18 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+package accounts
+
+import _root_.accounts._
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=packaging-imports-18 %}
+
+```scala
+package accounts
+
+import _root_.accounts.*
+```
+{% endtab %}
+{% endtabs %}
+
+## Importing `given` instances
+
+As you’ll see in the [Contextual Abstractions][contextual] chapter, in Scala 3 a special form of the `import` statement is used to import `given` instances.
+The basic form is shown in this example:
+
+{% tabs packaging-imports-19 %}
+{% tab 'Scala 3 only' %}
+```scala
+object A:
+ class TC
+ given tc: TC
+ def f(using TC) = ???
+
+object B:
+ import A.* // import all non-given members
+ import A.given // import the given instance
+```
+{% endtab %}
+{% endtabs %}
+
+In this code, the `import A.*` clause of object `B` imports all members of `A` *except* the `given` instance `tc`.
+Conversely, the second import, `import A.given`, imports *only* that `given` instance.
+The two `import` clauses can also be merged into one:
+
+{% tabs packaging-imports-20 %}
+{% tab 'Scala 3 only' %}
+```scala
+object B:
+ import A.{given, *}
+```
+{% endtab %}
+{% endtabs %}
+In Scala 2, that style of import does not exist. Implicit definitions are always imported by the wildcard import.
+### Discussion
+
+The wildcard selector `*` brings all definitions other than givens or extensions into scope, whereas a `given` selector brings all *givens*---including those resulting from extensions---into scope.
+
+These rules have two main benefits:
+
+- It’s more clear where givens in scope are coming from.
+ In particular, it’s not possible to hide imported givens in a long list of other wildcard imports.
+- It enables importing all givens without importing anything else.
+ This is particularly important since givens can be anonymous, so the usual use of named imports is not practical.
+
+### By-type imports
+
+Since givens can be anonymous, it’s not always practical to import them by their name, and wildcard imports are typically used instead.
+*By-type imports* provide a more specific alternative to wildcard imports, which makes it more clear what is imported:
+
+{% tabs packaging-imports-21 %}
+{% tab 'Scala 3 only' %}
+```scala
+import A.{given TC}
+```
+{% endtab %}
+{% endtabs %}
+
+This imports any `given` in `A` that has a type which conforms to `TC`.
+Importing givens of several types `T1,...,Tn` is expressed by multiple `given` selectors:
+
+{% tabs packaging-imports-22 %}
+{% tab 'Scala 3 only' %}
+```scala
+import A.{given T1, ..., given Tn}
+```
+{% endtab %}
+{% endtabs %}
+
+Importing all `given` instances of a parameterized type is expressed by wildcard arguments.
+For example, when you have this `object`:
+
+{% tabs packaging-imports-23 %}
+{% tab 'Scala 3 only' %}
+```scala
+object Instances:
+ given intOrd: Ordering[Int]
+ given listOrd[T: Ordering]: Ordering[List[T]]
+ given ec: ExecutionContext = ...
+ given im: Monoid[Int]
+```
+{% endtab %}
+{% endtabs %}
+
+This import statement imports the `intOrd`, `listOrd`, and `ec` instances, but leaves out the `im` instance because it doesn’t fit any of the specified bounds:
+
+{% tabs packaging-imports-24 %}
+{% tab 'Scala 3 only' %}
+```scala
+import Instances.{given Ordering[?], given ExecutionContext}
+```
+{% endtab %}
+{% endtabs %}
+
+By-type imports can be mixed with by-name imports.
+If both are present in an import clause, by-type imports come last.
+For instance, this import clause imports `im`, `intOrd`, and `listOrd`, but leaves out `ec`:
+
+{% tabs packaging-imports-25 %}
+{% tab 'Scala 3 only' %}
+```scala
+import Instances.{im, given Ordering[?]}
+```
+{% endtab %}
+{% endtabs %}
+
+### An example
+
+As a concrete example, imagine that you have this `MonthConversions` object that contains two `given` definitions:
+
+{% tabs packaging-imports-26 %}
+{% tab 'Scala 3 only' %}
+
+```scala
+object MonthConversions:
+ trait MonthConverter[A]:
+ def convert(a: A): String
+
+ given intMonthConverter: MonthConverter[Int] with
+ def convert(i: Int): String =
+ i match
+ case 1 => "January"
+ case 2 => "February"
+ // more cases here ...
+
+ given stringMonthConverter: MonthConverter[String] with
+ def convert(s: String): String =
+ s match
+ case "jan" => "January"
+ case "feb" => "February"
+ // more cases here ...
+```
+{% endtab %}
+{% endtabs %}
+
+To import those givens into the current scope, use these two `import` statements:
+
+{% tabs packaging-imports-27 %}
+{% tab 'Scala 3 only' %}
+
+```scala
+import MonthConversions.*
+import MonthConversions.{given MonthConverter[?]}
+```
+{% endtab %}
+{% endtabs %}
+
+Now you can create a method that uses those `given` instances:
+
+{% tabs packaging-imports-28 %}
+{% tab 'Scala 3 only' %}
+
+```scala
+def genericMonthConverter[A](a: A)(using monthConverter: MonthConverter[A]): String =
+ monthConverter.convert(a)
+```
+{% endtab %}
+{% endtabs %}
+
+Then you can use that method in your application:
+
+{% tabs packaging-imports-29 %}
+{% tab 'Scala 3 only' %}
+
+```scala
+@main def main =
+ println(genericMonthConverter(1)) // January
+ println(genericMonthConverter("jan")) // January
+```
+{% endtab %}
+{% endtabs %}
+
+As mentioned, one of the key design benefits of the “import given” syntax is to make it clear where givens in scope come from, and it’s clear in these `import` statements that the givens come from the `MonthConversions` object.
+
+[contextual]: {% link _overviews/scala3-book/ca-contextual-abstractions-intro.md %}
diff --git a/_overviews/scala3-book/scala-features.md b/_overviews/scala3-book/scala-features.md
new file mode 100644
index 0000000000..c1d1ca834c
--- /dev/null
+++ b/_overviews/scala3-book/scala-features.md
@@ -0,0 +1,577 @@
+---
+title: Scala Features
+type: chapter
+description: This page discusses the main features of the Scala programming language.
+languages: [ru, zh-cn]
+num: 2
+previous-page: introduction
+next-page: why-scala-3
+---
+
+
+The name _Scala_ comes from the word _scalable_, and true to that name, the Scala language is used to power busy websites and analyze huge data sets.
+This section introduces the features that make Scala a scalable language.
+These features are split into three sections:
+
+- High-level language features
+- Lower-level language features
+- Scala ecosystem features
+
+
+
+{% comment %}
+I think of this section as being like an “elevator pitch.”
+{% endcomment %}
+
+## High-level features
+
+Looking at Scala from the proverbial “30,000 foot view,” you can make the following statements about it:
+
+- It’s a high-level programming language
+- It has a concise, readable syntax
+- It’s statically-typed (but feels dynamic)
+- It has an expressive type system
+- It’s a functional programming (FP) language
+- It’s an object-oriented programming (OOP) language
+- It supports the fusion of FP and OOP
+- Contextual abstractions provide a clear way to implement _term inference_
+- It runs on the JVM (and in the browser)
+- It interacts seamlessly with Java code
+- It’s used for server-side applications (including microservices), big data applications, and can also be used in the browser with Scala.js
+
+The following sections take a quick look at these features.
+
+
+### A high-level language
+
+Scala is considered a high-level language in at least two ways.
+First, like Java and many other modern languages, you don’t deal with low-level concepts like pointers and memory management.
+
+Second, with the use of lambdas and higher-order functions, you write your code at a very high level.
+As the functional programming saying goes, in Scala you write _what_ you want, not _how_ to achieve it.
+That is, we don’t write imperative code like this:
+
+{% tabs scala-features-1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=scala-features-1 %}
+```scala
+import scala.collection.mutable.ListBuffer
+
+def double(ints: List[Int]): List[Int] = {
+ val buffer = new ListBuffer[Int]()
+ for (i <- ints) {
+ buffer += i * 2
+ }
+ buffer.toList
+}
+
+val oldNumbers = List(1, 2, 3)
+val newNumbers = double(oldNumbers)
+```
+{% endtab %}
+{% tab 'Scala 3' for=scala-features-1 %}
+```scala
+import scala.collection.mutable.ListBuffer
+
+def double(ints: List[Int]): List[Int] =
+ val buffer = new ListBuffer[Int]()
+ for i <- ints do
+ buffer += i * 2
+ buffer.toList
+
+val oldNumbers = List(1, 2, 3)
+val newNumbers = double(oldNumbers)
+```
+{% endtab %}
+{% endtabs %}
+
+That code instructs the compiler what to do on a step-by-step basis.
+Instead, we write high-level, functional code using higher-order functions and lambdas like this to compute the same result:
+
+{% tabs scala-features-2 %}
+{% tab 'Scala 2 and 3' for=scala-features-2 %}
+```scala
+val newNumbers = oldNumbers.map(_ * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+
+As you can see, that code is much more concise, easier to read, and easier to maintain.
+
+
+### Concise syntax
+
+Scala has a concise, readable syntax.
+For instance, variables are created concisely, and their types are clear:
+
+{% tabs scala-features-3 %}
+{% tab 'Scala 2 and 3' for=scala-features-3 %}
+```scala
+val nums = List(1,2,3)
+val p = Person("Martin", "Odersky")
+```
+{% endtab %}
+{% endtabs %}
+
+
+Higher-order functions and lambdas make for concise code that’s readable:
+
+{% tabs scala-features-4 %}
+{% tab 'Scala 2 and 3' for=scala-features-4 %}
+```scala
+nums.map(i => i * 2) // long form
+nums.map(_ * 2) // short form
+
+nums.filter(i => i > 1)
+nums.filter(_ > 1)
+```
+{% endtab %}
+{% endtabs %}
+
+Traits, classes, and methods are defined with a clean, light syntax:
+
+{% tabs scala-features-5 class=tabs-scala-version %}
+{% tab 'Scala 2' for=scala-features-5 %}
+```scala mdoc
+trait Animal {
+ def speak(): Unit
+}
+
+trait HasTail {
+ def wagTail(): Unit
+}
+
+class Dog extends Animal with HasTail {
+ def speak(): Unit = println("Woof")
+ def wagTail(): Unit = println("⎞⎜⎛ ⎞⎜⎛")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=scala-features-5 %}
+```scala
+trait Animal:
+ def speak(): Unit
+
+trait HasTail:
+ def wagTail(): Unit
+
+class Dog extends Animal, HasTail:
+ def speak(): Unit = println("Woof")
+ def wagTail(): Unit = println("⎞⎜⎛ ⎞⎜⎛")
+```
+{% endtab %}
+{% endtabs %}
+
+
+Studies have shown that the time a developer spends _reading_ code to _writing_ code is at least a 10:1 ratio, so writing code that is concise _and_ readable is important.
+
+
+### A dynamic feel
+
+Scala is a statically-typed language, but thanks to its type inference capabilities it feels dynamic.
+All of these expressions look like a dynamically-typed language like Python or Ruby, but they’re all Scala:
+
+{% tabs scala-features-6 class=tabs-scala-version %}
+{% tab 'Scala 2' for=scala-features-6 %}
+```scala
+val s = "Hello"
+val p = Person("Al", "Pacino")
+val sum = nums.reduceLeft(_ + _)
+val y = for (i <- nums) yield i * 2
+val z = nums
+ .filter(_ > 100)
+ .filter(_ < 10_000)
+ .map(_ * 2)
+```
+{% endtab %}
+{% tab 'Scala 3' for=scala-features-6 %}
+```scala
+val s = "Hello"
+val p = Person("Al", "Pacino")
+val sum = nums.reduceLeft(_ + _)
+val y = for i <- nums yield i * 2
+val z = nums
+ .filter(_ > 100)
+ .filter(_ < 10_000)
+ .map(_ * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+
+As Heather Miller states, Scala is considered to be a [strong, statically-typed language](https://heather.miller.am/blog/types-in-scala.html), and you get all the benefits of static types:
+
+- Correctness: you catch most errors at compile-time
+- Great IDE support
+ - Reliable code completion
+ - Catching errors at compile-time means catching mistakes as you type
+ - Easy and reliable refactoring
+- You can refactor your code with confidence
+- Method type declarations tell readers what the method does, and help serve as documentation
+- Scalability and maintainability: types help ensure correctness across arbitrarily large applications and development teams
+- Strong typing in combination with excellent inference enables mechanisms like [contextual abstraction]({{ site.scala3ref }}/contextual) that allows you to omit boilerplate code. Often, this boilerplate code can be inferred by the compiler, based on type definitions and a given context.
+
+{% comment %}
+In that list:
+- 'Correctness' and 'Scalability' come from Heather Miller’s page
+- the IDE-related quotes in this section come from the Scala.js website:
+ - catch most errors in the IDE
+ - Easy and reliable refactoring
+ - Reliable code completion
+{% endcomment %}
+
+
+### Expressive type system
+
+{% comment %}
+- this text comes from the current [ScalaTour](https://docs.scala-lang.org/tour/tour-of-scala.html).
+- TODO: all of the URLs will have to be updated
+
+- i removed these items until we can replace them:
+* [Compound types](/tour/compound-types.html)
+* [conversions](/tour/implicit-conversions.html)
+* [Explicitly typed self references](/tour/self-types.html)
+{% endcomment %}
+
+Scala’s type system enforces, at compile-time, that abstractions are used in a safe and coherent manner.
+In particular, the type system supports:
+
+- [Inferred types]({% link _overviews/scala3-book/types-inferred.md %})
+- [Generic classes]({% link _overviews/scala3-book/types-generics.md %})
+- [Variance annotations]({% link _overviews/scala3-book/types-variance.md %})
+- [Upper](/tour/upper-type-bounds.html) and [lower](/tour/lower-type-bounds.html) type bounds
+- [Polymorphic methods](/tour/polymorphic-methods.html)
+- [Intersection types]({% link _overviews/scala3-book/types-intersection.md %})
+- [Union types]({% link _overviews/scala3-book/types-union.md %})
+- [Type lambdas]({{ site.scala3ref }}/new-types/type-lambdas.html)
+- [`given` instances and `using` clauses]({% link _overviews/scala3-book/ca-context-parameters.md %})
+- [Extension methods]({% link _overviews/scala3-book/ca-extension-methods.md %})
+- [Type classes]({% link _overviews/scala3-book/ca-type-classes.md %})
+- [Multiversal equality]({% link _overviews/scala3-book/ca-multiversal-equality.md %})
+- [Opaque type aliases]({% link _overviews/scala3-book/types-opaque-types.md %})
+- [Open classes]({{ site.scala3ref }}/other-new-features/open-classes.html)
+- [Match types]({{ site.scala3ref }}/new-types/match-types.html)
+- [Dependent function types]({{ site.scala3ref }}/new-types/dependent-function-types.html)
+- [Polymorphic function types]({{ site.scala3ref }}/new-types/polymorphic-function-types.html)
+- [Context bounds]({{ site.scala3ref }}/contextual/context-bounds.html)
+- [Context functions]({{ site.scala3ref }}/contextual/context-functions.html)
+- [Inner classes](/tour/inner-classes.html) and [abstract type members](/tour/abstract-type-members.html) as object members
+
+In combination, these features provide a powerful basis for the safe reuse of programming abstractions and for the type-safe extension of software.
+
+
+### A functional programming language
+
+Scala is a functional programming (FP) language, meaning:
+
+- Functions are values, and can be passed around like any other value
+- Higher-order functions are directly supported
+- Lambdas are built in
+- Everything in Scala is an expression that returns a value
+- Syntactically it’s easy to use immutable variables, and their use is encouraged
+- It has a wealth of immutable collection classes in the standard library
+- Those collection classes come with dozens of functional methods: they don’t mutate the collection, but instead return an updated copy of the data
+
+
+### An object-oriented language
+
+Scala is an object-oriented programming (OOP) language.
+Every value is an instance of a class and every “operator” is a method.
+
+In Scala, all types inherit from a top-level class `Any`, whose immediate children are `AnyVal` (_value types_, such as `Int` and `Boolean`) and `AnyRef` (_reference types_, as in Java).
+This means that the Java distinction between primitive types and boxed types (e.g. `int` vs. `Integer`) isn’t present in Scala.
+Boxing and unboxing is completely transparent to the user.
+
+{% comment %}
+- AnyRef above is wrong in case of strict null checking, no? On the other hand, maybe too much information to state this here
+- probably not worth to mention (too advanced at this point) there is AnyKind
+- Add the “types hierarchy” image here?
+{% endcomment %}
+
+
+### Supports FP/OOP fusion
+
+{% comment %}
+NOTE: This text in the first line comes from this slide: https://x.com/alexelcu/status/996408359514525696
+{% endcomment %}
+
+The essence of Scala is the fusion of functional programming and object-oriented programming in a typed setting:
+
+- Functions for the logic
+- Objects for the modularity
+
+As [Martin Odersky has stated](https://jaxenter.com/current-state-scala-odersky-interview-129495.html), “Scala was designed to show that a fusion of functional and object-oriented programming is possible and practical.”
+
+
+### Term inference, made clearer
+
+Following Haskell, Scala was the second popular language to have some form of _implicits_.
+In Scala 3 these concepts have been completely re-thought and more clearly implemented.
+
+The core idea is _term inference_: Given a type, the compiler synthesizes a “canonical” term that has that type.
+In Scala, a context parameter directly leads to an inferred argument term that could also be written down explicitly.
+
+Use cases for this concept include implementing [type classes]({% link _overviews/scala3-book/ca-type-classes.md %}), establishing context, dependency injection, expressing capabilities, computing new types, and proving relationships between them.
+
+Scala 3 makes this process more clear than ever before.
+Read about contextual abstractions in the [Reference documentation]({{ site.scala3ref }}/contextual).
+
+
+### Client & server
+
+Scala code runs on the Java Virtual Machine (JVM), so you get all of its benefits:
+
+- Security
+- Performance
+- Memory management
+- Portability and platform independence
+- The ability to use the wealth of existing Java and JVM libraries
+
+In addition to running on the JVM, Scala also runs in the browser with Scala.js (and open source third-party tools to integrate popular JavaScript libraries), and native executables can be built with Scala Native and GraalVM.
+
+
+### Seamless Java interaction
+
+You can use Java classes and libraries in your Scala applications, and you can use Scala code in your Java applications.
+In regards to the second point, large libraries like [Akka](https://akka.io) and the [Play Framework](https://www.playframework.com) are written in Scala, and can be used in Java applications.
+
+In regards to the first point, Java classes and libraries are used in Scala applications every day.
+For instance, in Scala you can read files with a Java `BufferedReader` and `FileReader`:
+
+{% tabs scala-features-7 %}
+{% tab 'Scala 2 and 3' for=scala-features-7 %}
+```scala
+import java.io.*
+val br = BufferedReader(FileReader(filename))
+// read the file with `br` ...
+```
+{% endtab %}
+{% endtabs %}
+
+Using Java code in Scala is generally seamless.
+
+Java collections can also be used in Scala, and if you want to use Scala’s rich collection class methods with them, you can convert them with just a few lines of code:
+
+{% tabs scala-features-8 %}
+{% tab 'Scala 2 and 3' for=scala-features-8 %}
+```scala
+import scala.jdk.CollectionConverters.*
+val scalaList: Seq[Integer] = JavaClass.getJavaList().asScala.toSeq
+```
+{% endtab %}
+{% endtabs %}
+
+
+### Wealth of libraries
+
+As you’ll see in the third section of this page, Scala libraries and frameworks like these have been written to power busy websites and work with huge datasets:
+
+1. The [Play Framework](https://www.playframework.com) is a lightweight, stateless, developer-friendly, web-friendly architecture for creating highly-scalable applications
+2. [Apache Spark](https://spark.apache.org) is a unified analytics engine for big data processing, with built-in modules for streaming, SQL, machine learning and graph processing
+
+The [Awesome Scala list](https://github.com/lauris/awesome-scala) shows dozens of additional open source tools that developers have created to build Scala applications.
+
+In addition to server-side programming, [Scala.js](https://www.scala-js.org) is a strongly-typed replacement for writing JavaScript, with open source third-party libraries that include tools to integrate with Facebook’s React library, jQuery, and more.
+
+
+
+{% comment %}
+The Lower-Level Features section is like the second part of an elevator pitch.
+Assuming you told someone about the previous high-level features and then they say, “Tell me more,” this is what you might tell them.
+{% endcomment %}
+
+## Lower-level language features
+
+Where the previous section covered high-level features of Scala, it’s interesting to note that at a high level you can make the same statements about both Scala 2 and Scala 3.
+A decade ago Scala started with a strong foundation of desirable features, and as you’ll see in this section, those benefits have been improved with Scala 3.
+
+At a “sea level” view of the details---i.e., the language features programmers use everyday---Scala 3 has significant advantages over Scala 2:
+
+- The ability to create algebraic data types (ADTs) more concisely with enums
+- An even more concise and readable syntax:
+ - The “quiet” control structure syntax is easier to read
+ - Optional braces
+ - Fewer symbols in the code creates less visual noise, making it easier to read
+ - The `new` keyword is generally no longer needed when creating class instances
+ - The formality of package objects have been dropped in favor of simpler “top level” definitions
+- A grammar that’s more clear:
+ - Multiple different uses of the `implicit` keyword have been removed; those uses are replaced by more obvious keywords like `given`, `using`, and `extension`, focusing on intent over mechanism (see the [Givens][givens] section for details)
+ - [Extension methods][extension] replace implicit classes with a clearer and simpler mechanism
+ - The addition of the `open` modifier for classes makes the developer intentionally declare that a class is open for modification, thereby limiting ad-hoc extensions to a code base
+ - [Multiversal equality][multiversal] rules out nonsensical comparisons with `==` and `!=` (i.e., attempting to compare a `Person` to a `Planet`)
+ - Macros are implemented much more easily
+ - Union and intersection offer a flexible way to model types
+ - Trait parameters replace and simplify early initializers
+ - [Opaque type aliases][opaque_types] replace most uses of value classes, while guaranteeing the absence of boxing
+ - Export clauses provide a simple and general way to express aggregation, which can replace the previous facade pattern of package objects inheriting from classes
+ - The procedure syntax has been dropped, and the varargs syntax has been changed, both to make the language more consistent
+ - The `@infix` annotation makes it obvious how you want a method to be applied
+ - The [`@targetName`]({{ site.scala3ref }}/other-new-features/targetName.html) method annotation defines an alternate name for the method, improving Java interoperability, and letting you provide aliases for symbolic operators
+
+It would take too much space to demonstrate all of those features here, but follow the links in the items above to see those features in action.
+All of these features are discussed in detail in the *New*, *Changed*, and *Dropped* features pages in the [Overview documentation][reference].
+
+
+
+{% comment %}
+CHECKLIST OF ALL ADDED, UPDATED, AND REMOVED FEATURES
+=====================================================
+
+New Features
+------------
+- trait parameters
+- super traits
+- creator applications
+- export clauses
+- opaque type aliases
+- open classes
+- parameter untupling
+- kind polymorphism
+- tupled function
+- threadUnsafe annotation
+- new control syntax
+- optional braces (experimental)
+- explicit nulls
+- safe initialization
+
+CHANGED FEATURES
+----------------
+- numeric literals
+- structural types
+- operators
+- wildcard types
+- type checking
+- type inference
+- implicit resolution
+- implicit conversions
+- overload resolution
+- match expressions
+- vararg patterns
+- pattern bindings
+- pattern matching
+- eta expansion
+- compiler plugins
+- lazy vals initialization
+- main functions
+
+DROPPED FEATURES
+----------------
+- DelayedInit
+- macros
+- existential types
+- type projection
+- do/while syntax
+- procedure syntax
+- package objects
+- early initializers
+- class shadowing
+- limit 22
+- XML literals
+- symbol literals
+- auto-application
+- weak conformance
+- nonlocal returns
+- [this] qualifier
+ - private[this] and protected[this] access modifiers are deprecated
+ and will be phased out
+{% endcomment %}
+
+
+
+
+## Scala ecosystem
+
+{% comment %}
+TODO: I didn’t put much work into this section because I don’t know if you want
+ to add many tools because (a) that can be seen as an endorsement and
+ (b) it creates a section that can need more maintenance than average
+ since tool popularity can wax and wane. One way to avoid the first
+ point is to base the lists on Github stars and activity.
+{% endcomment %}
+
+Scala has a vibrant ecosystem, with libraries and frameworks for every need.
+The [“Awesome Scala” list](https://github.com/lauris/awesome-scala) provides a list of hundreds of open source projects that are available to Scala developers, and the [Scaladex](https://index.scala-lang.org) provides a searchable index of Scala libraries.
+Some of the more notable libraries are listed below.
+
+
+
+### Web development
+
+- The [Play Framework](https://www.playframework.com) followed the Ruby on Rails model to become a lightweight, stateless, developer-friendly, web-friendly architecture for highly-scalable applications
+- [Scalatra](https://scalatra.org) is a tiny, high-performance, async web framework, inspired by Sinatra
+- [Finatra](https://twitter.github.io/finatra) is Scala services built for X
+- [Scala.js](https://www.scala-js.org) is a strongly-typed replacement for JavaScript that provides a safer way to build robust front-end web applications
+- [ScalaJs-React](https://github.com/japgolly/scalajs-react) lifts Facebook’s React library into Scala.js, and endeavours to make it as type-safe and Scala-friendly as possible
+
+HTTP(S) libraries:
+
+- [Akka-http](https://akka.io)
+- [Finch](https://github.com/finagle/finch)
+- [Http4s](https://github.com/http4s/http4s)
+- [Sttp](https://github.com/softwaremill/sttp)
+
+JSON libraries:
+
+- [Argonaut](https://github.com/argonaut-io/argonaut)
+- [Circe](https://github.com/circe/circe)
+- [Json4s](https://github.com/json4s/json4s)
+- [Play-JSON](https://github.com/playframework/play-json)
+
+Serialization:
+
+- [ScalaPB](https://github.com/scalapb/ScalaPB)
+
+### Science and data analysis:
+
+- [Algebird](https://github.com/twitter/algebird)
+- [Spire](https://github.com/typelevel/spire)
+- [Squants](https://github.com/typelevel/squants)
+
+
+### Big data
+
+- [Apache Spark](https://github.com/apache/spark)
+- [Apache Flink](https://github.com/apache/flink)
+
+
+### AI, machine learning
+
+- [BigDL](https://github.com/intel-analytics/BigDL) (Distributed Deep Learning Framework for Apache Spark)
+- [TensorFlow Scala](https://github.com/eaplatanios/tensorflow_scala)
+
+
+### Functional Programming & Functional Reactive Programming
+
+FP:
+
+- [Cats](https://github.com/typelevel/cats)
+- [Zio](https://github.com/zio/zio)
+
+Functional reactive programming (FRP):
+
+- [fs2](https://github.com/typelevel/fs2)
+- [monix](https://github.com/monix/monix)
+
+
+### Build tools
+
+- [sbt](https://www.scala-sbt.org)
+- [Gradle](https://gradle.org)
+- [Mill](https://github.com/lihaoyi/mill)
+
+
+
+## Summary
+
+As this page shows, Scala has many terrific programming language features at a high level, at an everyday programming level, and through its developer ecosystem.
+
+
+
+[reference]: {{ site.scala3ref }}/overview.html
+[multiversal]: {% link _overviews/scala3-book/ca-multiversal-equality.md %}
+[extension]: {% link _overviews/scala3-book/ca-extension-methods.md %}
+[givens]: {% link _overviews/scala3-book/ca-context-parameters.md %}
+[opaque_types]: {% link _overviews/scala3-book/types-opaque-types.md %}
+
+
+
diff --git a/_overviews/scala3-book/scala-for-java-devs.md b/_overviews/scala3-book/scala-for-java-devs.md
new file mode 100644
index 0000000000..0ba8361778
--- /dev/null
+++ b/_overviews/scala3-book/scala-for-java-devs.md
@@ -0,0 +1,1332 @@
+---
+title: Scala for Java Developers
+type: chapter
+description: This page is for Java developers who are interested in learning about Scala 3.
+languages: [zh-cn]
+num: 74
+previous-page: interacting-with-java
+next-page: scala-for-javascript-devs
+---
+
+{% include_relative scala4x.css %}
+
+
+
+This page provides a comparison between the Java and Scala programming languages by sharing side-by-side examples of each language.
+It’s intended for programmers who know Java and want to learn about Scala, specifically by seeing how Scala features compare to Java.
+
+
+
+## Overview
+
+Before getting into the examples, this first section provides a relatively brief introduction and summary of the sections that follow.
+It presents the similarities and differences between Java and Scala at a high level, and then introduces the differences you’ll experience every day as you write code.
+
+### High level similarities
+
+At a high level, Scala shares these similarities with Java:
+
+- Scala code is compiled to _.class_ files, packaged in JAR files, and runs on the JVM
+- It’s an [object-oriented programming][modeling-oop] (OOP) language
+- It’s statically typed
+- Both languages have support for lambdas and [higher-order functions][hofs]
+- They can both be used with IDEs like IntelliJ IDEA and Microsoft VS Code
+- Projects can be built with build tools like Gradle, Ant, and Maven
+- It has terrific libraries and frameworks for building server-side, network-intensive applications, including web server applications, microservices, machine learning, and more (see the [“Awesome Scala” list](https://github.com/lauris/awesome-scala))
+- Both Java and Scala can use Scala libraries:
+ - They can use the [Akka actors library](https://akka.io) to build actor-based concurrent systems, and Apache Spark to build data-intensive applications
+ - They can use the [Play Framework](https://www.playframework.com) to develop server-side applications
+- You can use [GraalVM](https://www.graalvm.org) to compile your projects into native executables
+- Scala can seamlessly use the wealth of libraries that have been developed for Java
+
+### High level differences
+
+Also at a high level, the differences between Java and Scala are:
+
+- Scala has a concise but readable syntax; we call it _expressive_
+- Though it’s statically typed, Scala often feels like a dynamic language
+- Scala is a pure OOP language, so every object is an instance of a class, and symbols like `+` and `+=` that look like operators are really methods; this means that you can create your own operators
+- In addition to being a pure OOP language, Scala is also a pure FP language; in fact, it encourages a fusion of OOP and FP, with functions for the logic and objects for modularity
+- Scala has a full suite of immutable collections, including `List`, `Vector`, and immutable `Map` and `Set` implementations
+- Everything in Scala is an _expression_: constructs like `if` statements, `for` loops, `match` expressions, and even `try`/`catch` expressions all have return values
+- Scala idioms favor immutability by default: you’re encouraged to use immutable (`final`) variables and immutable collections
+- Idiomatic Scala code does not use `null`, and thus does not suffer from `NullPointerException`
+- The Scala ecosystem has other [build tools][tools] in sbt, Mill, and others
+- In addition to running on the JVM, the [Scala.js](https://www.scala-js.org) project lets you use Scala as a JavaScript replacement
+- The [Scala Native](http://www.scala-native.org) project adds low-level constructs to let you write “systems” level code, and also compiles to native executables
+
+{% comment %}
+These are several notes that came up early in the writing process, and I (Alvin) can’t really address them:
+TODO: Need a good, simple way to state that Scala has a sound type system
+TODO: Points to make about Scala’s consistency?
+TODO: Add a point about how the type system lets you express details as desired
+{% endcomment %}
+
+
+### Programming level differences
+
+Finally, these are some of the differences you’ll see every day when writing code:
+
+- Scala’s syntax is extremely consistent
+- Variables and parameters are defined as `val` (immutable, like `final` in Java) or `var` (mutable)
+- _Type inference_ makes your code feel dynamically typed, and helps to keep your code brief
+- In addition to simple `for` loops, Scala has powerful `for` comprehensions that yield results based on your algorithms
+- Pattern matching and `match` expressions will change the way you write code
+- Writing immutable code by default leads to writing _expressions_ rather than _statements_; in time you see that writing expressions simplifies your code (and your tests)
+- [Toplevel definitions][toplevel] let you put method, field, and other definitions anywhere, also leading to concise, expressive code
+- You can create _mixins_ by “mixing” multiple traits into classes and objects (traits are similar to interfaces in Java 8 and newer)
+- Classes are closed by default, supporting Joshua Bloch’s _Effective Java_ idiom, “Design and document for inheritance or else forbid it”
+- Scala’s [contextual abstractions][contextual] and _term inference_ provide a collection of features:
+ - [Extension methods][extension-methods] let you add new functionality to closed classes
+ - [_Given_ instances][givens] let you define terms that the compiler can synthesize at _using_ points, making your code less verbose and essentially letting the compiler write code for you
+ - [Multiversal equality][multiversal] lets you limit equality comparisons---at compile time---to only those comparisons that make sense
+- Scala has state of the art, third-party, open source functional programming libraries
+- Scala case classes are like records in Java 14; they help you model data when writing FP code, with built-in support for concepts like pattern matching and cloning
+- Thanks to features like by-name parameters, infix notation, optional parentheses, extension methods, and [higher-order functions][hofs], you can create your own “control structures” and DSLs
+- Scala files do not have to be named according to the classes or traits they contain
+- Many other goodies: companion classes and objects, macros, [union][union-types] and [intersection][intersection-types], numeric literals, multiple parameter lists, default values for parameters, named arguments, and more
+
+### Features compared with examples
+
+Given that introduction, the following sections provide side-by-side comparisons of Java and Scala programming language features.
+
+
+
+## OOP style classes and methods
+
+This section provides comparisons of features related to OOP-style classes and methods.
+
+### Comments:
+
+
+
+
+
+ //
+ /* ... */
+ /** ... */
+
+
+
+
+ //
+ /* ... */
+ /** ... */
+
+
+
+
+
+### OOP style class, primary constructor:
+
+Scala doesn’t follow the JavaBeans standard, so instead of showing Java
+code written in the JavaBeans style, here we show Java code that is
+equivalent to the Scala code that follows it.
+
+
+
+
+
+ class Person {
+ public String firstName;
+ public String lastName;
+ public int age;
+ public Person(
+ String firstName,
+ String lastName,
+ int age
+ ) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.age = age;
+ }
+ public String toString() {
+ return String.format("%s %s is %d years old.", firstName, lastName, age);
+ }
+ }
+
+
+
+
+ class Person (
+ var firstName: String,
+ var lastName: String,
+ var age: Int
+ ):
+ override def toString = s"$firstName $lastName is $age years old."
+
+
+
+
+
+
+### Auxiliary constructors:
+
+
+
+
+
+ public class Person {
+ public String firstName;
+ public String lastName;
+ public int age;
+
+ // primary constructor
+ public Person(
+ String firstName,
+ String lastName,
+ int age
+ ) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.age = age;
+ }
+
+ // zero-arg constructor
+ public Person() {
+ this("", "", 0);
+ }
+
+ // one-arg constructor
+ public Person(String firstName) {
+ this(firstName, "", 0);
+ }
+
+ // two-arg constructor
+ public Person(
+ String firstName,
+ String lastName
+ ) {
+ this(firstName, lastName, 0);
+ }
+
+ }
+
+
+
+
+ class Person (
+ var firstName: String,
+ var lastName: String,
+ var age: Int
+ ):
+ // zero-arg auxiliary constructor
+ def this() = this("", "", 0)
+
+ // one-arg auxiliary constructor
+ def this(firstName: String) =
+ this(firstName, "", 0)
+
+ // two-arg auxiliary constructor
+ def this(
+ firstName: String,
+ lastName: String
+ ) =
+ this(firstName, lastName, 0)
+
+ end Person
+
+
+
+
+
+
+### Classes closed by default:
+“Plan for inheritance or else forbid it.”
+
+
+
+
+
+ final class Person
+
+
+
+
+ class Person
+
+
+
+
+
+
+### A class that’s open for extension:
+
+
+
+
+
+ class Person
+
+
+
+
+ open class Person
+
+
+
+
+
+
+### One-line method:
+
+
+
+
+
+ public int add(int a, int b) {
+ return a + b;
+ }
+
+
+
+
+## Interfaces, traits, and inheritance
+
+This section compares Java interfaces to Scala traits, including how classes extend interfaces and traits.
+
+
+### Interfaces/traits:
+
+
+
+
+
+ public interface Marker {};
+
+
+
+
+ trait Marker
+
+
+
+
+
+
+### Simple interface:
+
+
+
+
+
+ public interface Adder {
+ public int add(int a, int b);
+ }
+
+
+
+
+ trait Adder:
+ def add(a: Int, b: Int): Int
+
+
+
+
+
+
+### Interface with a concrete method:
+
+
+
+
+
+ public interface Adder {
+ int add(int a, int b);
+ default int multiply(
+ int a, int b
+ ) {
+ return a * b;
+ }
+ }
+
+
+
+
+ trait Adder:
+ def add(a: Int, b: Int): Int
+ def multiply(a: Int, b: Int): Int =
+ a * b
+
+
+
+
+
+
+### Inheritance:
+
+
+
+
+
+ class Dog extends Animal implements HasLegs, HasTail
+
+
+
+
+ class Dog extends Animal, HasLegs, HasTail
+
+
+
+
+
+
+### Extend multiple interfaces
+
+These interfaces and traits have concrete, implemented methods (default methods):
+
+
+
+
+
+ interface Adder {
+ default int add(int a, int b) {
+ return a + b;
+ }
+ }
+
+ interface Multiplier {
+ default int multiply (
+ int a,
+ int b)
+ {
+ return a * b;
+ }
+ }
+
+ public class JavaMath implements Adder, Multiplier {}
+
+ JavaMath jm = new JavaMath();
+ jm.add(1,1);
+ jm.multiply(2,2);
+
+
+
+
+ trait Adder:
+ def add(a: Int, b: Int) = a + b
+
+ trait Multiplier:
+ def multiply(a: Int, b: Int) = a * b
+
+ class ScalaMath extends Adder, Multiplier
+
+ val sm = new ScalaMath
+ sm.add(1,1)
+ sm.multiply(2,2)
+
+
+
+
+
+
+### Mixins:
+
+
+
+
+
+ N/A
+
+
+
+
+ class DavidBanner
+
+ trait Angry:
+ def beAngry() =
+ println("You won’t like me ...")
+
+ trait Big:
+ println("I’m big")
+
+ trait Green:
+ println("I’m green")
+
+ // mix in the traits as DavidBanner
+ // is created
+ val hulk = new DavidBanner with Big with Angry with Green
+
+
+
+
+
+
+
+
+## Control structures
+
+This section compares [control structures][control] in Java and Scala.
+
+### `if` statement, one line:
+
+
+
+
+
+ if (x == 1) { System.out.println(1); }
+
+
+
+
+ if x == 1 then println(x)
+
+
+
+
+
+
+### `if` statement, multiline:
+
+
+
+
+
+ if (x == 1) {
+ System.out.println("x is 1, as you can see:")
+ System.out.println(x)
+ }
+
+
+
+
+ if x == 1 then
+ println("x is 1, as you can see:")
+ println(x)
+
+ try
+ writeTextToFile(text)
+ catch
+ case ioe: IOException =>
+ println(ioe.getMessage)
+ case nfe: NumberFormatException =>
+ println(nfe.getMessage)
+ finally
+ println("Clean up resources here.")
+
+
+
+
+
+
+
+## Collections classes
+
+This section compares the [collections classes][collections-classes] that are available in Java and Scala.
+
+
+### Immutable collections classes
+
+Examples of how to create instances of immutable collections.
+
+
+### Sequences:
+
+
+
+
+
+ List strings = List.of("a", "b", "c");
+
+
+
+
+ val strings = List("a", "b", "c")
+ val strings = Vector("a", "b", "c")
+
+ val map = Map(
+ "a" -> 1,
+ "b" -> 2,
+ "c" -> 3
+ )
+
+
+
+
+
+
+### Mutable collections classes
+
+Scala has mutable collections classes like `ArrayBuffer`, `Map`, and `Set` in its _scala.collection.mutable_ package.
+After [importing them][imports] into the current scope, they’re created just like the immutable `List`, `Vector`, `Map`, and `Set` examples just shown.
+
+Scala also has an `Array` class, which you can think of as being a wrapper around the Java `array` primitive type.
+A Scala `Array[A]` maps to a Java `A[]`, so you can think of this Scala `Array[String]`:
+
+```scala
+val a = Array("a", "b")
+```
+
+as being backed by this Java `String[]`:
+
+```java
+String[] a = {"a", "b"};
+```
+
+However, a Scala `Array` also has all of the functional methods you expect in a Scala collection, including `map` and `filter`:
+
+```scala
+val nums = Array(1, 2, 3, 4, 5)
+val doubledNums = nums.map(_ * 2)
+val filteredNums = nums.filter(_ > 2)
+```
+
+Because the Scala `Array` is represented in the same way as the Java `array`, you can easily use Java methods that return arrays in your Scala code.
+
+> Despite that discussion of `Array`, bear in mind that often in Scala there are alternatives to `Array` that might be better suited.
+> Arrays are useful for interoperating with other languages (Java, JavaScript) and they may also be useful when writing low-level code that needs to squeeze maximum performance out of the underlying platform. But in general, when you need to use a sequence, the Scala idiom is to prefer immutable sequences like `Vector` and `List`, and then use `ArrayBuffer` if and when when you really need a mutable sequence.
+
+You can also convert between Java and Scala collections classes with the Scala `CollectionConverters` objects.
+There are two objects in different packages, one for converting from Java to Scala, and another for converting from Scala to Java.
+This table shows the possible conversions:
+
+
+
+
+
Java
+
Scala
+
+
+
java.util.Collection
+
scala.collection.Iterable
+
+
+
java.util.List
+
scala.collection.mutable.Buffer
+
+
+
java.util.Set
+
scala.collection.mutable.Set
+
+
+
java.util.Map
+
scala.collection.mutable.Map
+
+
+
java.util.concurrent.ConcurrentMap
+
scala.collection.mutable.ConcurrentMap
+
+
+
java.util.Dictionary
+
scala.collection.mutable.Map
+
+
+
+
+
+
+## Methods on collections classes
+
+With the ability to treat Java collections as streams, Java and Scala now have many of the same common functional methods available to them:
+
+- `map`
+- `filter`
+- `forEach`/`foreach`
+- `findFirst`/`find`
+- `reduce`
+
+If you’re used to using these methods with lambda expressions in Java, you’ll find it easy to use the same methods on Scala’s [collection classes][collections-classes].
+
+Scala also has _dozens_ of other [collections methods][collections-methods], including `head`, `tail`, `drop`, `take`, `distinct`, `flatten`, and many more.
+At first you may wonder why there are so many methods, but after working with Scala you’ll realize that _because_ of these methods, you rarely ever need to write custom `for` loops any more.
+
+(This also means that you rarely need to _read_ custom `for` loops, as well.
+Because developers tend to spend on the order of ten times as much time _reading_ code as _writing_ code, this is significant.)
+
+
+
+## Tuples
+
+Java tuples are created like this:
+
+```scala
+Pair pair =
+ new Pair("Eleven", 11);
+
+Triplet triplet =
+ Triplet.with("Eleven", 11, 11.0);
+Quartet quartet =
+ Quartet.with("Eleven", 11, 11.0, new Person("Eleven"));
+```
+
+Other Java tuple names are Quintet, Sextet, Septet, Octet, Ennead, Decade.
+
+Tuples of any size in Scala are created by putting the values inside parentheses, like this:
+
+```scala
+val a = ("eleven")
+val b = ("eleven", 11)
+val c = ("eleven", 11, 11.0)
+val d = ("eleven", 11, 11.0, Person("Eleven"))
+```
+
+
+
+## Enums
+
+This section compares enumerations in Java and Scala.
+
+
+### Basic enum:
+
+
+ enum Planet(
+ mass: Double,
+ radius: Double
+ ):
+ case Mercury extends Planet(3.303e+23, 2.4397e6)
+ case Venus extends Planet(4.869e+24, 6.0518e6)
+ case Earth extends Planet(5.976e+24, 6.37814e6)
+ // more planets ...
+
+ private final val G = 6.67300E-11
+
+ def surfaceGravity = G * mass / (radius * radius)
+
+ def surfaceWeight(otherMass: Double)
+ = otherMass * surfaceGravity
+
+
+
+
+
+
+
+## Exceptions and error handling
+
+This section covers the differences between exception handling in Java and Scala.
+
+### Java uses checked exceptions
+
+Java uses checked exceptions, so in Java code you have historically written `try`/`catch`/`finally` blocks, along with `throws` clauses on methods:
+
+```scala
+public int makeInt(String s)
+throws NumberFormatException {
+ // code here to convert a String to an int
+}
+```
+
+### Scala doesn’t use checked exceptions
+
+The Scala idiom is to _not_ use checked exceptions like this.
+When working with code that can throw exceptions, you can use `try`/`catch`/`finally` blocks to catch exceptions from code that throws them, but how you proceed from there is different.
+
+The best way to explain this is that Scala code consists of _expressions_, which return values.
+As a result, you end up writing your code as a series of algebraic expressions:
+
+```scala
+val a = f(x)
+val b = g(a,z)
+val c = h(b,y)
+```
+
+This is nice, it’s just algebra.
+You create equations to solve small problems, and then combine equations to solve larger problems.
+
+And very importantly---as you remember from algebra courses---algebraic expressions don’t short circuit---they don’t throw exceptions that blow up a series of equations.
+
+Therefore, in Scala our methods don’t throw exceptions.
+Instead, they return types like `Option`.
+For example, this `makeInt` method catches a possible exception and returns an `Option` value:
+
+```scala
+def makeInt(s: String): Option[Int] =
+ try
+ Some(s.toInt)
+ catch
+ case e: NumberFormatException => None
+```
+
+The Scala `Option` is similar to the Java `Optional` class.
+As shown, if the string-to-int conversion succeeds, the `Int` is returned inside a `Some` value, and if it fails, a `None` value is returned.
+`Some` and `None` are subtypes of `Option`, so the method is declared to return the `Option[Int]` type.
+
+When you have an `Option` value, such as the one returned by `makeInt`, there are many ways to work with it, depending on your needs.
+This code shows one possible approach:
+
+```scala
+makeInt(aString) match
+ case Some(i) => println(s"Int i = $i")
+ case None => println(s"Could not convert $aString to an Int.")
+```
+
+`Option` is commonly used in Scala, and it’s built into many classes in the standard library.
+Other similar sets of classes like Try/Success/Failure and Either/Left/Right offer even more flexibility.
+
+For more information on dealing with errors and exceptions in Scala, see the [Functional Error Handling][error-handling] section.
+
+
+
+## Concepts that are unique to Scala
+
+That concludes are comparison of the Java and Scala languages.
+
+There are other concepts in Scala which currently have no equal in Java 11.
+This includes:
+
+- Everything related to Scala’s [contextual abstractions][contextual]
+- Several Scala method features:
+ - Multiple parameter lists
+ - Default parameter values
+ - Using named arguments when calling methods
+- Case classes (like “records” in Java 14), case objects, and companion classes and objects (see the [Domain Modeling][modeling-intro]) chapter
+- The ability to create your own control structures and DSLs
+- [Toplevel definitions][toplevel]
+- Pattern matching
+- Advanced features of `match` expressions
+- Type lambdas
+- Trait parameters
+- [Opaque type aliases][opaque]
+- [Multiversal equality][equality]
+- [Type classes][type-classes]
+- Infix methods
+- Macros and metaprogramming
+
+
+[collections-classes]: {% link _overviews/scala3-book/collections-classes.md %}
+[collections-methods]: {% link _overviews/scala3-book/collections-methods.md %}
+[control]: {% link _overviews/scala3-book/control-structures.md %}
+[equality]: {% link _overviews/scala3-book/ca-multiversal-equality.md %}
+[error-handling]: {% link _overviews/scala3-book/fp-functional-error-handling.md %}
+[extension-methods]: {% link _overviews/scala3-book/ca-extension-methods.md %}
+[givens]: {% link _overviews/scala3-book/ca-context-parameters.md %}
+[hofs]: {% link _overviews/scala3-book/fun-hofs.md %}
+[imports]: {% link _overviews/scala3-book/packaging-imports.md %}
+[modeling-intro]: {% link _overviews/scala3-book/domain-modeling-intro.md %}
+[modeling-oop]: {% link _overviews/scala3-book/domain-modeling-oop.md %}
+[opaque]: {% link _overviews/scala3-book/types-opaque-types.md %}
+[tools]: {% link _overviews/scala3-book/scala-tools.md %}
+[toplevel]: {% link _overviews/scala3-book/taste-toplevel-definitions.md %}
+[type-classes]: {% link _overviews/scala3-book/ca-type-classes.md %}
+
+
+
+
+
+[concurrency]: {% link _overviews/scala3-book/concurrency.md %}
+[contextual]: {% link _overviews/scala3-book/ca-contextual-abstractions-intro.md %}
+[control]: {% link _overviews/scala3-book/control-structures.md %}
+[fp-intro]: {% link _overviews/scala3-book/fp-intro.md %}
+[intersection-types]: {% link _overviews/scala3-book/types-intersection.md %}
+[modeling-fp]: {% link _overviews/scala3-book/domain-modeling-fp.md %}
+[multiversal]: {% link _overviews/scala3-book/ca-multiversal-equality.md %}
+[union-types]: {% link _overviews/scala3-book/types-union.md %}
+
+
diff --git a/_overviews/scala3-book/scala-for-javascript-devs.md b/_overviews/scala3-book/scala-for-javascript-devs.md
new file mode 100644
index 0000000000..26c672ae99
--- /dev/null
+++ b/_overviews/scala3-book/scala-for-javascript-devs.md
@@ -0,0 +1,1377 @@
+---
+title: Scala for JavaScript Developers
+type: chapter
+description: This chapter provides an introduction to Scala 3 for JavaScript developers
+languages: [zh-cn]
+num: 75
+previous-page: scala-for-java-devs
+next-page: scala-for-python-devs
+---
+
+{% include_relative scala4x.css %}
+
+
+
+This page provides a comparison between the JavaScript and Scala programming languages.
+It’s intended for programmers who know JavaScript and want to learn about Scala, specifically by seeing examples of how JavaScript language features compare to Scala.
+
+
+
+## Overview
+
+This section provides a relatively brief introduction and summary of the sections that follow.
+It presents the similarities and differences between JavaScript and Scala at a high level, and then introduces the differences you’ll experience every day as you write code.
+
+### High-level similarities
+
+At a high level, Scala shares these similarities with JavaScript:
+
+- Both are considered high-level programming languages, where you don’t have to concern yourself with low-level concepts like pointers and manual memory management
+- Both have a relatively simple, concise syntax
+- Both support a C/C++/Java style curly-brace syntax for writing methods and other block of code
+- Both include features (like classes) for object-oriented programming (OOP)
+- Both include features (like lambdas) for [functional programming][fp-intro] (FP)
+- JavaScript runs in the browser and other environments like Node.js.
+ The [Scala.js](https://www.scala-js.org) flavor of Scala targets JavaScript and Scala programs can thus run in the same environments.
+- Developers write server-side applications in JavaScript and Scala using [Node.js](https://nodejs.org); projects like the [Play Framework](https://www.playframework.com/) also let you write server-side applications in Scala
+- Both languages have similar `if` statements, `while` loops, and `for` loops
+- Starting [at this Scala.js page](https://www.scala-js.org/libraries/index.html), you’ll find dozens of libraries to support React, Angular, jQuery, and many other JavaScript and Scala libraries
+- JavaScript objects are mutable; Scala objects _can_ be mutable when writing in an imperative style
+- Both JavaScript and Scala support _promises_ as a way of handling the result of asynchronous computations ([Scala concurrency][concurrency] uses futures and promises)
+
+### High-level differences
+
+Also at a high level, some of the differences between JavaScript and Scala are:
+
+- JavaScript is dynamically typed, and Scala is statically typed
+ - Although Scala is statically typed, features like type inference make it feel like a dynamic language (as you’ll see in the examples that follow)
+- Scala idioms favor immutability by default: you’re encouraged to use immutable variables and immutable collections
+- Scala has a concise but readable syntax; we call it _expressive_
+- Scala is a pure OOP language, so every object is an instance of a class, and symbols like `+` and `+=` that look like operators are really methods; this means that you can create your own methods that work as operators
+- As a pure OOP language and a pure FP language, Scala encourages a fusion of OOP and FP, with functions for the logic and immutable objects for modularity
+- Scala has state of the art, third-party, open source functional programming libraries
+- Everything in Scala is an _expression_: constructs like `if` statements, `for` loops, `match` expressions, and even `try`/`catch` expressions all have return values
+- The [Scala Native](https://scala-native.org/) project lets you write “systems” level code, and also compiles to native executables
+
+### Programming level differences
+
+At a lower level, these are some of the differences you’ll see every day when writing code:
+
+- Scala variables and parameters are defined with `val` (immutable, like a JavaScript `const`) or `var` (mutable, like a JavaScript `var` or `let`)
+- Scala does not use semi-colons at the end of lines
+- Scala is statically-typed, though in many situations you don’t need to declare the type
+- Scala uses traits as interfaces and to create _mixins_
+- In addition to simple `for` loops, Scala has powerful `for` comprehensions that yield results based on your algorithms
+- Pattern matching and `match` expressions will change the way you write code
+- Scala’s [contextual abstractions][contextual] and _term inference_ provide a collection of features:
+ - [Extension methods][extension-methods] let you add new functionality to closed classes without breaking modularity, by being available only in specific scopes (as opposed to monkey-patching, which can pollute other areas of the code)
+ - [Given instances][givens] let you define terms that the compiler can use to synthesize code for you
+ - Type safety and [multiversal equality][multiversal] let you limit equality comparisons---at compile time---to only those comparisons that make sense
+- Thanks to features like by-name parameters, infix notation, optional parentheses, extension methods, and [higher-order functions][hofs], you can create your own “control structures” and DSLs
+- Many other goodies that you can read about throughout this book: case classes, companion classes and objects, macros, [union][union-types] and [intersection][intersection-types] types, multiple parameter lists, named arguments, and more
+
+
+
+## Variables and Types
+
+### Comments
+
+
+
+
+
+ //
+ /* ... */
+ /** ... */
+
+
+
+
+ //
+ /* ... */
+ /** ... */
+
+
+
+
+
+
+### Mutable variables
+
+
+
+
+
+ let // now preferred for mutable
+ var // old mutable style
+
+
+
+
+ var // used for mutable variables
+
+
+
+
+
+
+### Immutable values
+
+
+
+
+
+ const
+
+
+
+
+ val
+
+
+
+
+
+The rule of thumb in Scala is to declare variables using `val`, unless there’s a specific reason you need a mutable variable.
+
+
+
+## Naming standards
+
+JavaScript and Scala generally use the same _CamelCase_ naming standards.
+Variables are named like `myVariableName`, methods are named like `lastIndexOf`, and classes and object are named like `Animal` and `PrintedBook`.
+
+
+
+## Strings
+
+Many uses of strings are similar in JavaScript and Scala, though Scala only uses double-quotes for simple strings, and triple-quotes for multiline strings.
+
+
+### String basics
+
+
+
+
+
+ // use single- or double-quotes
+ let msg = 'Hello, world';
+ let msg = "Hello, world";
+
+
+
+
+ // use only double-quotes
+ val msg = "Hello, world"
+
+
+
+
+
+
+### Interpolation
+
+
+
+
+
+ let name = 'Joe';
+
+ // JavaScript uses backticks
+ let msg = `Hello, ${name}`;
+
+
+
+
+ val name = "Joe"
+ val age = 42
+ val weight = 180.5
+
+ // use `s` before a string for simple interpolation
+ println(s"Hi, $name") // "Hi, Joe"
+ println(s"${1 + 1}") // "2"
+
+ // `f` before a string allows printf-style formatting.
+ // this example prints:
+ // "Joe is 42 years old, and weighs"
+ // "180.5 pounds."
+ println(f"$name is $age years old, and weighs $weight%.1f pounds.")
+
+
+
+
+
+
+### Multiline strings with interpolation
+
+
+
+
+
+ let name = "joe";
+ let str = `
+ Hello, ${name}.
+ This is a multiline string.
+ `;
+
+
+
+
+
+ val name = "Martin Odersky"
+
+ val quote = s"""
+ |$name says
+ |Scala is a fusion of
+ |OOP and FP.
+ """.stripMargin.replaceAll("\n", " ").trim
+
+ // result:
+ // "Martin Odersky says Scala is a fusion of OOP and FP."
+
+
+
+
+
+
+JavaScript and Scala also have similar methods to work with strings, including `charAt`, `concat`, `indexOf`, and many more.
+Escape characters like `\n`, `\f`, `\t` are also the same in both languages.
+
+
+
+## Numbers and arithmetic
+
+Numeric operators are similar between JavaScript and Scala.
+The biggest difference is that Scala doesn’t offer `++` and `--` operators.
+
+
+### Numeric operators:
+
+
+
+
+
+ let x = 1;
+ let y = 2.0;
+
+ let a = 1 + 1;
+ let b = 2 - 1;
+ let c = 2 * 2;
+ let d = 4 / 2;
+ let e = 5 % 2;
+
+
+
+
+
+ val x = 1
+ val y = 2.0
+
+ val a = 1 + 1
+ val b = 2 - 1
+ val c = 2 * 2
+ val d = 4 / 2
+ val e = 5 % 2
+
+
+
+
+
+
+
+### Increment and decrement:
+
+
+
+
+
+ i++;
+ i += 1;
+
+ i--;
+ i -= 1;
+
+
+
+
+ i += 1;
+ i -= 1;
+
+
+
+
+
+Perhaps the biggest difference is that “operators” like `+` and `-` are really _methods_ in Scala, not operators.
+Scala numbers also have these related methods:
+
+```scala
+var a = 2
+a *= 2 // 4
+a /= 2 // 2
+```
+
+Scala's `Double` type most closely corresponds to JavaScript’s default `number` type,
+`Int` represents signed 32-bit integer values, and `BigInt` corresponds to JavaScript's `bigint`.
+
+These are Scala `Int` and `Double` values.
+Notice that the type doesn’t have to be explicitly declared:
+
+```scala
+val i = 1 // Int
+val d = 1.1 // Double
+```
+
+You can also use other numeric types as needed:
+
+```scala
+val a: Byte = 0 // Byte = 0
+val a: Double = 0 // Double = 0.0
+val a: Float = 0 // Float = 0.0
+val a: Int = 0 // Int = 0
+val a: Long = 0 // Long = 0
+val a: Short = 0 // Short = 0
+
+val x = BigInt(1_234_456_789)
+val y = BigDecimal(1_234_456.890)
+```
+
+
+### Boolean values
+
+Both languages use `true` and `false` for boolean values:
+
+
+
+
+
+ let a = true;
+ let b = false;
+
+
+
+
+ val a = true
+ val b = false
+
+
+
+
+
+
+
+## Dates
+
+Dates are another commonly used type in both languages.
+
+### Get the current date:
+
+
+
+
+
+ let d = new Date();
+ // result:
+ // Sun Nov 29 2020 18:47:57 GMT-0700 (Mountain Standard Time)
+
+
+
+
+
+ // different ways to get the current date and time
+ import java.time.*
+
+ val a = LocalDate.now
+ // 2020-11-29
+ val b = LocalTime.now
+ // 18:46:38.563737
+ val c = LocalDateTime.now
+ // 2020-11-29T18:46:38.563750
+ val d = Instant.now
+ // 2020-11-30T01:46:38.563759Z
+
+
+
+
+
+
+### Specify a different date:
+
+
+
+
+
+ let d = Date(2020, 1, 21, 1, 0, 0, 0);
+ let d = Date(2020, 1, 21, 1, 0, 0);
+ let d = Date(2020, 1, 21, 1, 0);
+ let d = Date(2020, 1, 21, 1);
+ let d = Date(2020, 1, 21);
+
+
+
+
+ val d = LocalDate.of(2020, 1, 21)
+ val d = LocalDate.of(2020, Month.JANUARY, 21)
+ val d = LocalDate.of(2020, 1, 1).plusDays(20)
+
+
+
+
+
+
+In this case, Scala uses the date and time classes that come with Java.
+Many date/time methods are similar between JavaScript and Scala.
+See [the _java.time_ package](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/package-summary.html) for more details.
+
+
+
+## Functions
+
+In both JavaScript and Scala, functions are objects, so their functionality is similar, but their syntax and terminology is a little different.
+
+### Named functions, one line:
+
+
+
+
+
+ function add(a, b) {
+ return a + b;
+ }
+ add(2, 2); // 4
+
+
+
+
+ // technically this is a method, not a function
+ def add(a: Int, b: Int) = a + b
+ add(2, 2) // 4
+
+
+
+
+
+### Named functions, multiline:
+
+
+
+
+
+ function addAndDouble(a, b) {
+ // imagine this requires
+ // multiple lines
+ return (a + b) * 2
+ }
+
+
+
+
+ def addAndDouble(a: Int, b: Int): Int =
+ // imagine this requires
+ // multiple lines
+ (a + b) * 2
+
+
+
+
+
+In Scala, showing the `Int` return type is optional.
+It’s _not_ shown in the `add` example and _is_ shown in the `addAndDouble` example, so you can see both approaches.
+
+
+
+## Anonymous functions
+
+Both JavaScript and Scala let you define anonymous functions, which you can pass into other functions and methods.
+
+### Arrow and anonymous functions
+
+
+
+
+
+ // arrow function
+ let log = (s) => console.log(s)
+
+ // anonymous function
+ let log = function(s) {
+ console.log(s);
+ }
+
+ // use either of those functions here
+ function printA(a, log) {
+ log(a);
+ }
+
+
+
+
+ // a function (an anonymous function assigned to a variable)
+ val log = (s: String) => console.log(s)
+
+ // a scala method. methods tend to be used much more often,
+ // probably because they’re easier to read.
+ def log(a: Any) = console.log(a)
+
+ // a function or a method can be passed into another
+ // function or method
+ def printA(a: Any, f: log: Any => Unit) = log(a)
+
+
+
+
+
+
+In Scala you rarely define a function using the first syntax shown.
+Instead, you often define anonymous functions right at the point of use.
+Many collections methods are [higher-order functions][hofs] and accept function parameters, so you write code like this:
+
+```scala
+// map method, long form
+List(1,2,3).map(i => i * 10) // List(10,20,30)
+
+// map, short form (which is more commonly used)
+List(1,2,3).map(_ * 10) // List(10,20,30)
+
+// filter, short form
+List(1,2,3).filter(_ < 3) // List(1,2)
+
+// filter and then map
+List(1,2,3,4,5).filter(_ < 3).map(_ * 10) // List(10, 20)
+```
+
+
+
+## Classes
+
+Scala has both classes and case classes.
+A _class_ is similar to a JavaScript class, and is generally intended for use in [OOP style applications][modeling-oop] (though they can also be used in FP code), and _case classes_ have additional features that make them very useful in [FP style applications][modeling-fp].
+
+The following example shows how to create several types as enumerations, and then defines an OOP-style `Pizza` class.
+At the end, a `Pizza` instance is created and used:
+
+```scala
+// create some enumerations that the Pizza class will use
+enum CrustSize:
+ case Small, Medium, Large
+
+enum CrustType:
+ case Thin, Thick, Regular
+
+enum Topping:
+ case Cheese, Pepperoni, BlackOlives, GreenOlives, Onions
+
+// import those enumerations and the ArrayBuffer,
+// so the Pizza class can use them
+import CrustSize.*
+import CrustType.*
+import Topping.*
+import scala.collection.mutable.ArrayBuffer
+
+// define an OOP style Pizza class
+class Pizza(
+ var crustSize: CrustSize,
+ var crustType: CrustType
+):
+
+ private val toppings = ArrayBuffer[Topping]()
+
+ def addTopping(t: Topping): Unit =
+ toppings += t
+
+ def removeTopping(t: Topping): Unit =
+ toppings -= t
+
+ def removeAllToppings(): Unit =
+ toppings.clear()
+
+ override def toString(): String =
+ s"""
+ |Pizza:
+ | Crust Size: ${crustSize}
+ | Crust Type: ${crustType}
+ | Toppings: ${toppings}
+ """.stripMargin
+
+end Pizza
+
+// create a Pizza instance
+val p = Pizza(Small, Thin)
+
+// change the crust
+p.crustSize = Large
+p.crustType = Thick
+
+// add and remove toppings
+p.addTopping(Cheese)
+p.addTopping(Pepperoni)
+p.addTopping(BlackOlives)
+p.removeTopping(Pepperoni)
+
+// print the pizza, which uses its `toString` method
+println(p)
+```
+
+
+
+## Interfaces, traits, and inheritance
+
+Scala uses traits as interfaces, and also to create mixins.
+Traits can have both abstract and concrete members, including methods and fields.
+
+This example shows how to define two traits, create a class that extends and implements those traits, and then create and use an instance of that class:
+
+```scala
+trait HasLegs:
+ def numLegs: Int
+ def walk(): Unit
+ def stop() = println("Stopped walking")
+
+trait HasTail:
+ def wagTail(): Unit
+ def stopTail(): Unit
+
+class Dog(var name: String) extends HasLegs, HasTail:
+ val numLegs = 4
+ def walk() = println("I’m walking")
+ def wagTail() = println("⎞⎜⎛ ⎞⎜⎛")
+ def stopTail() = println("Tail is stopped")
+ override def toString = s"$name is a Dog"
+
+// create a Dog instance
+val d = Dog("Rover")
+
+// use the class’s attributes and behaviors
+println(d.numLegs) // 4
+d.wagTail() // "⎞⎜⎛ ⎞⎜⎛"
+d.walk() // "I’m walking"
+```
+
+
+
+## Control Structures
+
+Except for the use of `===` and `!==` in JavaScript, comparison and logical operators are almost identical in JavaScript and Scala.
+
+{% comment %}
+TODO: Sébastien mentioned that `===` is closest to `eql` in Scala. Update this area.
+{% endcomment %}
+
+### Comparison operators
+
+
+
+
+
JavaScript
+
Scala
+
+
+
+ ==
+
+ ==
+
+
+
+ ===
+
+ ==
+
+
+
+ !=
+
+ !=
+
+
+
+ !==
+
+ !=
+
+
+
+ >
+
+ >
+
+
+
+ <
+
+ <
+
+
+
+ >=
+
+ >=
+
+
+
+ <=
+
+ <=
+
+
+
+
+### Logical operators
+
+
+
+
+
JavaScript
+
Scala
+
+
+
+ &&
+ ||
+ !
+
+
+ &&
+ ||
+ !
+
+
+
+
+
+
+
+## if/then/else expressions
+
+JavaScript and Scala if/then/else statements are similar.
+In Scala 2 they were almost identical, but with Scala 3, curly braces are no longer necessary (though they can still be used).
+
+### `if` statement, one line:
+
+
+
+
+
+ if (x == 1) { console.log(1); }
+
+
+
+
+ if x == 1 then println(x)
+
+
+
+
+
+### `if` statement, multiline:
+
+
+
+
+
+ if (x == 1) {
+ console.log("x is 1, as you can see:")
+ console.log(x)
+ }
+
+
+
+
+ if x == 1 then
+ println("x is 1, as you can see:")
+ println(x)
+
+ if x < 0 then
+ println("negative")
+ else if x == 0
+ println("zero")
+ else
+ println("positive")
+
+
+
+
+
+### Returning a value from `if`:
+
+JavaScript uses a ternary operator, and Scala uses its `if` expression as usual:
+
+
+
+
+
+ let minVal = a < b ? a : b;
+
+
+
+
+ val minValue = if a < b then a else b
+
+
+
+
+
+### `if` as the body of a method:
+
+Scala methods tend to be very short, and you can easily use `if` as the body of a method:
+
+
+
+
+
+ function min(a, b) {
+ return (a < b) ? a : b;
+ }
+
+
+
+
+ def min(a: Int, b: Int): Int =
+ if a < b then a else b
+
+
+
+
+
+In Scala 3 you can still use the “curly brace” style, if you prefer.
+For instance, you can write an if/else-if/else expression like this:
+
+```scala
+if (i == 0) {
+ println(0)
+} else if (i == 1) {
+ println(1)
+} else {
+ println("other")
+}
+```
+
+
+
+## Loops
+
+Both JavaScript and Scala have `while` loops and `for` loops.
+Scala used to have do/while loops, but they have been removed from the language.
+
+### `while` loop:
+
+
+
+
+
+ let i = 0;
+ while (i < 3) {
+ console.log(i);
+ i++;
+ }
+
+
+
+
+ var i = 0;
+ while i < 3 do
+ println(i)
+ i += 1
+
+
+
+
+
+The Scala code can also be written like this, if you prefer:
+
+```scala
+var i = 0
+while (i < 3) {
+ println(i)
+ i += 1
+}
+```
+
+The following examples show `for` loops in JavaScript and Scala.
+They assume that you have these collections to work with:
+
+```scala
+// JavaScript
+let nums = [1, 2, 3];
+
+// Scala
+val nums = List(1, 2, 3)
+```
+
+### `for` loop, single line
+
+
+
+
+
+ // newer syntax
+ for (let i of nums) {
+ console.log(i);
+ }
+
+ // older
+ for (i=0; i<nums.length; i++) {
+ console.log(nums[i]);
+ }
+
+
+
+
+ // preferred
+ for i <- nums do println(i)
+
+ // also available
+ for (i <- nums) println(i)
+
+
+
+
+
+### `for` loop, multiple lines in the body
+
+
+
+
+
+ // preferred
+ for (let i of nums) {
+ let j = i * 2;
+ console.log(j);
+ }
+
+ // also available
+ for (i=0; i<nums.length; i++) {
+ let j = nums[i] * 2;
+ console.log(j);
+ }
+
+
+
+
+ // preferred
+ for i <- nums do
+ val j = i * 2
+ println(j)
+
+ // also available
+ for (i <- nums) {
+ val j = i * 2
+ println(j)
+ }
+
+
+
+
+
+### Multiple generators in a `for` loop
+
+
+
+
+
+ let str = "ab";
+ for (let i = 1; i < 3; i++) {
+ for (var j = 0; j < str.length; j++) {
+ for (let k = 1; k < 11; k += 5) {
+ let c = str.charAt(j);
+ console.log(`i: ${i} j: ${c} k: ${k}`);
+ }
+ }
+ }
+
+
+
+
+ for
+ i <- 1 to 2
+ j <- 'a' to 'b'
+ k <- 1 to 10 by 5
+ do
+ println(s"i: $i, j: $j, k: $k")
+
+
+
+
+
+### Generator with guards
+
+A _guard_ is a name for an `if` expression inside a `for` expression.
+
+
+
+
+
+ for (let i = 0; i < 10; i++) {
+ if (i % 2 == 0 && i < 5) {
+ console.log(i);
+ }
+ }
+
+
+
+
+ for
+ i <- 1 to 10
+ if i % 2 == 0
+ if i < 5
+ do
+ println(i)
+
+
+
+
+
+### `for` comprehension
+
+A `for` comprehension is a `for` loop that uses `yield` to return (yield) a value. They’re used often in Scala.
+
+
+
+
+
+ N/A
+
+
+
+
+ val list =
+ for
+ i <- 1 to 3
+ yield
+ i * 10
+ // result: Vector(10, 20, 30)
+
+
+
+
+
+
+
+## switch & match
+
+Where JavaScript has `switch` statements, Scala has `match` expressions.
+Like everything else in Scala, these truly are _expressions_, meaning they return a result:
+
+```scala
+val day = 1
+
+// later in the code ...
+val monthAsString = day match
+ case 1 => "January"
+ case 2 => "February"
+ case _ => "Other"
+```
+
+`match` expressions can handle multiple matches in each `case` statement:
+
+```scala
+val numAsString = i match
+ case 1 | 3 | 5 | 7 | 9 => "odd"
+ case 2 | 4 | 6 | 8 | 10 => "even"
+ case _ => "too big"
+```
+
+They can also be used as the body of a method:
+
+```scala
+def isTruthy(a: Matchable) = a match
+ case 0 | "" => false
+ case _ => true
+
+def isPerson(x: Matchable): Boolean = x match
+ case p: Person => true
+ case _ => false
+```
+
+`match` expressions have many other pattern-matching options.
+
+
+
+## Collections classes
+
+Scala has different [collections classes][collections-classes] for different needs.
+
+Common _immutable_ sequences are:
+
+- `List`
+- `Vector`
+
+Common _mutable_ sequences are:
+
+- `Array`
+- `ArrayBuffer`
+
+Scala also has mutable and immutable Maps and Sets.
+
+This is how you create the common Scala collection types:
+
+```scala
+val strings = List("a", "b", "c")
+val strings = Vector("a", "b", "c")
+val strings = ArrayBuffer("a", "b", "c")
+
+val set = Set("a", "b", "a") // result: Set("a", "b")
+val map = Map(
+ "a" -> 1,
+ "b" -> 2,
+ "c" -> 3
+)
+```
+
+### Methods on collections
+
+The following examples show many different ways to work with Scala collections.
+
+### Populating lists:
+
+```scala
+// to, until
+(1 to 5).toList // List(1, 2, 3, 4, 5)
+(1 until 5).toList // List(1, 2, 3, 4)
+
+(1 to 10 by 2).toList // List(1, 3, 5, 7, 9)
+(1 until 10 by 2).toList // List(1, 3, 5, 7, 9)
+(1 to 10).by(2).toList // List(1, 3, 5, 7, 9)
+
+('d' to 'h').toList // List(d, e, f, g, h)
+('d' until 'h').toList // List(d, e, f, g)
+('a' to 'f').by(2).toList // List(a, c, e)
+
+// range method
+List.range(1, 3) // List(1, 2)
+List.range(1, 6, 2) // List(1, 3, 5)
+
+List.fill(3)("foo") // List(foo, foo, foo)
+List.tabulate(3)(n => n * n) // List(0, 1, 4)
+List.tabulate(4)(n => n * n) // List(0, 1, 4, 9)
+```
+
+### Functional methods on sequences:
+
+```scala
+// these examples use a List, but they’re the same with Vector
+val a = List(10, 20, 30, 40, 10) // List(10, 20, 30, 40, 10)
+a.contains(20) // true
+a.distinct // List(10, 20, 30, 40)
+a.drop(2) // List(30, 40, 10)
+a.dropRight(2) // List(10, 20, 30)
+a.dropWhile(_ < 25) // List(30, 40, 10)
+a.filter(_ < 25) // List(10, 20, 10)
+a.filter(_ > 100) // List()
+a.find(_ > 20) // Some(30)
+a.head // 10
+a.headOption // Some(10)
+a.init // List(10, 20, 30, 40)
+a.last // 10
+a.lastOption // Some(10)
+a.slice(2,4) // List(30, 40)
+a.tail // List(20, 30, 40, 10)
+a.take(3) // List(10, 20, 30)
+a.takeRight(2) // List(40, 10)
+a.takeWhile(_ < 30) // List(10, 20)
+
+// map, flatMap
+val fruits = List("apple", "pear")
+fruits.map(_.toUpperCase) // List(APPLE, PEAR)
+fruits.flatMap(_.toUpperCase) // List(A, P, P, L, E, P, E, A, R)
+
+val nums = List(10, 5, 8, 1, 7)
+nums.sorted // List(1, 5, 7, 8, 10)
+nums.sortWith(_ < _) // List(1, 5, 7, 8, 10)
+nums.sortWith(_ > _) // List(10, 8, 7, 5, 1)
+
+List(1,2,3).updated(0,10) // List(10, 2, 3)
+List(2,4).union(List(1,3)) // List(2, 4, 1, 3)
+
+// zip
+val women = List("Wilma", "Betty") // List(Wilma, Betty)
+val men = List("Fred", "Barney") // List(Fred, Barney)
+val couples = women.zip(men) // List((Wilma,Fred), (Betty,Barney))
+```
+
+Scala has _many_ more methods that are available to you.
+The benefits of all these methods are:
+
+- You don’t have to write custom `for` loops to solve problems
+- When you read someone else’s code, you won’t have to read their custom `for` loops; you’ll just find common methods like these, so it’s easier to read code from different projects
+
+
+### Tuples
+
+When you want to put multiple data types in the same list, JavaScript lets you do this:
+
+```scala
+let stuff = ["Joe", 42, 1.0];
+```
+
+In Scala you do this:
+
+```scala
+val a = ("eleven")
+val b = ("eleven", 11)
+val c = ("eleven", 11, 11.0)
+val d = ("eleven", 11, 11.0, Person("Eleven"))
+```
+
+In Scala these types are called tuples, and as shown, they can contain one or more elements, and the elements can have different types.
+You access their elements just like you access elements of a `List`, `Vector`, or `Array`:
+
+```scala
+d(0) // "eleven"
+d(1) // 11
+```
+
+### Enumerations
+
+JavaScript doesn’t have enumerations, but you can do this:
+
+```javascript
+let Color = {
+ RED: 1,
+ GREEN: 2,
+ BLUE: 3
+};
+Object.freeze(Color);
+```
+
+In Scala 3 you can do quite a few things with enumerations.
+You can create an equivalent of that code:
+
+```scala
+enum Color:
+ case Red, Green, Blue
+```
+
+You can create a parameterized enum:
+
+```scala
+enum Color(val rgb: Int):
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+```
+
+You can also create user-defined enum members:
+
+```scala
+enum Planet(mass: Double, radius: Double):
+ case Mercury extends Planet(3.303e+23, 2.4397e6)
+ case Venus extends Planet(4.869e+24,6.0518e6)
+ case Earth extends Planet(5.976e+24,6.37814e6)
+ // more planets here ...
+
+ private final val G = 6.67300E-11
+ def surfaceGravity = G * mass / (radius * radius)
+ def surfaceWeight(otherMass: Double) = otherMass * surfaceGravity
+```
+
+
+
+## Scala.js DOM Code
+
+Scala.js lets you write Scala code that is compiled to JavaScript code that can then be used in the browser.
+The approach is similar to TypeScript, ReScript, and other languages that are compiled to JavaScript.
+
+Once you include the necessary libraries, and import the necessary packages in your project, writing Scala.js code looks very similar to writing JavaScript code:
+
+```scala
+// show an alert dialog on a button click
+jQuery("#hello-button").click{() =>
+ dom.window.alert("Hello, world")
+}
+
+// define a button and what should happen when it’s clicked
+val btn = button(
+ "Click me",
+ onclick := { () =>
+ dom.window.alert("Hello, world")
+ })
+
+// create two divs with css classes, an h2 element, and the button
+val content =
+ div(cls := "foo",
+ div(cls := "bar",
+ h2("Hello"),
+ btn
+ )
+ )
+
+// add the content to the DOM
+val root = dom.document.getElementById("root")
+root.innerHTML = ""
+root.appendChild(content.render)
+```
+
+Note that although Scala is a type-safe language, no types are declared in the above code.
+Scala’s strong type inference capabilities often make Scala code look like it’s dynamically typed.
+But it is type-safe, so you catch many classes of errors early in the development cycle.
+
+
+
+## Other Scala.js resources
+
+The Scala.js website has an excellent collection of tutorials for JavaScript developers interested in using Scala.js.
+Here are some of their initial tutorials:
+
+- [Basic tutorial (creating a first Scala.js project)](https://www.scala-js.org/doc/tutorial/basic/)
+- [Scala.js for JavaScript developers](https://www.scala-js.org/doc/sjs-for-js/)
+- [From ES6 to Scala: Basics](https://www.scala-js.org/doc/sjs-for-js/es6-to-scala-part1.html)
+- [From ES6 to Scala: Collections](https://www.scala-js.org/doc/sjs-for-js/es6-to-scala-part2.html)
+- [From ES6 to Scala: Advanced](https://www.scala-js.org/doc/sjs-for-js/es6-to-scala-part3.html)
+
+
+
+## Concepts that are unique to Scala
+
+There are other concepts in Scala which currently have no equivalent in JavaScript:
+
+- Almost everything related to [contextual abstractions][contextual]
+- Method features:
+ - Multiple parameter lists
+ - Using named arguments when calling methods
+- Using traits as interfaces
+- Case classes
+- Companion classes and objects
+- The ability to create your own [control structures][control] and DSLs
+- Advanced features of `match` expressions and pattern matching
+- `for` comprehensions
+- Infix methods
+- Macros and metaprogramming
+- More ...
+
+
+[collections-classes]: {% link _overviews/scala3-book/collections-classes.md %}
+[concurrency]: {% link _overviews/scala3-book/concurrency.md %}
+[contextual]: {% link _overviews/scala3-book/ca-contextual-abstractions-intro.md %}
+[control]: {% link _overviews/scala3-book/control-structures.md %}
+[extension-methods]: {% link _overviews/scala3-book/ca-extension-methods.md %}
+[fp-intro]: {% link _overviews/scala3-book/fp-intro.md %}
+[givens]: {% link _overviews/scala3-book/ca-context-parameters.md %}
+[hofs]: {% link _overviews/scala3-book/fun-hofs.md %}
+[intersection-types]: {% link _overviews/scala3-book/types-intersection.md %}
+[modeling-fp]: {% link _overviews/scala3-book/domain-modeling-fp.md %}
+[modeling-oop]: {% link _overviews/scala3-book/domain-modeling-oop.md %}
+[multiversal]: {% link _overviews/scala3-book/ca-multiversal-equality.md %}
+[union-types]: {% link _overviews/scala3-book/types-union.md %}
+
+
diff --git a/_overviews/scala3-book/scala-for-python-devs.md b/_overviews/scala3-book/scala-for-python-devs.md
new file mode 100644
index 0000000000..147f5977f7
--- /dev/null
+++ b/_overviews/scala3-book/scala-for-python-devs.md
@@ -0,0 +1,1391 @@
+---
+title: Scala for Python Developers
+type: chapter
+description: This page is for Python developers who are interested in learning about Scala 3.
+languages: [zh-cn]
+num: 76
+previous-page: scala-for-javascript-devs
+next-page: where-next
+---
+
+{% include_relative scala4x.css %}
+
+
+
+{% comment %}
+
+NOTE: Hopefully someone with more Python experience can give this a thorough review.
+
+NOTE: On this page (https://contributors.scala-lang.org/t/feedback-sought-optional-braces/4702/10), Li Haoyi comments: “Python’s success also speaks for itself; beginners certainly don’t pick Python because of performance, ease of installation, packaging, IDE support, or simplicity of the language’s runtime semantics!” I’m not a Python expert, so these points are good to know, though I don’t want to go negative in any comparisons.
+It’s more like thinking, “Python developers will appreciate Scala’s performance, ease of installation, packaging, IDE support, etc.”
+{% endcomment %}
+
+{% comment %}
+TODO: We should probably go through this document and add links to our other detail pages, when time permits.
+{% endcomment %}
+
+This section provides a comparison between the Python and Scala programming languages.
+It’s intended for programmers who know Python and want to learn about Scala, specifically by seeing examples of how Python language features compare to Scala.
+
+## Introduction
+
+Before getting into the examples, this first section provides a relatively brief introduction and summary of the sections that follow.
+The two languages are first compared at a high level, and then at an everyday programming level.
+
+### High level similarities
+
+At a high level, Scala shares these *similarities* with Python:
+
+- Both are high-level programming languages, where you don’t have to concern yourself with low-level concepts like pointers and manual memory management
+- Both have a relatively simple, concise syntax
+- Both support a [functional style of programming][fp-intro]
+- Both are object-oriented programming (OOP) languages
+- Both have comprehensions: Python has list comprehensions and Scala has `for` comprehensions
+- Both languages have support for lambdas and [higher-order functions][hofs]
+- Both can be used with [Apache Spark](https://spark.apache.org) for big data processing
+- Both have a wealth of terrific libraries
+
+### High level differences
+
+Also at a high level, the _differences_ between Python and Scala are:
+
+- Python is dynamically typed, and Scala is statically typed
+ - Though it's dynamically typed, Python supports "gradual typing" with type hints, which are checked by static type checkers, like `mypy`
+ - Though it’s statically typed, Scala features like type inference make it feel like a dynamic language
+- Python is interpreted, and Scala code is compiled to _.class_ files, and runs on the Java Virtual Machine (JVM)
+- In addition to running on the JVM, the [Scala.js](https://www.scala-js.org) project lets you use Scala as a JavaScript replacement
+- The [Scala Native](https://scala-native.org/) project lets you write “systems” level code, and compiles to native executables
+- Everything in Scala is an _expression_: constructs like `if` statements, `for` loops, `match` expressions, and even `try`/`catch` expressions all have return values
+- Scala idioms favor immutability by default: you’re encouraged to use immutable variables and immutable collections
+- Scala has excellent support for [concurrent and parallel programming][concurrency]
+
+### Programming level similarities
+
+This section looks at the similarities you’ll see between Python and Scala when you write code on an everyday basis:
+
+- Scala’s type inference often makes it feel like a dynamically typed language
+- Neither language uses semicolons to end expressions
+- Both languages support the use of significant indentation rather than braces and parentheses
+- The syntax for defining methods is similar
+- Both have lists, dictionaries (maps), sets, and tuples
+- Both have comprehensions for mapping and filtering
+- Both have terrific IDE support
+- With Scala 3’s [toplevel definitions][toplevel] you can put method, field, and other definitions anywhere
+ - One difference is that Python can operate without even declaring a single method, while Scala 3 can’t do _everything_ at the toplevel; for instance, a [main method][main-method] (`@main def`) is required to start a Scala application
+
+### Programming level differences
+
+Also at a programming level, these are some of the differences you’ll see every day when writing code:
+
+- Programming in Scala feels very consistent:
+ - `val` and `var` fields are used consistently to define fields and parameters
+ - Lists, maps, sets, and tuples are all created and accessed similarly; for instance, parentheses are used to create all types---`List(1,2,3)`, `Set(1,2,3)`, `Map(1->"one")`---just like creating any other Scala class
+ - [Collections classes][collections-classes] generally have most of the same higher-order functions
+ - Pattern matching is used consistently throughout the language
+ - The syntax that’s used to define functions that are passed into methods is the same syntax that’s used to define anonymous functions
+- Scala variables and parameters are defined with the `val` (immutable) or `var` (mutable) keywords
+- Scala idioms prefer immutable data structures
+- Comments: Python uses `#` for comments; Scala uses the C, C++, and Java style: `//`, `/*...*/`, and `/**...*/`
+- Naming conventions: The Python standard is to use underscores like `my_list`; Scala uses `myList`
+- Scala is statically typed, so you declare types for method parameters, method return values, and in other places
+- Pattern matching and `match` expressions are used extensively in Scala (and will change the way you write code)
+- Traits are used heavily in Scala; interfaces and abstract classes are used less often in Python
+- Scala’s [contextual abstractions][contextual] and _term inference_ provide a collection of different features:
+ - [Extension methods][extension-methods] let you easily add new functionality to classes using a clear syntax
+ - [Multiversal equality][multiversal] lets you limit equality comparisons---at compile time---to only those comparisons that make sense
+- Scala has state-of-the-art open source functional programming libraries (see the [“Awesome Scala” list](https://github.com/lauris/awesome-scala))
+- You can create your own “control structures” and DSLs, thanks to features like objects, by-name parameters, infix notation, optional parentheses, extension methods, higher-order functions, and more
+- Scala code can run in the JVM and even be compiled to native images (using [Scala Native](https://github.com/scala-native/scala-native) and [GraalVM](https://www.graalvm.org)) for high performance
+- Many other goodies: companion classes and objects, macros, numeric literals, multiple parameter lists, [intersection][intersection-types] types, type-level programming, and more
+
+### Features compared with examples
+
+Given that introduction, the following sections provide side-by-side comparisons of Python and Scala programming language features.
+
+{% comment %}
+TODO: Update the Python examples to use four spaces. I started to do this, but then thought it would be better to do that in a separate PR.
+{% endcomment %}
+
+## Comments
+
+Python uses `#` for comments, while the Scala comment syntax is the same as languages like C, C++, and Java:
+
+
+
+
+
+ # a comment
+
+
+
+
+ // a comment
+ /* ... */
+ /** ... */
+
+
+
+
+
+## Variable assignment
+
+These examples demonstrate how to create variables in Python and Scala.
+
+### Create integer and string variables:
+
+
+
+
+
+ x = 1
+ x = "Hi"
+ y = """foo
+ bar
+ baz"""
+
+
+
+
+ val x = 1
+ val x = "Hi"
+ val y = """foo
+ bar
+ baz"""
+
+
+If a Scala field is going to be mutable, use `var` instead of `val` for variable definition:
+
+```scala
+var x = 1
+x += 1
+```
+
+However, the rule of thumb in Scala is to always use `val` unless the variable specifically needs to be mutated.
+
+## FP style records
+
+Scala case classes are similar to Python frozen dataclasses.
+
+### Constructor definition:
+
+
+
+
+
+ from dataclasses import dataclass, replace
+
+ @dataclass(frozen=True)
+ class Person:
+ name: str
+ age: int
+
+
+
+
+ case class Person(name: String, age: Int)
+
+
+
+
+
+### Create and use an instance:
+
+
+
+
+
+ p = Person("Alice", 42)
+ p.name # Alice
+ p2 = replace(p, age=43)
+
+
+
+
+ val p = Person("Alice", 42)
+ p.name // Alice
+ val p2 = p.copy(age = 43)
+
+
+
+
+
+## OOP style classes and methods
+
+This section provides comparisons of features related to OOP-style classes and methods.
+
+### OOP style class, primary constructor:
+
+
+
+
+
+ class Person(object):
+ def __init__(self, name):
+ self.name = name
+
+ def speak(self):
+ print(f'Hello, my name is {self.name}')
+
+
+
+
+ class Person (var name: String):
+ def speak() = println(s"Hello, my name is $name")
+
+
+
+
+
+### Create and use an instance:
+
+
+
+
+
+ p = Person("John")
+ p.name # John
+ p.name = 'Fred'
+ p.name # Fred
+ p.speak()
+
+
+
+
+ val p = Person("John")
+ p.name // John
+ p.name = "Fred"
+ p.name // Fred
+ p.speak()
+
+
+## Interfaces, traits, and inheritance
+
+If you’re familiar with Java 8 and newer, Scala traits are similar to those Java interfaces.
+Traits are used all the time in Scala, while Python interfaces (Protocols) and abstract classes are used much less often.
+Therefore, rather than attempt to compare the two, this example shows how to use Scala traits to build a small solution to a simulated math problem:
+
+```scala
+trait Adder:
+ def add(a: Int, b: Int) = a + b
+
+trait Multiplier:
+ def multiply(a: Int, b: Int) = a * b
+
+// create a class from the traits
+class SimpleMath extends Adder, Multiplier
+val sm = new SimpleMath
+sm.add(1,1) // 2
+sm.multiply(2,2) // 4
+```
+
+There are [many other ways to use traits with classes and objects][modeling-intro], but this gives you a little idea of how they can be used to organize concepts into logical groups of behavior, and then merge them as needed to create a complete solution.
+
+## Control structures
+
+This section compares [control structures][control-structures] in Python and Scala.
+Both languages have constructs like `if`/`else`, `while`, `for` loops, and `try`.
+Scala also has `match` expressions.
+
+### `if` statement, one line:
+
+
+
+
+
+ if x == 1: print(x)
+
+
+
+
+ if x == 1 then println(x)
+
+
+
+
+
+### `if` statement, multiline:
+
+
+
+
+
+ if x == 1:
+ print("x is 1, as you can see:")
+ print(x)
+
+
+
+
+ if x == 1 then
+ println("x is 1, as you can see:")
+ println(x)
+
+
+
+
+
+### if, else if, else:
+
+
+
+
+
+ if x < 0:
+ print("negative")
+ elif x == 0:
+ print("zero")
+ else:
+ print("positive")
+
+
+
+
+ if x < 0 then
+ println("negative")
+ else if x == 0 then
+ println("zero")
+ else
+ println("positive")
+
+
+
+
+
+### Returning a value from `if`:
+
+
+
+
+
+ min_val = a if a < b else b
+
+
+
+
+ val minValue = if a < b then a else b
+
+
+
+
+
+### `if` as the body of a method:
+
+
+
+
+
+ def min(a, b):
+ return a if a < b else b
+
+
+
+
+ def min(a: Int, b: Int): Int =
+ if a < b then a else b
+
+
+
+
+
+### `while` loop:
+
+
+
+
+
+ i = 1
+ while i < 3:
+ print(i)
+ i += 1
+
+
+
+
+ var i = 1
+ while i < 3 do
+ println(i)
+ i += 1
+
+
+
+
+
+### `for` loop with range:
+
+
+
+
+
+ for i in range(0,3):
+ print(i)
+
+
+
+
+ // preferred
+ for i <- 0 until 3 do println(i)
+
+ // also available
+ for (i <- 0 until 3) println(i)
+
+ // multiline syntax
+ for
+ i <- 0 until 3
+ do
+ println(i)
+
+
+
+
+
+### `for` loop with a list:
+
+
+
+
+
+ for i in ints: print(i)
+
+ for i in ints:
+ print(i)
+
+
+
+
+ for i <- ints do println(i)
+
+
+
+
+
+### `for` loop, multiple lines:
+
+
+
+
+
+ for i in ints:
+ x = i * 2
+ print(f"i = {i}, x = {x}")
+
+
+
+
+ for
+ i <- ints
+ do
+ val x = i * 2
+ println(s"i = $i, x = $x")
+
+
+
+
+
+### Multiple “range” generators:
+
+
+
+
+
+ for i in range(1,3):
+ for j in range(4,6):
+ for k in range(1,10,3):
+ print(f"i = {i}, j = {j}, k = {k}")
+
+
+
+
+ for
+ i <- 1 to 2
+ j <- 4 to 5
+ k <- 1 until 10 by 3
+ do
+ println(s"i = $i, j = $j, k = $k")
+
+
+
+
+
+### Generator with guards (`if` expressions):
+
+
+
+
+
+ for i in range(1,11):
+ if i % 2 == 0:
+ if i < 5:
+ print(i)
+
+
+
+
+ for
+ i <- 1 to 10
+ if i % 2 == 0
+ if i < 5
+ do
+ println(i)
+
+
+
+
+
+### Multiple `if` conditions per line:
+
+
+
+
+
+ for i in range(1,11):
+ if i % 2 == 0 and i < 5:
+ print(i)
+
+
+
+
+ for
+ i <- 1 to 10
+ if i % 2 == 0 && i < 5
+ do
+ println(i)
+
+
+
+
+
+### Comprehensions:
+
+
+
+
+
+ xs = [i * 10 for i in range(1, 4)]
+ # xs: [10,20,30]
+
+
+
+
+ val xs = for i <- 1 to 3 yield i * 10
+ // xs: Vector(10, 20, 30)
+
+
+
+
+
+### `match` expressions:
+
+
+
+
+
+ # From 3.10, Python supports structural pattern matching
+ # You can also use dictionaries for basic “switch” functionality
+ match month:
+ case 1:
+ monthAsString = "January"
+ case 2:
+ monthAsString = "February"
+ case _:
+ monthAsString = "Other"
+
+
+
+
+ val monthAsString = month match
+ case 1 => "January"
+ case 2 => "February"
+ _ => "Other"
+
+
+
+
+
+### switch/match:
+
+
+
+
+
+ # Only from Python 3.10
+ match i:
+ case 1 | 3 | 5 | 7 | 9:
+ numAsString = "odd"
+ case 2 | 4 | 6 | 8 | 10:
+ numAsString = "even"
+ case _:
+ numAsString = "too big"
+
+
+
+
+ val numAsString = i match
+ case 1 | 3 | 5 | 7 | 9 => "odd"
+ case 2 | 4 | 6 | 8 | 10 => "even"
+ case _ => "too big"
+
+
+Match expressions and pattern matching are a big part of the Scala programming experience, but only a few `match` expression features are shown here. See the [Control Structures][control-structures] page for many more examples.
+
+## Collections classes
+
+This section compares the [collections classes][collections-classes] that are available in Python and Scala, including lists, dictionaries/maps, sets, and tuples.
+
+### Lists
+
+Where Python has its list, Scala has several different specialized mutable and immutable sequence classes, depending on your needs.
+Because the Python list is mutable, it most directly compares to Scala’s `ArrayBuffer`.
+
+### Python list & Scala sequences:
+
+
+
+
+
+ a = [1,2,3]
+
+
+
+
+ // use different sequence classes
+ // as needed
+ val a = List(1,2,3)
+ val a = Vector(1,2,3)
+ val a = ArrayBuffer(1,2,3)
+
+ for i in ints: print(i)
+
+ for i in ints:
+ print(i)
+
+
+
+
+ // preferred
+ for i <- ints do println(i)
+
+ // also available
+ for (i <- ints) println(i)
+
+
+
+
+
+Scala’s main sequence classes are `List`, `Vector`, and `ArrayBuffer`.
+`List` and `Vector` are the main classes to use when you want an immutable sequence, and `ArrayBuffer` is the main class to use when you want a mutable sequence.
+(A “buffer” in Scala is a sequence that can grow and shrink.)
+
+### Dictionary/Map
+
+The Python dictionary is like the _mutable_ Scala `Map` class.
+However, the default Scala map is _immutable_, and has a number of transformation methods to let you easily create new maps.
+
+#### Dictionary/Map creation:
+
+
+
+
+
+ my_dict = {
+ 'a': 1,
+ 'b': 2,
+ 'c': 3
+ }
+
+
+
+
+ val myMap = Map(
+ "a" -> 1,
+ "b" -> 2,
+ "c" -> 3
+ )
+
+
+
+
+
+#### Accessing dictionary/map elements:
+
+
+
+
+
+ my_dict['a'] # 1
+
+
+
+
+ myMap("a") // 1
+
+
+
+
+
+#### Dictionary/Map with a `for` loop:
+
+
+
+
+
+ for key, value in my_dict.items():
+ print(key)
+ print(value)
+
+
+
+
+ for (key,value) <- myMap do
+ println(key)
+ println(value)
+
+
+
+
+
+Scala has other specialized `Map` classes for different needs.
+
+### Sets
+
+The Python set is similar to the _mutable_ Scala `Set` class.
+
+#### Set creation:
+
+
+
+
+
+ set = {"a", "b", "c"}
+
+
+
+
+ val set = Set(1,2,3)
+
+
+
+
+
+#### Duplicate elements:
+
+
+
+
+
+ set = {1,2,1}
+ # set: {1,2}
+
+
+
+
+ val set = Set(1,2,1)
+ // set: Set(1,2)
+
+
+
+
+
+Scala has other specialized `Set` classes for different needs.
+
+### Tuples
+
+Python and Scala tuples are also similar.
+
+#### Tuple creation:
+
+
+
+
+
+ t = (11, 11.0, "Eleven")
+
+
+
+
+ val t = (11, 11.0, "Eleven")
+
+
+
+
+
+#### Accessing tuple elements:
+
+
+
+
+
+ t[0] # 11
+ t[1] # 11.0
+
+
+
+
+ t(0) // 11
+ t(1) // 11.0
+
+
+
+
+
+## Methods on collections classes
+
+Python and Scala have several of the same common functional methods available to them:
+
+- `map`
+- `filter`
+- `reduce`
+
+If you’re used to using these methods with lambda expressions in Python, you’ll see that Scala has a similar approach with methods on its collections classes.
+To demonstrate this functionality, here are two sample lists:
+
+```scala
+numbers = [1,2,3] // python
+val numbers = List(1,2,3) // scala
+```
+
+Those lists are used in the following table, that shows how to apply mapping and filtering algorithms to it.
+
+### Mapping with a comprehension:
+
+
+
+
+
+ x = [i * 10 for i in numbers]
+
+
+
+
+ val x = for i <- numbers yield i * 10
+
+
+
+
+
+### Filtering with a comprehension:
+
+
+
+
+
+ evens = [i for i in numbers if i % 2 == 0]
+
+
+
+
+ val evens = numbers.filter(_ % 2 == 0)
+ // or
+ val evens = for i <- numbers if i % 2 == 0 yield i
+
+
+
+
+
+### Mapping & filtering with a comprehension:
+
+
+
+
+
+ x = [i * 10 for i in numbers if i % 2 == 0]
+
+
+
+
+ val x = numbers.filter(_ % 2 == 0).map(_ * 10)
+ // or
+ val x = for i <- numbers if i % 2 == 0 yield i * 10
+
+
+
+
+
+### Mapping:
+
+
+
+
+
+ x = map(lambda x: x * 10, numbers)
+
+
+
+
+ val x = numbers.map(_ * 10)
+
+
+
+
+
+### Filtering:
+
+
+
+
+
+ f = lambda x: x > 1
+ x = filter(f, numbers)
+
+
+
+
+ val x = numbers.filter(_ > 1)
+
+
+
+
+
+
+### Scala collections methods
+
+Scala collections classes have over 100 functional methods to simplify your code.
+In Python, some of these functions are available in the `itertools` module.
+In addition to `map`, `filter`, and `reduce`, other commonly-used methods in Scala are listed below.
+In those method examples:
+
+- `c` refers to a collection
+- `p` is a predicate
+- `f` is a function, anonymous function, or method
+- `n` refers to an integer value
+
+These are some of the filtering methods that are available:
+
+| Method | Description |
+| -------------- | ------------- |
+| `c1.diff(c2)` | Returns the difference of the elements in `c1` and `c2`. |
+| `c.distinct` | Returns the unique elements in `c`. |
+| `c.drop(n)` | Returns all elements in the collection except the first `n` elements. |
+| `c.filter(p)` | Returns all elements from the collection for which the predicate is `true`. |
+| `c.head` | Returns the first element of the collection. (Throws a `NoSuchElementException` if the collection is empty.) |
+| `c.tail` | Returns all elements from the collection except the first element. (Throws a `UnsupportedOperationException` if the collection is empty.) |
+| `c.take(n)` | Returns the first `n` elements of the collection `c`. |
+
+Here are a few transformer methods:
+
+| Method | Description |
+| --------------- | ------------- |
+| `c.flatten` | Converts a collection of collections (such as a list of lists) to a single collection (single list). |
+| `c.flatMap(f)` | Returns a new collection by applying `f` to all elements of the collection `c` (like `map`), and then flattening the elements of the resulting collections. |
+| `c.map(f)` | Creates a new collection by applying `f` to all elements of the collection `c`. |
+| `c.reduce(f)` | Applies the “reduction” function `f` to successive elements in `c` to yield a single value. |
+| `c.sortWith(f)` | Returns a version of `c` that’s sorted by the comparison function `f`. |
+
+Some common grouping methods:
+
+| Method | Description |
+| ---------------- | ------------- |
+| `c.groupBy(f)` | Partitions the collection into a `Map` of collections according to `f`. |
+| `c.partition(p)` | Returns two collections according to the predicate `p`. |
+| `c.span(p)` | Returns a collection of two collections, the first created by `c.takeWhile(p)`, and the second created by `c.dropWhile(p)`. |
+| `c.splitAt(n)` | Returns a collection of two collections by splitting the collection `c` at element `n`. |
+
+Some informational and mathematical methods:
+
+| Method | Description |
+| -------------- | ------------- |
+| `c1.containsSlice(c2)` | Returns `true` if `c1` contains the sequence `c2`. |
+| `c.count(p)` | Counts the number of elements in `c` where `p` is `true`. |
+| `c.distinct` | Returns the unique elements in `c`. |
+| `c.exists(p)` | Returns `true` if `p` is `true` for any element in the collection. |
+| `c.find(p)` | Returns the first element that matches `p`. The element is returned as `Option[A]`. |
+| `c.min` | Returns the smallest element from the collection. (Can throw _java.lang.UnsupportedOperationException_.) |
+| `c.max` | Returns the largest element from the collection. (Can throw _java.lang.UnsupportedOperationException_.) |
+|`c slice(from, to)` | Returns the interval of elements beginning at element `from`, and ending at element `to`. |
+| `c.sum` | Returns the sum of all elements in the collection. (Requires an `Ordering` be defined for the elements in the collection.) |
+
+Here are a few examples that demonstrate how these methods work on a list:
+
+```scala
+val a = List(10, 20, 30, 40, 10) // List(10, 20, 30, 40, 10)
+a.distinct // List(10, 20, 30, 40)
+a.drop(2) // List(30, 40, 10)
+a.dropRight(2) // List(10, 20, 30)
+a.dropWhile(_ < 25) // List(30, 40, 10)
+a.filter(_ < 25) // List(10, 20, 10)
+a.filter(_ > 100) // List()
+a.find(_ > 20) // Some(30)
+a.head // 10
+a.headOption // Some(10)
+a.init // List(10, 20, 30, 40)
+a.intersect(List(19,20,21)) // List(20)
+a.last // 10
+a.lastOption // Some(10)
+a.slice(2,4) // List(30, 40)
+a.tail // List(20, 30, 40, 10)
+a.take(3) // List(10, 20, 30)
+a.takeRight(2) // List(40, 10)
+a.takeWhile(_ < 30) // List(10, 20)
+```
+
+These methods show a common pattern in Scala: Functional methods that are available on objects.
+None of these methods mutate the initial list `a`; instead, they all return the data shown after the comments.
+
+There are many more methods available, but hopefully these descriptions and examples give you a taste of the power that’s available in the pre-built collections methods.
+
+## Enums
+
+This section compares enums (enumerations) in Python and Scala 3.
+
+### Creating enums:
+
+
+
+
+
+ from enum import Enum, auto
+ class Color(Enum):
+ RED = auto()
+ GREEN = auto()
+ BLUE = auto()
+
+
+
+
+ enum Color:
+ case Red, Green, Blue
+
+
+
+
+
+### Values and comparison:
+
+
+
+
+
+ Color.RED == Color.BLUE # False
+
+
+
+
+ Color.Red == Color.Blue // false
+
+
+
+
+
+### Parameterized enums:
+
+
+
+
+
+ N/A
+
+
+
+
+ enum Color(val rgb: Int):
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+
+
+
+
+
+### User-defined enum members:
+
+
+
+
+
+ N/A
+
+
+
+
+ enum Planet(
+ mass: Double,
+ radius: Double
+ ):
+ case Mercury extends
+ Planet(3.303e+23, 2.4397e6)
+ case Venus extends
+ Planet(4.869e+24, 6.0518e6)
+ case Earth extends
+ Planet(5.976e+24, 6.37814e6)
+ // more planets ...
+
+ // fields and methods
+ private final val G = 6.67300E-11
+ def surfaceGravity = G * mass /
+ (radius * radius)
+ def surfaceWeight(otherMass: Double)
+ = otherMass * surfaceGravity
+
+
+
+
+
+## Concepts that are unique to Scala
+
+There are other concepts in Scala which currently don’t have equivalent functionality in Python.
+Follow the links below for more details:
+
+- Most concepts related to [contextual abstractions][contextual], such as [extension methods][extension-methods], [type classes][type-classes], implicit values
+- Scala allows multiple parameter lists, which enables features like partially-applied functions, and the ability to create your own DSLs
+- The ability to create your own control structures and DSLs
+- [Multiversal equality][multiversal]: the ability to control at compile time what equality comparisons make sense
+- Infix methods
+- Macros
+
+## Scala and virtual environments
+
+In Scala, there is no need to explicitly set up the equivalent of a Python virtual environment. By default, Scala build tools manage project dependencies such that users do not have to think about manual package installation. For example, using the `sbt` build tool, we specify dependencies inside `build.sbt` file under `libraryDependencies` setting, then executing
+
+```
+cd myapp
+sbt compile
+```
+
+automatically resolves all dependencies for that particular project. The location of downloaded dependencies is largely an implementation detail of the build tool, and users do not have to interact with these downloaded dependencies directly. For example, if we delete the whole sbt dependencies cache, on the next compilation of the project, sbt simply resolves and downloads all the required dependencies again, automatically.
+
+This differs from Python, where by default dependencies are installed in system-wide or user-wide directories, so to obtain an isolated environment on a per-project basis one has to create a corresponding virtual environment. For example, using the `venv` module, we might create one for a particular project like so
+
+```
+cd myapp
+python3 -m venv myapp-env
+source myapp-env/bin/activate
+pip install -r requirements.txt
+```
+
+This installs all the dependencies under the project's `myapp/myapp-env` directory and alters the shell environmental variable `PATH` to look up dependencies from `myapp-env`.
+None of this manual process is necessary in Scala.
+
+
+[collections-classes]: {% link _overviews/scala3-book/collections-classes.md %}
+[concurrency]: {% link _overviews/scala3-book/concurrency.md %}
+[contextual]: {% link _overviews/scala3-book/ca-contextual-abstractions-intro.md %}
+[control-structures]: {% link _overviews/scala3-book/control-structures.md %}
+[extension-methods]: {% link _overviews/scala3-book/ca-extension-methods.md %}
+[fp-intro]: {% link _overviews/scala3-book/fp-intro.md %}
+[hofs]: {% link _overviews/scala3-book/fun-hofs.md %}
+[intersection-types]: {% link _overviews/scala3-book/types-intersection.md %}
+[main-method]: {% link _overviews/scala3-book/methods-main-methods.md %}
+[modeling-intro]: {% link _overviews/scala3-book/domain-modeling-intro.md %}
+[multiversal]: {% link _overviews/scala3-book/ca-multiversal-equality.md %}
+[toplevel]: {% link _overviews/scala3-book/taste-toplevel-definitions.md %}
+[type-classes]: {% link _overviews/scala3-book/ca-type-classes.md %}
+[union-types]: {% link _overviews/scala3-book/types-union.md %}
+
diff --git a/_overviews/scala3-book/scala-tools.md b/_overviews/scala3-book/scala-tools.md
new file mode 100644
index 0000000000..4469a7283d
--- /dev/null
+++ b/_overviews/scala3-book/scala-tools.md
@@ -0,0 +1,14 @@
+---
+title: Scala Tools
+type: chapter
+description: This chapter looks at two commonly-used Scala tools, sbt and ScalaTest.
+languages: [ru, zh-cn]
+num: 70
+previous-page: concurrency
+next-page: tools-sbt
+---
+
+This chapter introduces two ways to write and run Scala programs:
+
+- by creating Scala projects, possibly containing multiple files, and defining a program entry point,
+- by interacting with a worksheet, which is a program defined in a single file, executed line by line.
diff --git a/_overviews/scala3-book/scala4x.css b/_overviews/scala3-book/scala4x.css
new file mode 100644
index 0000000000..1772c03ac8
--- /dev/null
+++ b/_overviews/scala3-book/scala4x.css
@@ -0,0 +1,54 @@
+
+
+
diff --git a/_overviews/scala3-book/string-interpolation.md b/_overviews/scala3-book/string-interpolation.md
new file mode 100644
index 0000000000..1ba335e3b7
--- /dev/null
+++ b/_overviews/scala3-book/string-interpolation.md
@@ -0,0 +1,370 @@
+---
+title: String Interpolation
+type: chapter
+description: This page provides more information about creating strings and using string interpolation.
+languages: [ru, zh-cn]
+num: 18
+previous-page: first-look-at-types
+next-page: control-structures
+redirect_from:
+ - /overviews/core/string-interpolation.html
+---
+
+## Introduction
+
+String interpolation provides a way to use variables inside strings.
+For instance:
+
+{% tabs example-1 %}
+{% tab 'Scala 2 and 3' for=example-1 %}
+```scala
+val name = "James"
+val age = 30
+println(s"$name is $age years old") // "James is 30 years old"
+```
+{% endtab %}
+{% endtabs %}
+
+Using string interpolation consists of putting an `s` in front of your string
+quotes, and prefixing any variable names with a `$` symbol.
+
+## String Interpolators
+
+The `s` that you place before the string is just one possible interpolator that Scala
+provides.
+
+Scala provides three string interpolation methods out of the box: `s`, `f` and `raw`.
+Further, a string interpolator is just a special method, so it is possible to define your
+own. For instance, some database libraries define a `sql` interpolator that returns a
+database query.
+
+### The `s` Interpolator (`s`-Strings)
+
+Prepending `s` to any string literal allows the usage of variables directly in the string. You've already seen an example here:
+
+{% tabs example-2 %}
+{% tab 'Scala 2 and 3' for=example-2 %}
+```scala
+val name = "James"
+val age = 30
+println(s"$name is $age years old") // "James is 30 years old"
+```
+{% endtab %}
+{% endtabs %}
+
+Here, the `$name` and `$age` placeholders in the string are replaced by the results of
+calling `name.toString` and `age.toString`, respectively. The `s`-String will have
+access to all variables that are currently in scope.
+
+While it may seem obvious, it's important to note here that string interpolation will _not_ happen in normal string literals:
+
+{% tabs example-3 %}
+{% tab 'Scala 2 and 3' for=example-3 %}
+```scala
+val name = "James"
+val age = 30
+println("$name is $age years old") // "$name is $age years old"
+```
+{% endtab %}
+{% endtabs %}
+
+String interpolators can also take arbitrary expressions. For example:
+
+{% tabs example-4 %}
+{% tab 'Scala 2 and 3' for=example-4 %}
+```scala
+println(s"2 + 2 = ${2 + 2}") // "2 + 2 = 4"
+val x = -1
+println(s"x.abs = ${x.abs}") // "x.abs = 1"
+```
+{% endtab %}
+{% endtabs %}
+
+Any arbitrary expression can be embedded in `${}`.
+
+For some special characters, it is necessary to escape them when embedded within a string.
+To represent an actual dollar sign you can double it `$$`, like here:
+
+{% tabs example-5 %}
+{% tab 'Scala 2 and 3' for=example-5 %}
+```scala
+println(s"New offers starting at $$14.99") // "New offers starting at $14.99"
+```
+{% endtab %}
+{% endtabs %}
+
+Double quotes also need to be escaped. This can be done by using triple quotes as shown:
+
+{% tabs example-6 %}
+{% tab 'Scala 2 and 3' for=example-6 %}
+```scala
+println(s"""{"name":"James"}""") // `{"name":"James"}`
+```
+{% endtab %}
+{% endtabs %}
+
+Finally, all multi-line string literals can also be interpolated
+
+{% tabs example-7 %}
+{% tab 'Scala 2 and 3' for=example-7 %}
+```scala
+println(s"""name: "$name",
+ |age: $age""".stripMargin)
+```
+
+This will print as follows:
+
+```
+name: "James"
+age: 30
+```
+{% endtab %}
+{% endtabs %}
+
+### The `f` Interpolator (`f`-Strings)
+
+Prepending `f` to any string literal allows the creation of simple formatted strings, similar to `printf` in other languages. When using the `f`
+interpolator, all variable references should be followed by a `printf`-style format string, like `%d`. Let's look at an example:
+
+{% tabs example-8 %}
+{% tab 'Scala 2 and 3' for=example-8 %}
+```scala
+val height = 1.9d
+val name = "James"
+println(f"$name%s is $height%2.2f meters tall") // "James is 1.90 meters tall"
+```
+{% endtab %}
+{% endtabs %}
+
+The `f` interpolator is typesafe. If you try to pass a format string that only works for integers but pass a double, the compiler will issue an
+error. For example:
+
+{% tabs f-interpolator-error class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=f-interpolator-error %}
+```scala
+val height: Double = 1.9d
+
+scala> f"$height%4d"
+:9: error: type mismatch;
+ found : Double
+ required: Int
+ f"$height%4d"
+ ^
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=f-interpolator-error %}
+```scala
+val height: Double = 1.9d
+
+scala> f"$height%4d"
+-- Error: ----------------------------------------------------------------------
+1 |f"$height%4d"
+ | ^^^^^^
+ | Found: (height : Double), Required: Int, Long, Byte, Short, BigInt
+1 error found
+
+```
+{% endtab %}
+{% endtabs %}
+
+The `f` interpolator makes use of the string format utilities available from Java. The formats allowed after the `%` character are outlined in the
+[Formatter javadoc][java-format-docs]. If there is no `%` character after a variable
+definition a formatter of `%s` (`String`) is assumed.
+
+Finally, as in Java, use `%%` to get a literal `%` character in the output string:
+
+{% tabs literal-percent %}
+{% tab 'Scala 2 and 3' for=literal-percent %}
+```scala
+println(f"3/19 is less than 20%%") // "3/19 is less than 20%"
+```
+{% endtab %}
+{% endtabs %}
+
+### The `raw` Interpolator
+
+The raw interpolator is similar to the `s` interpolator except that it performs no escaping of literals within the string. Here's an example processed string:
+
+{% tabs example-9 %}
+{% tab 'Scala 2 and 3' for=example-9 %}
+```scala
+scala> s"a\nb"
+res0: String =
+a
+b
+```
+{% endtab %}
+{% endtabs %}
+
+Here the `s` string interpolator replaced the characters `\n` with a return character. The `raw` interpolator will not do that.
+
+{% tabs example-10 %}
+{% tab 'Scala 2 and 3' for=example-10 %}
+```scala
+scala> raw"a\nb"
+res1: String = a\nb
+```
+{% endtab %}
+{% endtabs %}
+
+The raw interpolator is useful when you want to avoid having expressions like `\n` turn into a return character.
+
+Furthermore, the raw interpolator allows the usage of variables, which are replaced with their value, just as the s interpolator.
+
+{% tabs example-11 %}
+{% tab 'Scala 2 and 3' for=example-11 %}
+```scala
+scala> val foo = 42
+scala> raw"a\n$foo"
+res1: String = a\n42
+```
+{% endtab %}
+{% endtabs %}
+
+## Advanced Usage
+
+In addition to the three default string interpolators, users can define their own.
+
+The literal `s"Hi $name"` is parsed by Scala as a _processed_ string literal.
+This means that the compiler does some additional work to this literal. The specifics
+of processed strings and string interpolation are described in [SIP-11][sip-11], but
+here's a quick example to help illustrate how they work.
+
+### Custom Interpolators
+
+In Scala, all processed string literals are simple code transformations. Anytime the compiler encounters a processed string literal of the form:
+
+{% tabs example-12 %}
+{% tab 'Scala 2 and 3' for=example-12 %}
+```scala
+id"string content"
+```
+{% endtab %}
+{% endtabs %}
+
+it transforms it into a method call (`id`) on an instance of [StringContext](https://www.scala-lang.org/api/current/scala/StringContext.html).
+This method can also be available on implicit scope.
+To define our own string interpolation, we need to create an implicit class (Scala 2) or an `extension` method (Scala 3) that adds a new method to `StringContext`.
+
+As a trivial example, let's assume we have a simple `Point` class and want to create a custom interpolator that turns `p"a,b"` into a `Point` object.
+
+{% tabs custom-interpolator-1 %}
+{% tab 'Scala 2 and 3' for=custom-interpolator-1 %}
+```scala
+case class Point(x: Double, y: Double)
+
+val pt = p"1,-2" // Point(1.0,-2.0)
+```
+{% endtab %}
+{% endtabs %}
+
+We'd create a custom `p`-interpolator by first implementing a `StringContext` extension
+with something like:
+
+{% tabs custom-interpolator-2 class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=custom-interpolator-2 %}
+```scala
+implicit class PointHelper(val sc: StringContext) extends AnyVal {
+ def p(args: Any*): Point = ???
+}
+```
+
+**Note:** It's important to extend `AnyVal` in Scala 2.x to prevent runtime instantiation on each interpolation. See the [value class]({% link _overviews/core/value-classes.md %}) documentation for more.
+
+{% endtab %}
+
+{% tab 'Scala 3' for=custom-interpolator-2 %}
+```scala
+extension (sc: StringContext)
+ def p(args: Any*): Point = ???
+```
+{% endtab %}
+
+{% endtabs %}
+
+Once this extension is in scope and the Scala compiler encounters `p"some string"`, it
+will process `some string` to turn it into String tokens and expression arguments for
+each embedded variable in the string.
+
+For example, `p"1, $someVar"` would turn into:
+
+{% tabs extension-desugaring class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=extension-desugaring %}
+```scala
+new StringContext("1, ", "").p(someVar)
+```
+
+The implicit class is then used to rewrite it to the following:
+
+```scala
+new PointHelper(new StringContext("1, ", "")).p(someVar)
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=extension-desugaring %}
+```scala
+StringContext("1, ","").p(someVar)
+```
+{% endtab %}
+
+{% endtabs %}
+
+As a result, each of the fragments of the processed String are exposed in the
+`StringContext.parts` member, while any expressions values in the string are passed in
+to the method's `args` parameter.
+
+### Example Implementation
+
+A naive implementation of our Point interpolator method might look something like below,
+though a more sophisticated method may choose to have more precise control over the
+processing of the string `parts` and expression `args` instead of reusing the
+`s`-Interpolator.
+
+{% tabs naive-implementation class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=naive-implementation %}
+```scala
+implicit class PointHelper(val sc: StringContext) extends AnyVal {
+ def p(args: Double*): Point = {
+ // reuse the `s`-interpolator and then split on ','
+ val pts = sc.s(args: _*).split(",", 2).map { _.toDoubleOption.getOrElse(0.0) }
+ Point(pts(0), pts(1))
+ }
+}
+
+val x=12.0
+
+p"1, -2" // Point(1.0, -2.0)
+p"${x/5}, $x" // Point(2.4, 12.0)
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=naive-implementation %}
+```scala
+extension (sc: StringContext)
+ def p(args: Double*): Point = {
+ // reuse the `s`-interpolator and then split on ','
+ val pts = sc.s(args: _*).split(",", 2).map { _.toDoubleOption.getOrElse(0.0) }
+ Point(pts(0), pts(1))
+ }
+
+val x=12.0
+
+p"1, -2" // Point(1.0, -2.0)
+p"${x/5}, $x" // Point(2.4, 12.0)
+```
+{% endtab %}
+{% endtabs %}
+
+While string interpolators were originally used to create some form of a String, the use
+of custom interpolators as above can allow for powerful syntactic shorthand, and the
+community has already made swift use of this syntax for things like ANSI terminal color
+expansion, executing SQL queries, magic `$"identifier"` representations, and many others.
+
+[java-format-docs]: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Formatter.html#detail
+[value-class]: {% link _overviews/core/value-classes.md %}
+[sip-11]: {% link _sips/sips/string-interpolation.md %}
diff --git a/_overviews/scala3-book/taste-collections.md b/_overviews/scala3-book/taste-collections.md
new file mode 100644
index 0000000000..773f823ce4
--- /dev/null
+++ b/_overviews/scala3-book/taste-collections.md
@@ -0,0 +1,151 @@
+---
+title: Collections
+type: section
+description: This page provides a high-level overview of the main features of the Scala 3 programming language.
+languages: [ru, zh-cn]
+num: 13
+previous-page: taste-objects
+next-page: taste-contextual-abstractions
+---
+
+
+The Scala library has a rich set of collection classes, and those classes have a rich set of methods.
+Collections classes are available in both immutable and mutable forms.
+
+## Creating lists
+
+To give you a taste of how these work, here are some examples that use the `List` class, which is an immutable, linked-list class.
+These examples show different ways to create a populated `List`:
+
+{% tabs collection_1 %}
+{% tab 'Scala 2 and 3' for=collection_1 %}
+
+```scala
+val a = List(1, 2, 3) // a: List[Int] = List(1, 2, 3)
+
+// Range methods
+val b = (1 to 5).toList // b: List[Int] = List(1, 2, 3, 4, 5)
+val c = (1 to 10 by 2).toList // c: List[Int] = List(1, 3, 5, 7, 9)
+val e = (1 until 5).toList // e: List[Int] = List(1, 2, 3, 4)
+val f = List.range(1, 5) // f: List[Int] = List(1, 2, 3, 4)
+val g = List.range(1, 10, 3) // g: List[Int] = List(1, 4, 7)
+```
+
+{% endtab %}
+{% endtabs %}
+
+## `List` methods
+
+Once you have a populated list, the following examples show some of the methods you can call on it.
+Notice that these are all functional methods, meaning that they don’t mutate the collection they’re called on, but instead return a new collection with the updated elements.
+The result that’s returned by each expression is shown in the comment on each line:
+
+{% tabs collection_2 %}
+{% tab 'Scala 2 and 3' for=collection_2 %}
+
+```scala
+// a sample list
+val a = List(10, 20, 30, 40, 10) // List(10, 20, 30, 40, 10)
+
+a.drop(2) // List(30, 40, 10)
+a.dropWhile(_ < 25) // List(30, 40, 10)
+a.filter(_ < 25) // List(10, 20, 10)
+a.slice(2,4) // List(30, 40)
+a.tail // List(20, 30, 40, 10)
+a.take(3) // List(10, 20, 30)
+a.takeWhile(_ < 30) // List(10, 20)
+
+// flatten
+val a = List(List(1,2), List(3,4))
+a.flatten // List(1, 2, 3, 4)
+
+// map, flatMap
+val nums = List("one", "two")
+nums.map(_.toUpperCase) // List("ONE", "TWO")
+nums.flatMap(_.toUpperCase) // List('O', 'N', 'E', 'T', 'W', 'O')
+```
+
+{% endtab %}
+{% endtabs %}
+
+These examples show how the “foldLeft” and “reduceLeft” methods are used to sum the values in a sequence of integers:
+
+{% tabs collection_3 %}
+{% tab 'Scala 2 and 3' for=collection_3 %}
+
+```scala
+val firstTen = (1 to 10).toList // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+
+firstTen.reduceLeft(_ + _) // 55
+firstTen.foldLeft(100)(_ + _) // 155 (100 is a “seed” value)
+```
+
+{% endtab %}
+{% endtabs %}
+
+There are many more methods available to Scala collections classes, and they’re demonstrated in the [Collections chapter][collections], and in the [API Documentation][api].
+
+## Tuples
+
+The Scala _tuple_ is a type that lets you easily put a collection of different types in the same container.
+For example, given this `Person` case class:
+
+{% tabs collection_4 %}
+{% tab 'Scala 2 and 3' for=collection_4 %}
+
+```scala
+case class Person(name: String)
+```
+
+{% endtab %}
+{% endtabs %}
+
+This is how you create a tuple that contains an `Int`, a `String`, and a custom `Person` value:
+
+{% tabs collection_5 %}
+{% tab 'Scala 2 and 3' for=collection_5 %}
+
+```scala
+val t = (11, "eleven", Person("Eleven"))
+```
+
+{% endtab %}
+{% endtabs %}
+
+Once you have a tuple, you can access its values by binding them to variables, or access them by number:
+
+{% tabs collection_6 %}
+{% tab 'Scala 2 and 3' for=collection_6 %}
+
+```scala
+t(0) // 11
+t(1) // "eleven"
+t(2) // Person("Eleven")
+```
+
+{% endtab %}
+{% endtabs %}
+
+You can also use this _extractor_ approach to assign the tuple fields to variable names:
+
+{% tabs collection_7 %}
+{% tab 'Scala 2 and 3' for=collection_7 %}
+
+```scala
+val (num, str, person) = t
+
+// result:
+// val num: Int = 11
+// val str: String = eleven
+// val person: Person = Person(Eleven)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Tuples are nice for those times when you want to put a collection of heterogeneous types in a little collection-like structure.
+See the [Reference documentation][reference] for more tuple details.
+
+[collections]: {% link _overviews/scala3-book/collections-intro.md %}
+[api]: https://scala-lang.org/api/3.x/
+[reference]: {{ site.scala3ref }}/overview.html
diff --git a/_overviews/scala3-book/taste-contextual-abstractions.md b/_overviews/scala3-book/taste-contextual-abstractions.md
new file mode 100644
index 0000000000..60d21d1643
--- /dev/null
+++ b/_overviews/scala3-book/taste-contextual-abstractions.md
@@ -0,0 +1,76 @@
+---
+title: Contextual Abstractions
+type: section
+description: This section provides an introduction to Contextual Abstractions in Scala 3.
+languages: [ru, zh-cn]
+num: 14
+previous-page: taste-collections
+next-page: taste-toplevel-definitions
+---
+
+
+{% comment %}
+TODO: Now that this is a separate section, it needs a little more content.
+{% endcomment %}
+
+Under certain circumstances, you can omit some parameters of method calls that are considered repetitive.
+
+Those parameters are called _Context Parameters_ because they are inferred by the compiler from the context surrounding the method call.
+
+For instance, consider a program that sorts a list of addresses by two criteria: the city name and then street name.
+
+{% tabs contextual_1 %}
+{% tab 'Scala 2 and 3' for=contextual_1 %}
+
+```scala
+val addresses: List[Address] = ...
+
+addresses.sortBy(address => (address.city, address.street))
+```
+
+{% endtab %}
+{% endtabs %}
+
+The `sortBy` method takes a function that returns, for every address, the value to compare it with the other addresses.
+In this case, we pass a function that returns a pair containing the city name and the street name.
+
+Note that we only indicate _what_ to compare, but not _how_ to perform the comparison.
+How does the sorting algorithm know how to compare pairs of `String`?
+
+Actually, the `sortBy` method takes a second parameter---a context parameter---that is inferred by the compiler.
+It does not appear in the above example because it is supplied by the compiler.
+
+This second parameter implements the _how_ to compare.
+It is convenient to omit it because we know `String`s are generally compared using the lexicographic order.
+
+However, it is also possible to pass it explicitly:
+
+{% tabs contextual_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=contextual_2 %}
+
+```scala
+addresses.sortBy(address => (address.city, address.street))(Ordering.Tuple2(Ordering.String, Ordering.String))
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=contextual_2 %}
+
+```scala
+addresses.sortBy(address => (address.city, address.street))(using Ordering.Tuple2(Ordering.String, Ordering.String))
+```
+
+in Scala 3 `using` in an argument list to `sortBy` signals passing the context parameter explicitly, avoiding ambiguity.
+
+{% endtab %}
+{% endtabs %}
+
+In this case, the `Ordering.Tuple2(Ordering.String, Ordering.String)` instance is exactly the one that is otherwise inferred by the compiler.
+In other words both examples produce the same program.
+
+_Contextual Abstractions_ are used to avoid repetition of code.
+They help developers write pieces of code that are extensible and concise at the same time.
+
+For more details, see the [Contextual Abstractions chapter][contextual] of this book, and also the [Reference documentation][reference].
+
+[contextual]: {% link _overviews/scala3-book/ca-contextual-abstractions-intro.md %}
+[reference]: {{ site.scala3ref }}/overview.html
diff --git a/_overviews/scala3-book/taste-control-structures.md b/_overviews/scala3-book/taste-control-structures.md
new file mode 100644
index 0000000000..4b58abbf00
--- /dev/null
+++ b/_overviews/scala3-book/taste-control-structures.md
@@ -0,0 +1,541 @@
+---
+title: Control Structures
+type: section
+description: This section demonstrates Scala 3 control structures.
+languages: [ru, zh-cn]
+num: 8
+previous-page: taste-vars-data-types
+next-page: taste-modeling
+---
+
+
+Scala has the control structures you find in other programming languages, and also has powerful `for` expressions and `match` expressions:
+
+- `if`/`else`
+- `for` loops and expressions
+- `match` expressions
+- `while` loops
+- `try`/`catch`
+
+These structures are demonstrated in the following examples.
+
+## `if`/`else`
+
+Scala’s `if`/`else` control structure looks similar to other languages.
+
+{% tabs if-else class=tabs-scala-version %}
+{% tab 'Scala 2' for=if-else %}
+
+```scala
+if (x < 0) {
+ println("negative")
+} else if (x == 0) {
+ println("zero")
+} else {
+ println("positive")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=if-else %}
+
+```scala
+if x < 0 then
+ println("negative")
+else if x == 0 then
+ println("zero")
+else
+ println("positive")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Note that this really is an _expression_---not a _statement_.
+This means that it returns a value, so you can assign the result to a variable:
+
+{% tabs if-else-expression class=tabs-scala-version %}
+{% tab 'Scala 2' for=if-else-expression %}
+
+```scala
+val x = if (a < b) { a } else { b }
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=if-else-expression %}
+
+```scala
+val x = if a < b then a else b
+```
+
+{% endtab %}
+{% endtabs %}
+
+As you’ll see throughout this book, _all_ Scala control structures can be used as expressions.
+
+> An expression returns a result, while a statement does not.
+> Statements are typically used for their side-effects, such as using `println` to print to the console.
+
+## `for` loops and expressions
+
+The `for` keyword is used to create a `for` loop.
+This example shows how to print every element in a `List`:
+
+{% tabs for-loop class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-loop %}
+
+```scala
+val ints = List(1, 2, 3, 4, 5)
+
+for (i <- ints) println(i)
+```
+
+> The code `i <- ints` is referred to as a _generator_. In any generator `p <- e`, the expression `e` can generate zero or many bindings to the pattern `p`.
+> The code that follows the closing parentheses of the generator is the _body_ of the loop.
+
+{% endtab %}
+
+{% tab 'Scala 3' for=for-loop %}
+
+```scala
+val ints = List(1, 2, 3, 4, 5)
+
+for i <- ints do println(i)
+```
+
+> The code `i <- ints` is referred to as a _generator_, and the code that follows the `do` keyword is the _body_ of the loop.
+
+{% endtab %}
+{% endtabs %}
+
+### Guards
+
+You can also use one or more `if` expressions inside a `for` loop.
+These are referred to as _guards_.
+This example prints all of the numbers in `ints` that are greater than `2`:
+
+{% tabs for-guards class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-guards %}
+
+```scala
+for (i <- ints if i > 2)
+ println(i)
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=for-guards %}
+
+```scala
+for
+ i <- ints
+ if i > 2
+do
+ println(i)
+```
+
+{% endtab %}
+{% endtabs %}
+
+You can use multiple generators and guards.
+This loop iterates over the numbers `1` to `3`, and for each number it also iterates over the characters `a` to `c`.
+However, it also has two guards, so the only time the print statement is called is when `i` has the value `2` and `j` is the character `b`:
+
+{% tabs for-guards-multi class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-guards-multi %}
+
+```scala
+for {
+ i <- 1 to 3
+ j <- 'a' to 'c'
+ if i == 2
+ if j == 'b'
+} {
+ println(s"i = $i, j = $j") // prints: "i = 2, j = b"
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=for-guards-multi %}
+
+```scala
+for
+ i <- 1 to 3
+ j <- 'a' to 'c'
+ if i == 2
+ if j == 'b'
+do
+ println(s"i = $i, j = $j") // prints: "i = 2, j = b"
+```
+
+{% endtab %}
+{% endtabs %}
+
+### `for` expressions
+
+The `for` keyword has even more power: When you use the `yield` keyword instead of `do`, you create `for` _expressions_ which are used to calculate and yield results.
+
+A few examples demonstrate this.
+Using the same `ints` list as the previous example, this code creates a new list, where the value of each element in the new list is twice the value of the elements in the original list:
+
+{% tabs for-expression_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-expression_1 %}
+
+````
+scala> val doubles = for (i <- ints) yield i * 2
+val doubles: List[Int] = List(2, 4, 6, 8, 10)
+````
+
+{% endtab %}
+
+{% tab 'Scala 3' for=for-expression_1 %}
+
+````
+scala> val doubles = for i <- ints yield i * 2
+val doubles: List[Int] = List(2, 4, 6, 8, 10)
+````
+
+{% endtab %}
+{% endtabs %}
+
+Scala’s control structure syntax is flexible, and that `for` expression can be written in several other ways, depending on your preference:
+
+{% tabs for-expressioni_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-expressioni_2 %}
+
+```scala
+val doubles = for (i <- ints) yield i * 2
+val doubles = for (i <- ints) yield (i * 2)
+val doubles = for { i <- ints } yield (i * 2)
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=for-expressioni_2 %}
+
+```scala
+val doubles = for i <- ints yield i * 2 // style shown above
+val doubles = for (i <- ints) yield i * 2
+val doubles = for (i <- ints) yield (i * 2)
+val doubles = for { i <- ints } yield (i * 2)
+```
+
+{% endtab %}
+{% endtabs %}
+
+This example shows how to capitalize the first character in each string in the list:
+
+{% tabs for-expressioni_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-expressioni_3 %}
+
+```scala
+val names = List("chris", "ed", "maurice")
+val capNames = for (name <- names) yield name.capitalize
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=for-expressioni_3 %}
+
+```scala
+val names = List("chris", "ed", "maurice")
+val capNames = for name <- names yield name.capitalize
+```
+
+{% endtab %}
+{% endtabs %}
+
+Finally, this `for` expression iterates over a list of strings, and returns the length of each string, but only if that length is greater than `4`:
+
+{% tabs for-expressioni_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-expressioni_4 %}
+
+```scala
+val fruits = List("apple", "banana", "lime", "orange")
+
+val fruitLengths =
+ for (f <- fruits if f.length > 4) yield f.length
+
+// fruitLengths: List[Int] = List(5, 6, 6)
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=for-expressioni_4 %}
+
+```scala
+val fruits = List("apple", "banana", "lime", "orange")
+
+val fruitLengths = for
+ f <- fruits
+ if f.length > 4
+yield
+ // you can use multiple lines
+ // of code here
+ f.length
+
+// fruitLengths: List[Int] = List(5, 6, 6)
+```
+
+{% endtab %}
+{% endtabs %}
+
+`for` loops and expressions are covered in more detail in the [Control Structures sections][control] of this book, and in the [Reference documentation]({{ site.scala3ref }}/other-new-features/control-syntax.html).
+
+## `match` expressions
+
+Scala has a `match` expression, which in its most basic use is like a Java `switch` statement:
+
+{% tabs match class=tabs-scala-version %}
+{% tab 'Scala 2' for=match %}
+
+```scala
+val i = 1
+
+// later in the code ...
+i match {
+ case 1 => println("one")
+ case 2 => println("two")
+ case _ => println("other")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=match %}
+
+```scala
+val i = 1
+
+// later in the code ...
+i match
+ case 1 => println("one")
+ case 2 => println("two")
+ case _ => println("other")
+```
+
+{% endtab %}
+{% endtabs %}
+
+However, `match` really is an expression, meaning that it returns a result based on the pattern match, which you can bind to a variable:
+
+{% tabs match-expression_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=match-expression_1 %}
+
+```scala
+val result = i match {
+ case 1 => "one"
+ case 2 => "two"
+ case _ => "other"
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=match-expression_1 %}
+
+```scala
+val result = i match
+ case 1 => "one"
+ case 2 => "two"
+ case _ => "other"
+```
+
+{% endtab %}
+{% endtabs %}
+
+`match` isn’t limited to working with just integer values, it can be used with any data type:
+
+{% tabs match-expression_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=match-expression_2 %}
+
+```scala
+val p = Person("Fred")
+
+// later in the code
+p match {
+ case Person(name) if name == "Fred" =>
+ println(s"$name says, Yubba dubba doo")
+
+ case Person(name) if name == "Bam Bam" =>
+ println(s"$name says, Bam bam!")
+
+ case _ => println("Watch the Flintstones!")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=match-expression_2 %}
+
+```scala
+val p = Person("Fred")
+
+// later in the code
+p match
+ case Person(name) if name == "Fred" =>
+ println(s"$name says, Yubba dubba doo")
+
+ case Person(name) if name == "Bam Bam" =>
+ println(s"$name says, Bam bam!")
+
+ case _ => println("Watch the Flintstones!")
+```
+
+{% endtab %}
+{% endtabs %}
+
+In fact, a `match` expression can be used to test a variable against many different types of patterns.
+This example shows (a) how to use a `match` expression as the body of a method, and (b) how to match all the different types shown:
+
+{% tabs match-expression_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=match-expression_3 %}
+
+```scala
+// getClassAsString is a method that takes a single argument of any type.
+def getClassAsString(x: Any): String = x match {
+ case s: String => s"'$s' is a String"
+ case i: Int => "Int"
+ case d: Double => "Double"
+ case l: List[_] => "List"
+ case _ => "Unknown"
+}
+
+// examples
+getClassAsString(1) // Int
+getClassAsString("hello") // 'hello' is a String
+getClassAsString(List(1, 2, 3)) // List
+```
+
+Because the method `getClassAsString` takes a parameter value of type `Any`, it can be decomposed by any kind of
+pattern.
+
+{% endtab %}
+{% tab 'Scala 3' for=match-expression_3 %}
+
+```scala
+// getClassAsString is a method that takes a single argument of any type.
+def getClassAsString(x: Matchable): String = x match
+ case s: String => s"'$s' is a String"
+ case i: Int => "Int"
+ case d: Double => "Double"
+ case l: List[?] => "List"
+ case _ => "Unknown"
+
+// examples
+getClassAsString(1) // Int
+getClassAsString("hello") // 'hello' is a String
+getClassAsString(List(1, 2, 3)) // List
+```
+
+The method `getClassAsString` takes as a parameter a value of type [Matchable]({{ site.scala3ref }}/other-new-features/matchable.html), which can be
+any type supporting pattern matching (some types don’t support pattern matching because this could
+break encapsulation).
+
+{% endtab %}
+{% endtabs %}
+
+There’s _much_ more to pattern matching in Scala.
+Patterns can be nested, results of patterns can be bound, and pattern matching can even be user-defined.
+See the pattern matching examples in the [Control Structures chapter][control] for more details.
+
+## `try`/`catch`/`finally`
+
+Scala’s `try`/`catch`/`finally` control structure lets you catch exceptions.
+It’s similar to Java, but its syntax is consistent with `match` expressions:
+
+{% tabs try class=tabs-scala-version %}
+{% tab 'Scala 2' for=try %}
+
+```scala
+try {
+ writeTextToFile(text)
+} catch {
+ case ioe: IOException => println("Got an IOException.")
+ case nfe: NumberFormatException => println("Got a NumberFormatException.")
+} finally {
+ println("Clean up your resources here.")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=try %}
+
+```scala
+try
+ writeTextToFile(text)
+catch
+ case ioe: IOException => println("Got an IOException.")
+ case nfe: NumberFormatException => println("Got a NumberFormatException.")
+finally
+ println("Clean up your resources here.")
+```
+
+{% endtab %}
+{% endtabs %}
+
+## `while` loops
+
+Scala also has a `while` loop construct.
+Its one-line syntax looks like this:
+
+{% tabs while_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=while_1 %}
+
+```scala
+while (x >= 0) { x = f(x) }
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=while_1 %}
+
+```scala
+while x >= 0 do x = f(x)
+```
+Scala 3 still supports the Scala 2 syntax for the sake of compatibility.
+
+{% endtab %}
+{% endtabs %}
+
+The `while` loop multiline syntax looks like this:
+
+{% tabs while_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=while_2 %}
+
+```scala
+var x = 1
+
+while (x < 3) {
+ println(x)
+ x += 1
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=while_2 %}
+
+```scala
+var x = 1
+
+while
+ x < 3
+do
+ println(x)
+ x += 1
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Custom control structures
+
+Thanks to features like by-name parameters, infix notation, fluent interfaces, optional parentheses, extension methods, and higher-order functions, you can also create your own code that works just like a control structure.
+You’ll learn more about this in the [Control Structures][control] section.
+
+[control]: {% link _overviews/scala3-book/control-structures.md %}
diff --git a/_overviews/scala3-book/taste-functions.md b/_overviews/scala3-book/taste-functions.md
new file mode 100644
index 0000000000..e73024bca0
--- /dev/null
+++ b/_overviews/scala3-book/taste-functions.md
@@ -0,0 +1,78 @@
+---
+title: First-Class Functions
+type: section
+description: This page provides an introduction to functions in Scala 3.
+languages: [ru, zh-cn]
+num: 11
+previous-page: taste-methods
+next-page: taste-objects
+---
+
+
+Scala has most features you’d expect in a functional programming language, including:
+
+- Lambdas (anonymous functions)
+- Higher-order functions (HOFs)
+- Immutable collections in the standard library
+
+Lambdas, also known as _anonymous functions_, are a big part of keeping your code concise but readable.
+
+The `map` method of the `List` class is a typical example of a higher-order function---a function that takes a function as parameter.
+
+These two examples are equivalent, and show how to multiply each number in a list by `2` by passing a lambda into the `map` method:
+
+
+{% tabs function_1 %}
+{% tab 'Scala 2 and 3' for=function_1 %}
+```scala
+val a = List(1, 2, 3).map(i => i * 2) // List(2,4,6)
+val b = List(1, 2, 3).map(_ * 2) // List(2,4,6)
+```
+{% endtab %}
+{% endtabs %}
+
+Those examples are also equivalent to the following code, which uses a `double` method instead of a lambda:
+
+
+{% tabs function_2 %}
+{% tab 'Scala 2 and 3' for=function_2 %}
+```scala
+def double(i: Int): Int = i * 2
+
+val a = List(1, 2, 3).map(i => double(i)) // List(2,4,6)
+val b = List(1, 2, 3).map(double) // List(2,4,6)
+```
+{% endtab %}
+{% endtabs %}
+
+> If you haven’t seen the `map` method before, it applies a given function to every element in a list, yielding a new list that contains the resulting values.
+
+Passing lambdas to higher-order functions on collections classes (like `List`) is a part of the Scala experience, something you’ll do every day.
+
+## Immutable collections
+
+When you work with immutable collections like `List`, `Vector`, and the immutable `Map` and `Set` classes, it’s important to know that these functions don’t mutate the collection they’re called on; instead, they return a new collection with the updated data.
+As a result, it’s also common to chain them together in a “fluent” style to solve problems.
+
+For instance, this example shows how to filter a collection twice, and then multiply each element in the remaining collection:
+
+
+{% tabs function_3 %}
+{% tab 'Scala 2 and 3' for=function_3 %}
+```scala
+// a sample list
+val nums = (1 to 10).toList // List(1,2,3,4,5,6,7,8,9,10)
+
+// methods can be chained together as needed
+val x = nums.filter(_ > 3)
+ .filter(_ < 7)
+ .map(_ * 10)
+
+// result: x == List(40, 50, 60)
+```
+{% endtab %}
+{% endtabs %}
+
+In addition to higher-order functions being used throughout the standard library, you can also [create your own][higher-order].
+
+[higher-order]: {% link _overviews/scala3-book/fun-hofs.md %}
diff --git a/_overviews/scala3-book/taste-hello-world.md b/_overviews/scala3-book/taste-hello-world.md
new file mode 100644
index 0000000000..52fc532e5e
--- /dev/null
+++ b/_overviews/scala3-book/taste-hello-world.md
@@ -0,0 +1,165 @@
+---
+title: Hello, World!
+type: section
+description: This section demonstrates a Scala 3 'Hello, World!' example.
+languages: [ru, zh-cn]
+num: 5
+previous-page: taste-intro
+next-page: taste-repl
+---
+
+> **Hint**: in the following examples try picking your preferred Scala version.
+
+## Your First Scala Program
+
+
+A Scala “Hello, World!” example goes as follows.
+First, put this code in a file named _hello.scala_:
+
+
+
+{% tabs hello-world-demo class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=hello-world-demo %}
+```scala
+object hello {
+ def main(args: Array[String]) = {
+ println("Hello, World!")
+ }
+}
+```
+> In this code, we defined a method named `main`, inside a Scala `object` named `hello`.
+> An `object` in Scala is similar to a `class`, but defines a singleton instance that you can pass around.
+> `main` takes an input parameter named `args` that must be typed as `Array[String]`, (ignore `args` for now).
+
+{% endtab %}
+
+{% tab 'Scala 3' for=hello-world-demo %}
+```scala
+@main def hello() = println("Hello, World!")
+```
+> In this code, `hello` is a method.
+> It’s defined with `def`, and declared to be a “main” method with the `@main` annotation.
+> It prints the `"Hello, World!"` string to standard output (STDOUT) using the `println` method.
+
+{% endtab %}
+
+{% endtabs %}
+
+
+Next, compile and run the code with `scala`:
+
+```bash
+$ scala run hello.scala
+```
+
+The command should produce an output similar to:
+```
+Compiling project (Scala {{site.scala-3-version}}, JVM (20))
+Compiled project (Scala {{site.scala-3-version}}, JVM (20))
+Hello, World!
+```
+
+Assuming that worked, congratulations, you just compiled and ran your first Scala application.
+
+> More information about sbt and other tools that make Scala development easier can be found in the [Scala Tools][scala_tools] chapter.
+> The Scala CLI documentation can be found [here](https://scala-cli.virtuslab.org/).
+
+## Ask For User Input
+
+In our next example let's ask for the user's name before we greet them!
+
+There are several ways to read input from a command-line, but a simple way is to use the
+`readLine` method in the _scala.io.StdIn_ object. To use it, you need to first import it, like this:
+
+{% tabs import-readline %}
+{% tab 'Scala 2 and 3' for=import-readline %}
+```scala
+import scala.io.StdIn.readLine
+```
+{% endtab %}
+{% endtabs %}
+
+To demonstrate how this works, let’s create a little example. Put this source code in a file named _helloInteractive.scala_:
+
+
+{% tabs hello-world-interactive class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=hello-world-interactive %}
+```scala
+import scala.io.StdIn.readLine
+
+object helloInteractive {
+
+ def main(args: Array[String]) = {
+ println("Please enter your name:")
+ val name = readLine()
+
+ println("Hello, " + name + "!")
+ }
+
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=hello-world-interactive %}
+```scala
+import scala.io.StdIn.readLine
+
+@main def helloInteractive() =
+ println("Please enter your name:")
+ val name = readLine()
+
+ println("Hello, " + name + "!")
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+In this code we save the result of `readLine` to a variable called `name`, we then
+use the `+` operator on strings to join `"Hello, "` with `name` and `"!"`, making one single string value.
+
+> You can learn more about using `val` by reading [Variables and Data Types](/scala3/book/taste-vars-data-types.html).
+
+Then run the code with `scala`. This time the program will pause after asking for your name,
+and wait until you type a name and press return on the keyboard, looking like this:
+
+```bash
+$ scala run helloInteractive.scala
+Compiling project (Scala {{site.scala-3-version}}, JVM (20))
+Compiled project (Scala {{site.scala-3-version}}, JVM (20))
+Please enter your name:
+▌
+```
+
+When you enter your name at the prompt, the final interaction should look like this:
+
+```bash
+$ scala run helloInteractive.scala
+Compiling project (Scala {{site.scala-3-version}}, JVM (20))
+Compiled project (Scala {{site.scala-3-version}}, JVM (20))
+Please enter your name:
+Alvin Alexander
+Hello, Alvin Alexander!
+```
+
+### A Note about Imports
+
+As you saw in this application, sometimes certain methods, or other kinds of definitions that we'll see later,
+are not available unless you use an `import` clause like so:
+
+{% tabs import-readline-2 %}
+{% tab 'Scala 2 and 3' for=import-readline-2 %}
+```scala
+import scala.io.StdIn.readLine
+```
+{% endtab %}
+{% endtabs %}
+
+Imports help you write code in a few ways:
+ - you can put code in multiple files, to help avoid clutter, and to help navigate large projects.
+ - you can use a code library, perhaps written by someone else, that has useful functionality
+ - you can know where a certain definition comes from (especially if it was not written in the current file).
+
+[scala_tools]: {% link _overviews/scala3-book/scala-tools.md %}
diff --git a/_overviews/scala3-book/taste-intro.md b/_overviews/scala3-book/taste-intro.md
new file mode 100644
index 0000000000..9d93b317cf
--- /dev/null
+++ b/_overviews/scala3-book/taste-intro.md
@@ -0,0 +1,62 @@
+---
+title: A Taste of Scala
+type: chapter
+description: This chapter provides a high-level overview of the main features of the Scala 3 programming language.
+languages: [ru, zh-cn]
+num: 4
+previous-page: why-scala-3
+next-page: taste-hello-world
+---
+
+
+This chapter provides a whirlwind tour of the main features of the Scala 3 programming language.
+After this initial tour, the rest of the book provides more details on these features, and the [Reference documentation][reference] provides _many_ more details.
+
+## Setting Up Scala
+
+Throughout this chapter, and the rest of the book, we encourage you to try out the examples by either copying
+them or typing them out manually. The tools necessary to follow along with the examples on your own computer
+can be installed by following our [getting started guide][get-started].
+
+> Alternatively you can run the examples in a web browser with [Scastie](https://scastie.scala-lang.org), a
+> fully online editor and code-runner for Scala.
+
+## Comments
+
+One good thing to know up front is that comments in Scala are just like comments in Java (and many other languages):
+
+{% tabs comments %}
+{% tab 'Scala 2 and 3' for=comments %}
+```scala
+// a single line comment
+
+/*
+ * a multiline comment
+ */
+
+/**
+ * also a multiline comment
+ */
+```
+{% endtab %}
+{% endtabs %}
+
+## IDEs
+
+The two main IDEs (integrated development environments) for Scala are:
+
+- [IntelliJ IDEA](/getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.html)
+- [Visual Studio Code](https://scalameta.org/metals/docs/editors/vscode/)
+
+## Naming conventions
+
+Another good thing to know is that Scala naming conventions follow the same “camel case” style as Java:
+
+- Class names: `Person`, `StoreEmployee`
+- Variable names: `name`, `firstName`
+- Method names: `convertToInt`, `toUpper`
+
+More on conventions used while writing Scala code can be found in the [Style Guide](/style/index.html).
+
+[reference]: {{ site.scala3ref }}/overview.html
+[get-started]: {% link _overviews/getting-started/install-scala.md %}
diff --git a/_overviews/scala3-book/taste-methods.md b/_overviews/scala3-book/taste-methods.md
new file mode 100644
index 0000000000..6c54818805
--- /dev/null
+++ b/_overviews/scala3-book/taste-methods.md
@@ -0,0 +1,159 @@
+---
+title: Methods
+type: section
+description: This section provides an introduction to defining and using methods in Scala 3.
+languages: [ru, zh-cn]
+num: 10
+previous-page: taste-modeling
+next-page: taste-functions
+---
+
+
+## Scala methods
+
+Scala classes, case classes, traits, enums, and objects can all contain methods.
+The syntax of a simple method looks like this:
+
+{% tabs method_1 %}
+{% tab 'Scala 2 and 3' for=method_1 %}
+```scala
+def methodName(param1: Type1, param2: Type2): ReturnType =
+ // the method body
+ // goes here
+```
+{% endtab %}
+{% endtabs %}
+
+Here are a few examples:
+
+{% tabs method_2 %}
+{% tab 'Scala 2 and 3' for=method_2 %}
+```scala
+def sum(a: Int, b: Int): Int = a + b
+def concatenate(s1: String, s2: String): String = s1 + s2
+```
+{% endtab %}
+{% endtabs %}
+
+You don’t have to declare a method’s return type, so you can write those methods like this, if you prefer:
+
+{% tabs method_3 %}
+{% tab 'Scala 2 and 3' for=method_3 %}
+```scala
+def sum(a: Int, b: Int) = a + b
+def concatenate(s1: String, s2: String) = s1 + s2
+```
+{% endtab %}
+{% endtabs %}
+
+This is how you call those methods:
+
+{% tabs method_4 %}
+{% tab 'Scala 2 and 3' for=method_4 %}
+```scala
+val x = sum(1, 2)
+val y = concatenate("foo", "bar")
+```
+{% endtab %}
+{% endtabs %}
+
+Here’s an example of a multiline method:
+
+{% tabs method_5 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_5 %}
+```scala
+def getStackTraceAsString(t: Throwable): String = {
+ val sw = new StringWriter
+ t.printStackTrace(new PrintWriter(sw))
+ sw.toString
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=method_5 %}
+```scala
+def getStackTraceAsString(t: Throwable): String =
+ val sw = new StringWriter
+ t.printStackTrace(new PrintWriter(sw))
+ sw.toString
+```
+{% endtab %}
+{% endtabs %}
+
+Method parameters can also have default values.
+In this example, the `timeout` parameter has a default value of `5000`:
+
+{% tabs method_6 %}
+{% tab 'Scala 2 and 3' for=method_6 %}
+```scala
+def makeConnection(url: String, timeout: Int = 5000): Unit =
+ println(s"url=$url, timeout=$timeout")
+```
+{% endtab %}
+{% endtabs %}
+
+Because a default `timeout` value is supplied in the method declaration, the method can be called in these two ways:
+
+{% tabs method_7 %}
+{% tab 'Scala 2 and 3' for=method_7 %}
+```scala
+makeConnection("https://localhost") // url=http://localhost, timeout=5000
+makeConnection("https://localhost", 2500) // url=http://localhost, timeout=2500
+```
+{% endtab %}
+{% endtabs %}
+
+Scala also supports the use of _named parameters_ when calling a method, so you can also call that method like this, if you prefer:
+
+{% tabs method_8 %}
+{% tab 'Scala 2 and 3' for=method_8 %}
+```scala
+makeConnection(
+ url = "https://localhost",
+ timeout = 2500
+)
+```
+{% endtab %}
+{% endtabs %}
+
+Named parameters are particularly useful when multiple method parameters have the same type.
+At a glance, with this method you may wonder which parameters are set to `true` or `false`:
+
+{% tabs method_9 %}
+{% tab 'Scala 2 and 3' for=method_9 %}
+
+```scala
+engage(true, true, true, false)
+```
+
+{% endtab %}
+{% endtabs %}
+
+The `extension` keyword declares that you’re about to define one or more extension methods on the parameter that’s put in parentheses.
+As shown with this example, the parameter `s` of type `String` can then be used in the body of your extension methods.
+
+This next example shows how to add a `makeInt` method to the `String` class.
+Here, `makeInt` takes a parameter named `radix`.
+The code doesn’t account for possible string-to-integer conversion errors, but skipping that detail, the examples show how it works:
+
+{% tabs extension %}
+{% tab 'Scala 3 Only' %}
+
+```scala
+extension (s: String)
+ def makeInt(radix: Int): Int = Integer.parseInt(s, radix)
+
+"1".makeInt(2) // Int = 1
+"10".makeInt(2) // Int = 2
+"100".makeInt(2) // Int = 4
+```
+
+{% endtab %}
+{% endtabs %}
+
+## See also
+
+Scala Methods can be much more powerful: they can take type parameters and context parameters.
+They are covered in detail in the [Domain Modeling][data-1] section.
+
+[data-1]: {% link _overviews/scala3-book/domain-modeling-tools.md %}
diff --git a/_overviews/scala3-book/taste-modeling.md b/_overviews/scala3-book/taste-modeling.md
new file mode 100644
index 0000000000..3e391d745a
--- /dev/null
+++ b/_overviews/scala3-book/taste-modeling.md
@@ -0,0 +1,422 @@
+---
+title: Domain Modeling
+type: section
+description: This section provides an introduction to data modeling in Scala 3.
+languages: [ru, zh-cn]
+num: 9
+previous-page: taste-control-structures
+next-page: taste-methods
+---
+
+
+{% comment %}
+NOTE: I kept the OOP section first, assuming that most readers will be coming from an OOP background.
+{% endcomment %}
+
+Scala supports both functional programming (FP) and object-oriented programming (OOP), as well as a fusion of the two paradigms.
+This section provides a quick overview of data modeling in OOP and FP.
+
+## OOP Domain Modeling
+
+When writing code in an OOP style, your two main tools for data encapsulation are _traits_ and _classes_.
+
+{% comment %}
+NOTE: Julien had a comment, “in OOP we don’t really model data.
+It’s more about modeling operations, imho.”
+
+How to resolve? Is there a good DDD term to use here?
+{% endcomment %}
+
+### Traits
+
+Scala traits can be used as simple interfaces, but they can also contain abstract and concrete methods and fields, and they can have parameters, just like classes.
+They provide a great way for you to organize behaviors into small, modular units.
+Later, when you want to create concrete implementations of attributes and behaviors, classes and objects can extend traits, mixing in as many traits as needed to achieve the desired behavior.
+
+As an example of how to use traits as interfaces, here are three traits that define well-organized and modular behaviors for animals like dogs and cats:
+
+{% tabs traits class=tabs-scala-version %}
+{% tab 'Scala 2' for=traits %}
+
+```scala
+trait Speaker {
+ def speak(): String // has no body, so it’s abstract
+}
+
+trait TailWagger {
+ def startTail(): Unit = println("tail is wagging")
+ def stopTail(): Unit = println("tail is stopped")
+}
+
+trait Runner {
+ def startRunning(): Unit = println("I’m running")
+ def stopRunning(): Unit = println("Stopped running")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=traits %}
+
+```scala
+trait Speaker:
+ def speak(): String // has no body, so it’s abstract
+
+trait TailWagger:
+ def startTail(): Unit = println("tail is wagging")
+ def stopTail(): Unit = println("tail is stopped")
+
+trait Runner:
+ def startRunning(): Unit = println("I’m running")
+ def stopRunning(): Unit = println("Stopped running")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Given those traits, here’s a `Dog` class that extends all of those traits while providing a behavior for the abstract `speak` method:
+
+{% tabs traits-class class=tabs-scala-version %}
+{% tab 'Scala 2' for=traits-class %}
+
+```scala
+class Dog(name: String) extends Speaker with TailWagger with Runner {
+ def speak(): String = "Woof!"
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=traits-class %}
+
+```scala
+class Dog(name: String) extends Speaker, TailWagger, Runner:
+ def speak(): String = "Woof!"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Notice how the class extends the traits with the `extends` keyword.
+
+Similarly, here’s a `Cat` class that implements those same traits while also overriding two of the concrete methods it inherits:
+
+{% tabs traits-override class=tabs-scala-version %}
+{% tab 'Scala 2' for=traits-override %}
+
+```scala
+class Cat(name: String) extends Speaker with TailWagger with Runner {
+ def speak(): String = "Meow"
+ override def startRunning(): Unit = println("Yeah ... I don’t run")
+ override def stopRunning(): Unit = println("No need to stop")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=traits-override %}
+
+```scala
+class Cat(name: String) extends Speaker, TailWagger, Runner:
+ def speak(): String = "Meow"
+ override def startRunning(): Unit = println("Yeah ... I don’t run")
+ override def stopRunning(): Unit = println("No need to stop")
+```
+
+{% endtab %}
+{% endtabs %}
+
+These examples show how those classes are used:
+
+{% tabs traits-use class=tabs-scala-version %}
+{% tab 'Scala 2' for=traits-use %}
+
+```scala
+val d = new Dog("Rover")
+println(d.speak()) // prints "Woof!"
+
+val c = new Cat("Morris")
+println(c.speak()) // "Meow"
+c.startRunning() // "Yeah ... I don’t run"
+c.stopRunning() // "No need to stop"
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=traits-use %}
+
+```scala
+val d = Dog("Rover")
+println(d.speak()) // prints "Woof!"
+
+val c = Cat("Morris")
+println(c.speak()) // "Meow"
+c.startRunning() // "Yeah ... I don’t run"
+c.stopRunning() // "No need to stop"
+```
+
+{% endtab %}
+{% endtabs %}
+
+If that code makes sense---great, you’re comfortable with traits as interfaces.
+If not, don’t worry, they’re explained in more detail in the [Domain Modeling][data-1] chapter.
+
+### Classes
+
+Scala _classes_ are used in OOP-style programming.
+Here’s an example of a class that models a “person.” In OOP, fields are typically mutable, so `firstName` and `lastName` are both declared as `var` parameters:
+
+{% tabs class_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=class_1 %}
+
+```scala
+class Person(var firstName: String, var lastName: String) {
+ def printFullName() = println(s"$firstName $lastName")
+}
+
+val p = new Person("John", "Stephens")
+println(p.firstName) // "John"
+p.lastName = "Legend"
+p.printFullName() // "John Legend"
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=class_1 %}
+
+```scala
+class Person(var firstName: String, var lastName: String):
+ def printFullName() = println(s"$firstName $lastName")
+
+val p = Person("John", "Stephens")
+println(p.firstName) // "John"
+p.lastName = "Legend"
+p.printFullName() // "John Legend"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Notice that the class declaration creates a constructor:
+
+{% tabs class_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=class_2 %}
+
+```scala
+// this code uses that constructor
+val p = new Person("John", "Stephens")
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=class_2 %}
+
+```scala
+// this code uses that constructor
+val p = Person("John", "Stephens")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Constructors and other class-related topics are covered in the [Domain Modeling][data-1] chapter.
+
+## FP Domain Modeling
+
+{% comment %}
+NOTE: Julien had a note about expecting to see sealed traits here.
+I didn’t include that because I didn’t know if enums are intended
+to replace the Scala2 “sealed trait + case class” pattern. How to resolve?
+{% endcomment %}
+
+When writing code in an FP style, you’ll use these concepts:
+
+- Algebraic Data Types to define the data
+- Traits for functionality on the data.
+
+### Enumerations and Sum Types
+
+Sum types are one way to model algebraic data types (ADTs) in Scala.
+
+They are used when data can be represented with different choices.
+
+For instance, a pizza has three main attributes:
+
+- Crust size
+- Crust type
+- Toppings
+
+These are concisely modeled with enumerations, which are sum types that only contain singleton values:
+
+{% tabs enum_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=enum_1 %}
+
+In Scala 2 `sealed` classes and `case object` are combined to define an enumeration:
+
+```scala
+sealed abstract class CrustSize
+object CrustSize {
+ case object Small extends CrustSize
+ case object Medium extends CrustSize
+ case object Large extends CrustSize
+}
+
+sealed abstract class CrustType
+object CrustType {
+ case object Thin extends CrustType
+ case object Thick extends CrustType
+ case object Regular extends CrustType
+}
+
+sealed abstract class Topping
+object Topping {
+ case object Cheese extends Topping
+ case object Pepperoni extends Topping
+ case object BlackOlives extends Topping
+ case object GreenOlives extends Topping
+ case object Onions extends Topping
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=enum_1 %}
+
+Scala 3 offers the `enum` construct for defining enumerations:
+
+```scala
+enum CrustSize:
+ case Small, Medium, Large
+
+enum CrustType:
+ case Thin, Thick, Regular
+
+enum Topping:
+ case Cheese, Pepperoni, BlackOlives, GreenOlives, Onions
+```
+
+{% endtab %}
+{% endtabs %}
+
+Once you have an enumeration you can import its members as ordinary values:
+
+{% tabs enum_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=enum_2 %}
+
+```scala
+import CrustSize._
+val currentCrustSize = Small
+
+// enums in a `match` expression
+currentCrustSize match {
+ case Small => println("Small crust size")
+ case Medium => println("Medium crust size")
+ case Large => println("Large crust size")
+}
+
+// enums in an `if` statement
+if (currentCrustSize == Small) println("Small crust size")
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=enum_2 %}
+
+```scala
+import CrustSize.*
+val currentCrustSize = Small
+
+// enums in a `match` expression
+currentCrustSize match
+ case Small => println("Small crust size")
+ case Medium => println("Medium crust size")
+ case Large => println("Large crust size")
+
+// enums in an `if` statement
+if currentCrustSize == Small then println("Small crust size")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Here’s another example of how to create a sum type with Scala, this would not be called an enumeration because the `Succ` case has parameters:
+
+{% tabs enum_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=enum_3 %}
+
+```scala
+sealed abstract class Nat
+object Nat {
+ case object Zero extends Nat
+ case class Succ(pred: Nat) extends Nat
+}
+```
+
+Sum Types are covered in detail in the [Domain Modeling]({% link _overviews/scala3-book/domain-modeling-tools.md %}) section of this book.
+
+{% endtab %}
+{% tab 'Scala 3' for=enum_3 %}
+
+```scala
+enum Nat:
+ case Zero
+ case Succ(pred: Nat)
+```
+
+Enums are covered in detail in the [Domain Modeling]({% link _overviews/scala3-book/domain-modeling-tools.md %}) section of this book, and in the [Reference documentation]({{ site.scala3ref }}/enums/enums.html).
+
+{% endtab %}
+{% endtabs %}
+
+### Product Types
+
+A product type is an algebraic data type (ADT) that only has one shape, for example a singleton object, represented in Scala by a `case` object; or an immutable structure with accessible fields, represented by a `case` class.
+
+A `case` class has all of the functionality of a `class`, and also has additional features baked in that make them useful for functional programming.
+When the compiler sees the `case` keyword in front of a `class` it has these effects and benefits:
+
+- Case class constructor parameters are public `val` fields by default, so the fields are immutable, and accessor methods are generated for each parameter.
+- An `unapply` method is generated, which lets you use case classes in more ways in `match` expressions.
+- A `copy` method is generated in the class.
+ This provides a way to create updated copies of the object without changing the original object.
+- `equals` and `hashCode` methods are generated to implement structural equality.
+- A default `toString` method is generated, which is helpful for debugging.
+
+{% comment %}
+NOTE: Julien had a comment about how he decides when to use case classes vs classes. Add something here?
+{% endcomment %}
+
+You _can_ manually add all of those methods to a class yourself, but since those features are so commonly used in functional programming, using a `case` class is much more convenient.
+
+This code demonstrates several `case` class features:
+
+{% tabs case-class %}
+{% tab 'Scala 2 and 3' for=case-class %}
+
+```scala
+// define a case class
+case class Person(
+ name: String,
+ vocation: String
+)
+
+// create an instance of the case class
+val p = Person("Reginald Kenneth Dwight", "Singer")
+
+// a good default toString method
+p // : Person = Person(Reginald Kenneth Dwight,Singer)
+
+// can access its fields, which are immutable
+p.name // "Reginald Kenneth Dwight"
+p.name = "Joe" // error: can’t reassign a val field
+
+// when you need to make a change, use the `copy` method
+// to “update as you copy”
+val p2 = p.copy(name = "Elton John")
+p2 // : Person = Person(Elton John,Singer)
+```
+
+{% endtab %}
+{% endtabs %}
+
+See the [Domain Modeling][data-1] sections for many more details on `case` classes.
+
+[data-1]: {% link _overviews/scala3-book/domain-modeling-tools.md %}
diff --git a/_overviews/scala3-book/taste-objects.md b/_overviews/scala3-book/taste-objects.md
new file mode 100644
index 0000000000..479182bfa2
--- /dev/null
+++ b/_overviews/scala3-book/taste-objects.md
@@ -0,0 +1,155 @@
+---
+title: Singleton Objects
+type: section
+description: This section provides an introduction to the use of singleton objects in Scala 3.
+languages: [ru, zh-cn]
+num: 12
+previous-page: taste-functions
+next-page: taste-collections
+---
+
+
+In Scala, the `object` keyword creates a Singleton object.
+Put another way, an object defines a class that has exactly one instance.
+
+Objects have several uses:
+
+- They are used to create collections of utility methods.
+- A _companion object_ is an object that has the same name as the class it shares a file with.
+ In this situation, that class is also called a _companion class_.
+- They’re used to implement traits to create _modules_.
+
+## “Utility” methods
+
+Because an `object` is a Singleton, its methods can be accessed like `static` methods in a Java class.
+For example, this `StringUtils` object contains a small collection of string-related methods:
+
+
+{% tabs object_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=object_1 %}
+```scala
+object StringUtils {
+ def isNullOrEmpty(s: String): Boolean = s == null || s.trim.isEmpty
+ def leftTrim(s: String): String = s.replaceAll("^\\s+", "")
+ def rightTrim(s: String): String = s.replaceAll("\\s+$", "")
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=object_1 %}
+```scala
+object StringUtils:
+ def isNullOrEmpty(s: String): Boolean = s == null || s.trim.isEmpty
+ def leftTrim(s: String): String = s.replaceAll("^\\s+", "")
+ def rightTrim(s: String): String = s.replaceAll("\\s+$", "")
+```
+{% endtab %}
+{% endtabs %}
+
+Because `StringUtils` is a singleton, its methods can be called directly on the object:
+
+{% tabs object_2 %}
+{% tab 'Scala 2 and 3' for=object_2 %}
+```scala
+val x = StringUtils.isNullOrEmpty("") // true
+val x = StringUtils.isNullOrEmpty("a") // false
+```
+{% endtab %}
+{% endtabs %}
+
+## Companion objects
+
+A companion class or object can access the private members of its companion.
+Use a companion object for methods and values which aren’t specific to instances of the companion class.
+
+This example demonstrates how the `area` method in the companion class can access the private `calculateArea` method in its companion object:
+
+{% tabs object_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=object_3 %}
+```scala
+import scala.math._
+
+class Circle(radius: Double) {
+ import Circle._
+ def area: Double = calculateArea(radius)
+}
+
+object Circle {
+ private def calculateArea(radius: Double): Double =
+ Pi * pow(radius, 2.0)
+}
+
+val circle1 = new Circle(5.0)
+circle1.area // Double = 78.53981633974483
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=object_3 %}
+```scala
+import scala.math.*
+
+class Circle(radius: Double):
+ import Circle.*
+ def area: Double = calculateArea(radius)
+
+object Circle:
+ private def calculateArea(radius: Double): Double =
+ Pi * pow(radius, 2.0)
+
+val circle1 = Circle(5.0)
+circle1.area // Double = 78.53981633974483
+```
+{% endtab %}
+{% endtabs %}
+
+## Creating modules from traits
+
+Objects can also be used to implement traits to create modules.
+This technique takes two traits and combines them to create a concrete `object`:
+
+{% tabs object_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=object_4 %}
+```scala
+trait AddService {
+ def add(a: Int, b: Int) = a + b
+}
+
+trait MultiplyService {
+ def multiply(a: Int, b: Int) = a * b
+}
+
+// implement those traits as a concrete object
+object MathService extends AddService with MultiplyService
+
+// use the object
+import MathService._
+println(add(1,1)) // 2
+println(multiply(2,2)) // 4
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=object_4 %}
+```scala
+trait AddService:
+ def add(a: Int, b: Int) = a + b
+
+trait MultiplyService:
+ def multiply(a: Int, b: Int) = a * b
+
+// implement those traits as a concrete object
+object MathService extends AddService, MultiplyService
+
+// use the object
+import MathService.*
+println(add(1,1)) // 2
+println(multiply(2,2)) // 4
+```
+{% endtab %}
+{% endtabs %}
+
+{% comment %}
+NOTE: I don’t know if this is worth keeping, but I’m leaving it here as a comment for now.
+
+> You may read that objects are used to _reify_ traits into modules.
+> _Reify_ means, “to take an abstract concept and turn it into something concrete.” This is what happens in these examples, but “implement” is a more familiar word for most people than “reify.”
+{% endcomment %}
diff --git a/_overviews/scala3-book/taste-repl.md b/_overviews/scala3-book/taste-repl.md
new file mode 100644
index 0000000000..784eaca131
--- /dev/null
+++ b/_overviews/scala3-book/taste-repl.md
@@ -0,0 +1,88 @@
+---
+title: The REPL
+type: section
+description: This section provides an introduction to the Scala REPL.
+languages: [ru, zh-cn]
+num: 6
+previous-page: taste-hello-world
+next-page: taste-vars-data-types
+---
+
+
+The Scala REPL (“Read-Evaluate-Print-Loop”) is a command-line interpreter that you use as a “playground” area to test your Scala code.
+You start a REPL session by running the `scala` or `scala3` command depending on your installation at your operating system command line, where you’ll see a “welcome” prompt like this:
+
+
+{% tabs command-line class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=command-line %}
+```bash
+$ scala
+Welcome to Scala {{site.scala-version}} (OpenJDK 64-Bit Server VM, Java 1.8.0_342).
+Type in expressions for evaluation. Or try :help.
+
+scala> _
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=command-line %}
+```bash
+$ scala
+Welcome to Scala {{site.scala-3-version}} (1.8.0_322, Java OpenJDK 64-Bit Server VM).
+Type in expressions for evaluation. Or try :help.
+
+scala> _
+```
+{% endtab %}
+
+{% endtabs %}
+
+The REPL is a command-line interpreter, so it sits there waiting for you to type something.
+Now you can type Scala expressions to see how they work:
+
+{% tabs expression-one %}
+{% tab 'Scala 2 and 3' for=expression-one %}
+````
+scala> 1 + 1
+val res0: Int = 2
+
+scala> 2 + 2
+val res1: Int = 4
+````
+{% endtab %}
+{% endtabs %}
+
+As shown in the output, if you don’t assign a variable to the result of an expression, the REPL creates variables named `res0`, `res1`, etc., for you.
+You can use these variable names in subsequent expressions:
+
+{% tabs expression-two %}
+{% tab 'Scala 2 and 3' for=expression-two %}
+````
+scala> val x = res0 * 10
+val x: Int = 20
+````
+{% endtab %}
+{% endtabs %}
+
+Notice that the REPL output also shows the result of your expressions.
+
+You can run all sorts of experiments in the REPL.
+This example shows how to create and then call a `sum` method:
+
+{% tabs expression-three %}
+{% tab 'Scala 2 and 3' for=expression-three %}
+````
+scala> def sum(a: Int, b: Int): Int = a + b
+def sum(a: Int, b: Int): Int
+
+scala> sum(2, 2)
+val res2: Int = 4
+````
+{% endtab %}
+{% endtabs %}
+
+If you prefer a browser-based playground environment, you can also use [scastie.scala-lang.org](https://scastie.scala-lang.org).
+
+If you prefer writing your code in a text editor instead of in console prompt, you can use a [worksheet].
+
+[worksheet]: {% link _overviews/scala3-book/tools-worksheets.md %}
diff --git a/_overviews/scala3-book/taste-summary.md b/_overviews/scala3-book/taste-summary.md
new file mode 100644
index 0000000000..96c95089c3
--- /dev/null
+++ b/_overviews/scala3-book/taste-summary.md
@@ -0,0 +1,32 @@
+---
+title: Summary
+type: section
+description: This page provides a summary of the previous 'Taste of Scala' sections.
+languages: [ru, zh-cn]
+num: 16
+previous-page: taste-toplevel-definitions
+next-page: first-look-at-types
+---
+
+
+In the previous sections you saw:
+
+- How to use the Scala REPL
+- How to create variables with `val` and `var`
+- Some common data types
+- Control structures
+- How to model the real world using OOP and FP styles
+- How to create and use methods
+- How to use lambdas (anonymous functions) and higher-order functions
+- How to use objects for several purposes
+- An introduction to [contextual abstraction][contextual]
+
+We also mentioned that if you prefer using a browser-based playground environment instead of the Scala REPL, you can also use [Scastie](https://scastie.scala-lang.org/).
+
+Scala has even more features that aren’t covered in this whirlwind tour.
+See the remainder of this book and the [Reference documentation][reference] for many more details.
+
+
+
+[reference]: {{ site.scala3ref }}/overview.html
+[contextual]: {% link _overviews/scala3-book/ca-contextual-abstractions-intro.md %}
diff --git a/_overviews/scala3-book/taste-toplevel-definitions.md b/_overviews/scala3-book/taste-toplevel-definitions.md
new file mode 100644
index 0000000000..b56273945f
--- /dev/null
+++ b/_overviews/scala3-book/taste-toplevel-definitions.md
@@ -0,0 +1,71 @@
+---
+title: Toplevel Definitions
+type: section
+description: This page provides an introduction to top-level definitions in Scala 3
+languages: [ru, zh-cn]
+num: 15
+previous-page: taste-contextual-abstractions
+next-page: taste-summary
+---
+
+
+In Scala 3, all kinds of definitions can be written at the “top level” of your source code files.
+For instance, you can create a file named _MyCoolApp.scala_ and put these contents into it:
+
+{% tabs toplevel_1 %}
+{% tab 'Scala 3 only' for=toplevel_1 %}
+```scala
+import scala.collection.mutable.ArrayBuffer
+
+enum Topping:
+ case Cheese, Pepperoni, Mushrooms
+
+import Topping.*
+class Pizza:
+ val toppings = ArrayBuffer[Topping]()
+
+val p = Pizza()
+
+extension (s: String)
+ def capitalizeAllWords = s.split(" ").map(_.capitalize).mkString(" ")
+
+val hwUpper = "hello, world".capitalizeAllWords
+
+type Money = BigDecimal
+
+// more definitions here as desired ...
+
+@main def myApp =
+ p.toppings += Cheese
+ println("show me the code".capitalizeAllWords)
+```
+{% endtab %}
+{% endtabs %}
+
+As shown, there’s no need to put those definitions inside a `package`, `class`, or other construct.
+
+## Replaces package objects
+
+If you’re familiar with Scala 2, this approach replaces _package objects_.
+But while being much easier to use, they work similarly: When you place a definition in a package named _foo_, you can then access that definition under all other packages under _foo_, such as within the _foo.bar_ package in this example:
+
+{% tabs toplevel_2 %}
+{% tab 'Scala 3 only' for=toplevel_2 %}
+```scala
+package foo {
+ def double(i: Int) = i * 2
+}
+
+package foo {
+ package bar {
+ @main def fooBarMain =
+ println(s"${double(1)}") // this works
+ }
+}
+```
+{% endtab %}
+{% endtabs %}
+
+Curly braces are used in this example to put an emphasis on the package nesting.
+
+The benefit of this approach is that you can place definitions under a package named _com.acme.myapp_, and then those definitions can be referenced within _com.acme.myapp.model_, _com.acme.myapp.controller_, etc.
diff --git a/_overviews/scala3-book/taste-vars-data-types.md b/_overviews/scala3-book/taste-vars-data-types.md
new file mode 100644
index 0000000000..194e2d7f40
--- /dev/null
+++ b/_overviews/scala3-book/taste-vars-data-types.md
@@ -0,0 +1,273 @@
+---
+title: Variables and Data Types
+type: section
+description: This section demonstrates val and var variables, and some common Scala data types.
+languages: [ru, zh-cn]
+num: 7
+previous-page: taste-repl
+next-page: taste-control-structures
+---
+
+
+This section provides a look at Scala variables and data types.
+
+## Two types of variables
+
+When you create a new variable in Scala, you declare whether the variable is immutable or mutable:
+
+
+
+
+
Variable Type
+
Description
+
+
+
+
+
val
+
Creates an immutable variable—like final in Java. You should always create a variable with val, unless there’s a reason you need a mutable variable.
+
+
+
var
+
Creates a mutable variable, and should only be used when a variable’s contents will change over time.
+
+
+
+
+These examples show how to create `val` and `var` variables:
+
+{% tabs var-express-1 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+// immutable
+val a = 0
+
+// mutable
+var b = 1
+```
+{% endtab %}
+{% endtabs %}
+
+In an application, a `val` can’t be reassigned.
+You’ll cause a compiler error if you try to reassign one:
+
+{% tabs var-express-2 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val msg = "Hello, world"
+msg = "Aloha" // "reassignment to val" error; this won’t compile
+```
+{% endtab %}
+{% endtabs %}
+
+Conversely, a `var` can be reassigned:
+
+{% tabs var-express-3 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+var msg = "Hello, world"
+msg = "Aloha" // this compiles because a var can be reassigned
+```
+{% endtab %}
+{% endtabs %}
+
+## Declaring variable types
+
+When you create a variable you can explicitly declare its type, or let the compiler infer the type:
+
+{% tabs var-express-4 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val x: Int = 1 // explicit
+val x = 1 // implicit; the compiler infers the type
+```
+{% endtab %}
+{% endtabs %}
+
+The second form is known as _type inference_, and it’s a great way to help keep this type of code concise.
+The Scala compiler can usually infer the data type for you, as shown in the output of these REPL examples:
+
+{% tabs var-express-5 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+scala> val x = 1
+val x: Int = 1
+
+scala> val s = "a string"
+val s: String = a string
+
+scala> val nums = List(1, 2, 3)
+val nums: List[Int] = List(1, 2, 3)
+```
+{% endtab %}
+{% endtabs %}
+
+You can always explicitly declare a variable’s type if you prefer, but in simple assignments like these it isn’t necessary:
+
+{% tabs var-express-6 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val x: Int = 1
+val s: String = "a string"
+val p: Person = Person("Richard")
+```
+{% endtab %}
+{% endtabs %}
+
+Notice that with this approach, the code feels more verbose than necessary.
+
+{% comment %}
+TODO: Jonathan had an early comment on the text below: “While it might feel like this, I would be afraid that people automatically assume from this statement that everything is always boxed.” Suggestion on how to change this?
+{% endcomment %}
+
+## Built-in data types
+
+Scala comes with the standard numeric data types you’d expect, and they’re all full-blown instances of classes.
+In Scala, everything is an object.
+
+These examples show how to declare variables of the numeric types:
+
+{% tabs var-express-7 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val b: Byte = 1
+val i: Int = 1
+val l: Long = 1
+val s: Short = 1
+val d: Double = 2.0
+val f: Float = 3.0
+```
+{% endtab %}
+{% endtabs %}
+
+Because `Int` and `Double` are the default numeric types, you typically create them without explicitly declaring the data type:
+
+{% tabs var-express-8 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val i = 123 // defaults to Int
+val j = 1.0 // defaults to Double
+```
+{% endtab %}
+{% endtabs %}
+
+In your code you can also append the characters `L`, `D`, and `F` (and their lowercase equivalents) to numbers to specify that they are `Long`, `Double`, or `Float` values:
+
+{% tabs var-express-9 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val x = 1_000L // val x: Long = 1000
+val y = 2.2D // val y: Double = 2.2
+val z = 3.3F // val z: Float = 3.3
+```
+{% endtab %}
+{% endtabs %}
+
+When you need really large numbers, use the `BigInt` and `BigDecimal` types:
+
+{% tabs var-express-10 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+var a = BigInt(1_234_567_890_987_654_321L)
+var b = BigDecimal(123_456.789)
+```
+{% endtab %}
+{% endtabs %}
+
+Where `Double` and `Float` are approximate decimal numbers, `BigDecimal` is used for precise arithmetic.
+
+Scala also has `String` and `Char` data types:
+
+{% tabs var-express-11 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val name = "Bill" // String
+val c = 'a' // Char
+```
+{% endtab %}
+{% endtabs %}
+
+### Strings
+
+Scala strings are similar to Java strings, but they have two great additional features:
+
+- They support string interpolation
+- It’s easy to create multiline strings
+
+#### String interpolation
+
+String interpolation provides a very readable way to use variables inside strings.
+For instance, given these three variables:
+
+{% tabs var-express-12 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val firstName = "John"
+val mi = 'C'
+val lastName = "Doe"
+```
+{% endtab %}
+{% endtabs %}
+
+You can combine those variables in a string like this:
+
+{% tabs var-express-13 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+println(s"Name: $firstName $mi $lastName") // "Name: John C Doe"
+```
+{% endtab %}
+{% endtabs %}
+
+Just precede the string with the letter `s`, and then put a `$` symbol before your variable names inside the string.
+
+To embed arbitrary expressions inside a string, enclose them in curly braces:
+
+{% tabs var-express-14 %}
+{% tab 'Scala 2 and 3' %}
+
+``` scala
+println(s"2 + 2 = ${2 + 2}") // prints "2 + 2 = 4"
+
+val x = -1
+println(s"x.abs = ${x.abs}") // prints "x.abs = 1"
+```
+{% endtab %}
+{% endtabs %}
+
+The `s` that you place before the string is just one possible interpolator.
+If you use an `f` instead of an `s`, you can use `printf`-style formatting syntax in the string.
+Furthermore, a string interpolator is just a special method and it is possible to define your own.
+For instance, some database libraries define the very powerful `sql` interpolator.
+
+#### Multiline strings
+
+Multiline strings are created by including the string inside three double-quotes:
+
+{% tabs var-express-15 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val quote = """The essence of Scala:
+ Fusion of functional and object-oriented
+ programming in a typed setting."""
+```
+{% endtab %}
+{% endtabs %}
+
+> For more details on string interpolators and multiline strings, see the [“First Look at Types” chapter][first-look].
+
+[first-look]: {% link _overviews/scala3-book/first-look-at-types.md %}
diff --git a/_overviews/scala3-book/tools-sbt.md b/_overviews/scala3-book/tools-sbt.md
new file mode 100644
index 0000000000..c17820ecf5
--- /dev/null
+++ b/_overviews/scala3-book/tools-sbt.md
@@ -0,0 +1,511 @@
+---
+title: Building and Testing Scala Projects with sbt
+type: section
+description: This section looks at a commonly-used build tool, sbt, and a testing library, ScalaTest.
+languages: [ru, zh-cn]
+num: 71
+previous-page: scala-tools
+next-page: tools-worksheets
+---
+
+In this section you’ll see two tools that are commonly used in Scala projects:
+
+- The [sbt](https://www.scala-sbt.org) build tool
+- [ScalaTest](https://www.scalatest.org), a source code testing framework
+
+We’ll start by showing how to use sbt to build your Scala projects, and then we’ll show how to use sbt and ScalaTest together to test your Scala projects.
+
+> If you want to learn about tools to help you migrate your Scala 2 code to Scala 3, see our [Scala 3 Migration Guide](/scala3/guides/migration/compatibility-intro.html).
+
+
+
+## Building Scala projects with sbt
+
+You can use several different tools to build your Scala projects, including Ant, Maven, Gradle, Mill, and more.
+But a tool named _sbt_ was the first build tool that was specifically created for Scala.
+
+> To install sbt, see [its download page](https://www.scala-sbt.org/download.html) or our [Getting Started][getting_started] page.
+
+
+
+### Creating a “Hello, world” project
+
+You can create an sbt “Hello, world” project in just a few steps.
+First, create a directory to work in, and move into that directory:
+
+```bash
+$ mkdir hello
+$ cd hello
+```
+
+In the directory `hello`, create a subdirectory `project`:
+
+```bash
+$ mkdir project
+```
+
+Create a file named _build.properties_ in the directory `project`, with
+the following content:
+
+```text
+sbt.version=1.10.11
+```
+
+Then create a file named _build.sbt_ in the project root directory that contains this line:
+
+```scala
+scalaVersion := "{{ site.scala-3-version }}"
+```
+
+Now create a file named something like _Hello.scala_---the first part of the name doesn’t matter---with this line:
+
+```scala
+@main def helloWorld = println("Hello, world")
+```
+
+That’s all you have to do.
+
+You should have a project structure like the following:
+
+~~~ bash
+$ tree
+.
+├── build.sbt
+├── Hello.scala
+└── project
+ └── build.properties
+~~~
+
+Now run the project with this `sbt` command:
+
+```bash
+$ sbt run
+```
+
+You should see output that looks like this, including the `"Hello, world"` from your program:
+
+```bash
+$ sbt run
+[info] welcome to sbt 1.5.4 (AdoptOpenJDK Java 11.x)
+[info] loading project definition from project ...
+[info] loading settings for project from build.sbt ...
+[info] compiling 1 Scala source to target/scala-3.0.0/classes ...
+[info] running helloWorld
+Hello, world
+[success] Total time: 2 s
+```
+
+The sbt launcher---the `sbt` command-line tool---loads the version of sbt set in the file _project/build.properties_, which loads the version of the Scala compiler set in the file _build.sbt_, compiles the code in the file _Hello.scala_, and runs the resulting bytecode.
+
+When you look at your directory, you’ll see that sbt has a directory named _target_.
+These are working directories that sbt uses.
+
+As you can see, creating and running a little Scala project with sbt takes just a few simple steps.
+
+### Using sbt with larger projects
+
+For a little project, that’s all that sbt requires to run.
+For larger projects that require many source code files, dependencies, or sbt plugins, you’ll want to create an organized directory structure.
+The rest of this section demonstrates the structure that sbt uses.
+
+
+### The sbt directory structure
+
+Like Maven, sbt uses a standard project directory structure.
+A nice benefit of that is that once you’re comfortable with its structure, it makes it easy to work on other Scala/sbt projects.
+
+The first thing to know is that underneath the root directory of your project, sbt expects a directory structure that looks like this:
+
+```text
+.
+├── build.sbt
+├── project/
+│ └── build.properties
+├── src/
+│ ├── main/
+│ │ ├── java/
+│ │ ├── resources/
+│ │ └── scala/
+│ └── test/
+│ ├── java/
+│ ├── resources/
+│ └── scala/
+└── target/
+```
+
+You can also add a _lib_ directory under the root directory if you want to add unmanaged dependencies---JAR files---to your project.
+
+If you’re going to create a project that has Scala source code files and tests, but won’t be using any Java source code files, and doesn’t need any “resources”---such as embedded images, configuration files, etc.---this is all you really need under the _src_ directory:
+
+```text
+.
+└── src/
+ ├── main/
+ │ └── scala/
+ └── test/
+ └── scala/
+```
+
+
+### “Hello, world” with an sbt directory structure
+
+{% comment %}
+LATER: using something like `sbt new scala/scala3.g8` may eventually
+ be preferable, but that seems to have a few bugs atm (creates
+ a 'target' directory above the root; renames the root dir;
+ uses 'dottyVersion'; 'name' doesn’t match the supplied name;
+ config syntax is a little hard for beginners.)
+{% endcomment %}
+
+Creating this directory structure is simple.
+There are tools to do this for you, but assuming that you’re using a Unix/Linux system, you can use these commands to create your first sbt project directory structure:
+
+```bash
+$ mkdir HelloWorld
+$ cd HelloWorld
+$ mkdir -p src/{main,test}/scala
+$ mkdir project target
+```
+
+When you run a `find .` command after running those commands, you should see this result:
+
+```bash
+$ find .
+.
+./project
+./src
+./src/main
+./src/main/scala
+./src/test
+./src/test/scala
+./target
+```
+
+If you see that, you’re in great shape for the next step.
+
+> There are other ways to create the files and directories for an sbt project.
+> One way is to use the `sbt new` command, [which is documented here on scala-sbt.org](https://www.scala-sbt.org/1.x/docs/Hello.html).
+> That approach isn’t shown here because some of the files it creates are more complicated than necessary for an introduction like this.
+
+
+### Creating a first build.sbt file
+
+At this point you only need two more things to run a “Hello, world” project:
+
+- A _build.sbt_ file
+- A _Hello.scala_ file
+
+For a little project like this, the _build.sbt_ file only needs a `scalaVersion` entry, but we’ll add three lines that you commonly see:
+
+```scala
+name := "HelloWorld"
+version := "0.1"
+scalaVersion := "{{ site.scala-3-version }}"
+```
+
+Because sbt projects use a standard directory structure, sbt can find everything else it needs.
+
+Now you just need to add a little “Hello, world” program.
+
+
+### A “Hello, world” program
+
+In large projects, all of your Scala source code files will go under the _src/main/scala_ and _src/test/scala_ directories, but for a little sample project like this, you can put your source code file in the root directory of your project.
+Therefore, create a file named _HelloWorld.scala_ in the root directory with these contents:
+
+```scala
+@main def helloWorld = println("Hello, world")
+```
+
+That code defines a Scala 3 “main” method that prints the `"Hello, world"` when it’s run.
+
+Now, use the `sbt run` command to compile and run your project:
+
+```bash
+$ sbt run
+
+[info] welcome to sbt
+[info] loading settings for project ...
+[info] loading project definition
+[info] loading settings for project root from build.sbt ...
+[info] Compiling 1 Scala source ...
+[info] running helloWorld
+Hello, world
+[success] Total time: 4 s
+```
+
+The first time you run `sbt` it downloads everything it needs, and that can take a few moments to run, but after that it gets much faster.
+
+Also, once you get this first step working, you’ll find that it’s much faster to run sbt interactively.
+To do that, first run the `sbt` command by itself:
+
+```bash
+$ sbt
+
+[info] welcome to sbt
+[info] loading settings for project ...
+[info] loading project definition ...
+[info] loading settings for project root from build.sbt ...
+[info] sbt server started at
+ local:///${HOME}/.sbt/1.0/server/7d26bae822c36a31071c/sock
+sbt:hello-world> _
+```
+
+Then inside this sbt shell, execute its `run` command:
+
+````
+sbt:hello-world> run
+
+[info] running helloWorld
+Hello, world
+[success] Total time: 0 s
+````
+
+There, that’s much faster.
+
+If you type `help` at the sbt command prompt you’ll see a list of other commands you can run.
+But for now, just type `exit` (or press `CTRL-D`) to leave the sbt shell.
+
+### Using project templates
+
+Manually creating the project structure can be tedious. Thankfully, sbt can create it for you,
+based on a template.
+
+To create a Scala 3 project from a template, run the following command in a shell:
+
+~~~
+$ sbt new scala/scala3.g8
+~~~
+
+Sbt will load the template, ask some questions, and create the project files in a subdirectory:
+
+~~~
+$ tree scala-3-project-template
+scala-3-project-template
+├── build.sbt
+├── project
+│ └── build.properties
+├── README.md
+└── src
+ ├── main
+ │ └── scala
+ │ └── Main.scala
+ └── test
+ └── scala
+ └── Test1.scala
+~~~
+
+> If you want to create a Scala 3 project that cross-compiles with Scala 2, use the template `scala/scala3-cross.g8`:
+>
+> ~~~
+> $ sbt new scala/scala3-cross.g8
+> ~~~
+
+Learn more about `sbt new` and project templates in the [documentation of sbt](https://www.scala-sbt.org/1.x/docs/sbt-new-and-Templates.html#sbt+new+and+Templates).
+
+### Other build tools for Scala
+
+While sbt is widely used, there are other tools you can use to build Scala projects:
+
+- [Ant](https://ant.apache.org/)
+- [Gradle](https://gradle.org/)
+- [Maven](https://maven.apache.org/)
+- [Mill](https://com-lihaoyi.github.io/mill/)
+
+#### Coursier
+
+In a related note, [Coursier](https://get-coursier.io/docs/overview) is a “dependency resolver,” similar to Maven and Ivy in function.
+It’s written from scratch in Scala, “embraces functional programming principles,” and downloads artifacts in parallel for rapid downloads.
+sbt uses it to handle most dependency resolutions, and as a command-line tool, it can be used to easily install tools like sbt, Java, and Scala on your system, as shown in our [Getting Started][getting_started] page.
+
+This example from the `launch` web page shows that the `cs launch` command can be used to launch applications from dependencies:
+
+```scala
+$ cs launch org.scalameta::scalafmt-cli:2.4.2 -- --help
+scalafmt 2.4.2
+Usage: scalafmt [options] [...]
+
+ -h, --help prints this usage text
+ -v, --version print version
+ more ...
+```
+
+See Coursier’s [launch page](https://get-coursier.io/docs/cli-launch) for more details.
+
+
+
+## Using sbt with ScalaTest
+
+[ScalaTest](https://www.scalatest.org) is one of the main testing libraries for Scala projects.
+In this section you’ll see the steps necessary to create a Scala/sbt project that uses ScalaTest.
+
+
+### 1) Create the project directory structure
+
+As with the previous lesson, create an sbt project directory structure for a project named _HelloScalaTest_ with the following commands:
+
+```bash
+$ mkdir HelloScalaTest
+$ cd HelloScalaTest
+$ mkdir -p src/{main,test}/scala
+$ mkdir project
+```
+
+
+### 2) Create the build.properties and build.sbt files
+
+Next, create a _build.properties_ file in the _project/_ subdirectory of your project
+with this line:
+
+```text
+sbt.version=1.10.11
+```
+
+Next, create a _build.sbt_ file in the root directory of your project with these contents:
+
+```scala
+name := "HelloScalaTest"
+version := "0.1"
+scalaVersion := "{{site.scala-3-version}}"
+
+libraryDependencies ++= Seq(
+ "org.scalatest" %% "scalatest" % "3.2.19" % Test
+)
+```
+
+The first three lines of this file are essentially the same as the first example.
+The `libraryDependencies` lines tell sbt to include the dependencies (JAR files) that are needed to include ScalaTest.
+
+> The ScalaTest documentation has always been good, and you can always find the up to date information on what those lines should look like on the [Installing ScalaTest](https://www.scalatest.org/install) page.
+
+
+### 3) Create a Scala source code file
+
+Next, create a Scala program that you can use to demonstrate ScalaTest.
+First, create a directory under _src/main/scala_ named _math_:
+
+```bash
+$ mkdir src/main/scala/math
+ ----
+```
+
+Then, inside that directory, create a file named _MathUtils.scala_ with these contents:
+
+```scala
+package math
+
+object MathUtils:
+ def double(i: Int) = i * 2
+```
+
+That method provides a simple way to demonstrate ScalaTest.
+
+
+{% comment %}
+Because this project doesn’t have a `main` method, we don’t try to run it with `sbt run`; we just compile it with `sbt compile`:
+
+````
+$ sbt compile
+
+[info] welcome to sbt
+[info] loading settings for project ...
+[info] loading project definition ...
+[info] loading settings for project ...
+[info] Executing in batch mode. For better performance use sbt's shell
+[success] Total time: 1 s
+````
+
+With that compiled, let’s create a ScalaTest file to test the `double` method.
+{% endcomment %}
+
+
+### 4) Create your first ScalaTest tests
+
+ScalaTest is very flexible, and offers several different ways to write tests.
+A simple way to get started is to write tests using the ScalaTest `AnyFunSuite`.
+To get started, create a directory named _math_ under the _src/test/scala_ directory:
+
+```bash
+$ mkdir src/test/scala/math
+ ----
+```
+
+Next, create a file named _MathUtilsTests.scala_ in that directory with the following contents:
+
+```scala
+package math
+
+import org.scalatest.funsuite.AnyFunSuite
+
+class MathUtilsTests extends AnyFunSuite:
+
+ // test 1
+ test("'double' should handle 0") {
+ val result = MathUtils.double(0)
+ assert(result == 0)
+ }
+
+ // test 2
+ test("'double' should handle 1") {
+ val result = MathUtils.double(1)
+ assert(result == 2)
+ }
+
+ test("test with Int.MaxValue") (pending)
+
+end MathUtilsTests
+```
+
+This code demonstrates the ScalaTest `AnyFunSuite` approach.
+A few important points:
+
+- Your test class should extend `AnyFunSuite`
+- You create tests as shown, by giving each `test` a unique name
+- At the end of each test you should call `assert` to test that a condition has been satisfied
+- When you know you want to write a test, but you don’t want to write it right now, create the test as “pending,” with the syntax shown
+
+Using ScalaTest like this is similar to JUnit, so if you’re coming to Scala from Java, hopefully this looks similar.
+
+Now you can run these tests with the `sbt test` command.
+Skipping the first few lines of output, the result looks like this:
+
+````
+sbt:HelloScalaTest> test
+
+[info] Compiling 1 Scala source ...
+[info] MathUtilsTests:
+[info] - 'double' should handle 0
+[info] - 'double' should handle 1
+[info] - test with Int.MaxValue (pending)
+[info] Total number of tests run: 2
+[info] Suites: completed 1, aborted 0
+[info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 1
+[info] All tests passed.
+[success] Total time: 1 s
+````
+
+If everything works well, you’ll see output that looks like that.
+Welcome to the world of testing Scala applications with sbt and ScalaTest.
+
+
+### Support for many types of tests
+
+This example demonstrates a style of testing that’s similar to xUnit _Test-Driven Development_ (TDD) style testing, with a few benefits of the _Behavior-Driven Development_ (BDD) style.
+
+As mentioned, ScalaTest is flexible and you can also write tests using other styles, such as a style similar to Ruby’s RSpec.
+You can also use mock objects, property-based testing, and use ScalaTest to test Scala.js code.
+
+See the User Guide on the [ScalaTest website](https://www.scalatest.org) for more details on the different testing styles that are available.
+
+
+
+## Where to go from here
+
+For more information about sbt and ScalaTest, see the following resources:
+
+- [The sbt documentation](https://www.scala-sbt.org/1.x/docs/)
+- [The ScalaTest website](https://www.scalatest.org/)
+
+
+
+[getting_started]: {{ site.baseurl }}/scala3/getting-started.html
diff --git a/_overviews/scala3-book/tools-worksheets.md b/_overviews/scala3-book/tools-worksheets.md
new file mode 100644
index 0000000000..cf14935e46
--- /dev/null
+++ b/_overviews/scala3-book/tools-worksheets.md
@@ -0,0 +1,57 @@
+---
+title: Worksheets
+type: section
+description: This section looks at worksheets, an alternative to Scala projects.
+languages: [ru, zh-cn]
+num: 72
+previous-page: tools-sbt
+next-page: interacting-with-java
+---
+
+A worksheet is a Scala file that is evaluated on save, and the result of each expression is shown
+in a column to the right of your program. Worksheets are like a [REPL session] on steroids, and
+enjoy 1st class editor support: completion, hyperlinking, interactive errors-as-you-type, etc.
+Worksheets use the extension `.worksheet.sc`.
+
+In the following, we show how to use worksheets in IntelliJ, and in VS Code (with the Metals extension).
+
+1. Open a Scala project, or create one.
+ - To create a project in IntelliJ, select “File” -> “New” -> “Project…”, select “Scala”
+ in the left column, and click “Next” to set the project name and location.
+ - To create a project in VS Code, run the command “Metals: New Scala project”, select the
+ seed `scala/scala3.g8`, set the project location, open it in a new VS Code window, and
+ import its build.
+1. Create a file named `hello.worksheet.sc` in the directory `src/main/scala/`.
+ - In IntelliJ, right-click on the directory `src/main/scala/`, and select “New”, and
+ then “File”.
+ - In VS Code, right-click on the directory `src/main/scala/`, and select “New File”.
+1. Paste the following content in the editor:
+ ~~~
+ println("Hello, world!")
+
+ val x = 1
+ x + x
+ ~~~
+1. Evaluate the worksheet.
+ - In IntelliJ, click on the green arrow at the top of the editor to evaluate the worksheet.
+ - In VS Code, save the file.
+
+ You should see the result of the evaluation of every line on the right panel (IntelliJ), or
+ as comments (VS Code).
+
+
+
+A worksheet evaluated in IntelliJ.
+
+
+
+A worksheet evaluated in VS Code (with the Metals extension).
+
+Note that the worksheet will use the Scala version defined by your project (set by the key `scalaVersion`,
+in your file `build.sbt`, typically).
+
+Also note that worksheets don’t have a [program entry point]. Instead, top-level statements and expressions
+are evaluated from top to bottom.
+
+[REPL session]: {% link _overviews/scala3-book/taste-repl.md %}
+[program entry point]: {% link _overviews/scala3-book/methods-main-methods.md %}
diff --git a/_overviews/scala3-book/types-adts-gadts.md b/_overviews/scala3-book/types-adts-gadts.md
new file mode 100644
index 0000000000..356d01c16d
--- /dev/null
+++ b/_overviews/scala3-book/types-adts-gadts.md
@@ -0,0 +1,195 @@
+---
+title: Algebraic Data Types
+type: section
+description: This section introduces and demonstrates algebraic data types (ADTs) in Scala 3.
+languages: [ru, zh-cn]
+num: 54
+previous-page: types-union
+next-page: types-variance
+scala3: true
+versionSpecific: true
+---
+
+
+Algebraic Data Types (ADTs) can be created with the `enum` construct, so we’ll briefly review enumerations before looking at ADTs.
+
+## Enumerations
+
+An _enumeration_ is used to define a type consisting of a set of named values:
+
+```scala
+enum Color:
+ case Red, Green, Blue
+```
+which can be seen as a shorthand for:
+```scala
+enum Color:
+ case Red extends Color
+ case Green extends Color
+ case Blue extends Color
+```
+#### Parameters
+Enums can be parameterized:
+
+```scala
+enum Color(val rgb: Int):
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+```
+This way, each of the different variants has a value member `rgb` which is assigned the corresponding value:
+```scala
+println(Color.Green.rgb) // prints 65280
+```
+
+#### Custom Definitions
+Enums can also have custom definitions:
+
+```scala
+enum Planet(mass: Double, radius: Double):
+
+ private final val G = 6.67300E-11
+ def surfaceGravity = G * mass / (radius * radius)
+ def surfaceWeight(otherMass: Double) = otherMass * surfaceGravity
+
+ case Mercury extends Planet(3.303e+23, 2.4397e6)
+ case Venus extends Planet(4.869e+24, 6.0518e6)
+ case Earth extends Planet(5.976e+24, 6.37814e6)
+ // 5 or 6 more planets ...
+```
+
+Like classes and `case` classes, you can also define a companion object for an enum:
+
+```scala
+object Planet:
+ def main(args: Array[String]) =
+ val earthWeight = args(0).toDouble
+ val mass = earthWeight / Earth.surfaceGravity
+ for (p <- values)
+ println(s"Your weight on $p is ${p.surfaceWeight(mass)}")
+```
+
+## Algebraic Datatypes (ADTs)
+
+The `enum` concept is general enough to also support _algebraic data types_ (ADTs) and their generalized version (GADTs).
+Here’s an example that shows how an `Option` type can be represented as an ADT:
+
+```scala
+enum Option[+T]:
+ case Some(x: T)
+ case None
+```
+
+This example creates an `Option` enum with a covariant type parameter `T` consisting of two cases, `Some` and `None`.
+`Some` is _parameterized_ with a value parameter `x`; this is a shorthand for writing a `case` class that extends `Option`.
+Since `None` is not parameterized, it’s treated as a normal `enum` value.
+
+The `extends` clauses that were omitted in the previous example can also be given explicitly:
+
+```scala
+enum Option[+T]:
+ case Some(x: T) extends Option[T]
+ case None extends Option[Nothing]
+```
+
+As with normal `enum` values, the cases of an `enum` are defined in the `enum`s companion object, so they’re referred to as `Option.Some` and `Option.None` (unless the definitions are “pulled out” with an import):
+
+```scala
+scala> Option.Some("hello")
+val res1: t2.Option[String] = Some(hello)
+
+scala> Option.None
+val res2: t2.Option[Nothing] = None
+```
+
+As with other enumeration uses, ADTs can define additional methods.
+For instance, here’s `Option` again, with an `isDefined` method and an `Option(...)` constructor in its companion object:
+
+```scala
+enum Option[+T]:
+ case Some(x: T)
+ case None
+
+ def isDefined: Boolean = this match
+ case None => false
+ case Some(_) => true
+
+object Option:
+ def apply[T >: Null](x: T): Option[T] =
+ if (x == null) None else Some(x)
+```
+
+Enumerations and ADTs share the same syntactic construct, so they can
+be seen simply as two ends of a spectrum, and it’s perfectly possible
+to construct hybrids.
+For instance, the code below gives an
+implementation of `Color`, either with three enum values or with a
+parameterized case that takes an RGB value:
+
+```scala
+enum Color(val rgb: Int):
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+ case Mix(mix: Int) extends Color(mix)
+```
+
+#### Recursive Enumerations
+So far all the enumerations that we defined consisted of different variants of values or case classes.
+Enumerations can also be recursive, as illustrated in the below example of encoding natural numbers:
+```scala
+enum Nat:
+ case Zero
+ case Succ(n: Nat)
+```
+For example the value `Succ(Succ(Zero))` represents the number `2` in an unary encoding.
+Lists can be defined in a very similar way:
+
+```scala
+enum List[+A]:
+ case Nil
+ case Cons(head: A, tail: List[A])
+```
+
+## Generalized Algebraic Datatypes (GADTs)
+The above notation for enumerations is very concise and serves as the perfect starting point for modeling your data types.
+Since we can always be more explicit, it is also possible to express types that are much more powerful: generalized algebraic datatypes (GADTs).
+
+Here is an example of a GADT where the type parameter (`T`) specifies the contents stored in the box:
+```scala
+enum Box[T](contents: T):
+ case IntBox(n: Int) extends Box[Int](n)
+ case BoolBox(b: Boolean) extends Box[Boolean](b)
+```
+Pattern matching on the particular constructor (`IntBox` or `BoolBox`) recovers the type information:
+```scala
+def extract[T](b: Box[T]): T = b match
+ case IntBox(n) => n + 1
+ case BoolBox(b) => !b
+```
+It is only safe to return an `Int` in the first case, since we know from pattern matching that the input was an `IntBox`.
+
+
+## Desugaring Enumerations
+_Conceptually_, enums can be thought of as defining a sealed class together with its companion object.
+Let’s look at the desugaring of our `Color` enum above:
+```scala
+sealed abstract class Color(val rgb: Int) extends scala.reflect.Enum
+object Color:
+ case object Red extends Color(0xFF0000) { def ordinal = 0 }
+ case object Green extends Color(0x00FF00) { def ordinal = 1 }
+ case object Blue extends Color(0x0000FF) { def ordinal = 2 }
+ case class Mix(mix: Int) extends Color(mix) { def ordinal = 3 }
+
+ def fromOrdinal(ordinal: Int): Color = ordinal match
+ case 0 => Red
+ case 1 => Green
+ case 2 => Blue
+ case _ => throw new NoSuchElementException(ordinal.toString)
+```
+Note that the above desugaring is simplified and we purposefully leave out [some details][desugar-enums].
+
+While enums could be manually encoded using other constructs, using enumerations is more concise and also comes with a few additional utilities (such as the `fromOrdinal` method).
+
+
+[desugar-enums]: {{ site.scala3ref }}/enums/desugarEnums.html
diff --git a/_overviews/scala3-book/types-dependent-function.md b/_overviews/scala3-book/types-dependent-function.md
new file mode 100644
index 0000000000..cf86880fa6
--- /dev/null
+++ b/_overviews/scala3-book/types-dependent-function.md
@@ -0,0 +1,149 @@
+---
+title: Dependent Function Types
+type: section
+description: This section introduces and demonstrates dependent function types in Scala 3.
+languages: [ru, zh-cn]
+num: 58
+previous-page: types-structural
+next-page: types-others
+scala3: true
+versionSpecific: true
+---
+
+A *dependent function type* describes function types, where the result type may depend on the function’s parameter values.
+The concept of dependent types, and of dependent function types, is more advanced and you would typically only come across it when designing your own libraries or using advanced libraries.
+
+## Dependent Method Types
+Let's consider the following example of a heterogenous database that can store values of different types.
+The key contains the information about what's the type of the corresponding value:
+
+```scala
+trait Key { type Value }
+
+trait DB {
+ def get(k: Key): Option[k.Value] // a dependent method
+}
+```
+Given a key, the method `get` lets us access the map and potentially returns the stored value of type `k.Value`.
+We can read this _path-dependent type_ as: "depending on the concrete type of the argument `k`, we return a matching value".
+
+For example, we could have the following keys:
+```scala
+object Name extends Key { type Value = String }
+object Age extends Key { type Value = Int }
+```
+The following calls to method `get` would now type check:
+```scala
+val db: DB = ...
+val res1: Option[String] = db.get(Name)
+val res2: Option[Int] = db.get(Age)
+```
+Calling the method `db.get(Name)` returns a value of type `Option[String]`, while calling `db.get(Age)` returns a value of type `Option[Int]`.
+The return type _depends_ on the concrete type of the argument passed to `get`---hence the name _dependent type_.
+
+## Dependent Function Types
+As seen above, Scala 2 already had support for dependent method types.
+However, creating values of type `DB` is quite cumbersome:
+```scala
+// a user of a DB
+def user(db: DB): Unit =
+ db.get(Name) ... db.get(Age)
+
+// creating an instance of the DB and passing it to `user`
+user(new DB {
+ def get(k: Key): Option[k.Value] = ... // implementation of DB
+})
+```
+We manually need to create an anonymous inner class of `DB`, implementing the `get` method.
+For code that relies on creating many different instances of `DB` this is very tedious.
+
+The trait `DB` only has a single abstract method `get`.
+Wouldn't it be nice, if we could use lambda syntax instead?
+```scala
+user { k =>
+ ... // implementation of DB
+}
+```
+In fact, this is now possible in Scala 3! We can define `DB` as a _dependent function type_:
+```scala
+type DB = (k: Key) => Option[k.Value]
+// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// A dependent function type
+```
+Given this definition of `DB` the above call to `user` type checks, as is.
+
+You can read more about the internals of dependent function types in the [reference documentation][ref].
+
+## Case Study: Numerical Expressions
+Let us assume we want to define a module that abstracts over the internal represention of numbers.
+This can be useful, for instance, to implement libraries for automatic derivation.
+
+We start by defining our module for numbers:
+```scala
+trait Nums:
+ // the type of numbers is left abstract
+ type Num
+
+ // some operations on numbers
+ def lit(d: Double): Num
+ def add(l: Num, r: Num): Num
+ def mul(l: Num, r: Num): Num
+```
+> We omit the concrete implementation of `Nums`, but as an exercise you could implement `Nums` by assigning `type Num = Double` and implement methods accordingly.
+
+A program that uses our number abstraction now has the following type:
+
+```scala
+type Prog = (n: Nums) => n.Num => n.Num
+
+val ex: Prog = nums => x => nums.add(nums.lit(0.8), x)
+```
+The type of a function that computes the derivative of programs like `ex` is:
+```scala
+def derivative(input: Prog): Double
+```
+Given the facility of dependent function types, calling this function with different programs is very convenient:
+```scala
+derivative { nums => x => x }
+derivative { nums => x => nums.add(nums.lit(0.8), x) }
+// ...
+```
+
+To recall, the same program in the encoding above would be:
+```scala
+derivative(new Prog {
+ def apply(nums: Nums)(x: nums.Num): nums.Num = x
+})
+derivative(new Prog {
+ def apply(nums: Nums)(x: nums.Num): nums.Num = nums.add(nums.lit(0.8), x)
+})
+// ...
+```
+
+#### Combination with Context Functions
+The combination of extension methods, [context functions][ctx-fun], and dependent functions provides a powerful tool for library designers.
+For instance, we can refine our library from above as follows:
+```scala
+trait NumsDSL extends Nums:
+ extension (x: Num)
+ def +(y: Num) = add(x, y)
+ def *(y: Num) = mul(x, y)
+
+def const(d: Double)(using n: Nums): n.Num = n.lit(d)
+
+type Prog = (n: NumsDSL) ?=> n.Num => n.Num
+// ^^^
+// prog is now a context function that implicitly
+// assumes a NumsDSL in the calling context
+
+def derivative(input: Prog): Double = ...
+
+// notice how we do not need to mention Nums in the examples below?
+derivative { x => const(1.0) + x }
+derivative { x => x * x + const(2.0) }
+// ...
+```
+
+
+[ref]: {{ site.scala3ref }}/new-types/dependent-function-types.html
+[ctx-fun]: {{ site.scala3ref }}/contextual/context-functions.html
diff --git a/_overviews/scala3-book/types-generics.md b/_overviews/scala3-book/types-generics.md
new file mode 100644
index 0000000000..84ddd4599e
--- /dev/null
+++ b/_overviews/scala3-book/types-generics.md
@@ -0,0 +1,89 @@
+---
+title: Generics
+type: section
+description: This section introduces and demonstrates generics in Scala 3.
+languages: [ru, zh-cn]
+num: 51
+previous-page: types-inferred
+next-page: types-intersection
+---
+
+
+Generic classes (or traits) take a type as _a parameter_ within square brackets `[...]`.
+The Scala convention is to use a single letter (like `A`) to name those type parameters.
+The type can then be used inside the class as needed for method instance parameters, or on return types:
+
+{% tabs stack class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+// here we declare the type parameter A
+// v
+class Stack[A] {
+ private var elements: List[A] = Nil
+ // ^
+ // Here we refer to the type parameter
+ // v
+ def push(x: A): Unit =
+ elements = elements.prepended(x)
+ def peek: A = elements.head
+ def pop(): A = {
+ val currentTop = peek
+ elements = elements.tail
+ currentTop
+ }
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+// here we declare the type parameter A
+// v
+class Stack[A]:
+ private var elements: List[A] = Nil
+ // ^
+ // Here we refer to the type parameter
+ // v
+ def push(x: A): Unit =
+ elements = elements.prepended(x)
+ def peek: A = elements.head
+ def pop(): A =
+ val currentTop = peek
+ elements = elements.tail
+ currentTop
+```
+{% endtab %}
+{% endtabs %}
+
+This implementation of a `Stack` class takes any type as a parameter.
+The beauty of generics is that you can now create a `Stack[Int]`, `Stack[String]`, and so on, allowing you to reuse your implementation of a `Stack` for arbitrary element types.
+
+This is how you create and use a `Stack[Int]`:
+
+{% tabs stack-usage class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+val stack = new Stack[Int]
+stack.push(1)
+stack.push(2)
+println(stack.pop()) // prints 2
+println(stack.pop()) // prints 1
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val stack = Stack[Int]
+stack.push(1)
+stack.push(2)
+println(stack.pop()) // prints 2
+println(stack.pop()) // prints 1
+```
+{% endtab %}
+{% endtabs %}
+
+> See the [Variance section][variance] for details on how to express variance with generic types.
+
+
+[variance]: {% link _overviews/scala3-book/types-variance.md %}
diff --git a/_overviews/scala3-book/types-inferred.md b/_overviews/scala3-book/types-inferred.md
new file mode 100644
index 0000000000..92333b3735
--- /dev/null
+++ b/_overviews/scala3-book/types-inferred.md
@@ -0,0 +1,53 @@
+---
+title: Inferred Types
+type: section
+description: This section introduces and demonstrates inferred types in Scala 3
+languages: [ru, zh-cn]
+num: 50
+previous-page: types-introduction
+next-page: types-generics
+---
+
+
+As with other statically typed programming languages, in Scala you can _declare_ a type when creating a new variable:
+
+{% tabs xy %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val x: Int = 1
+val y: Double = 1
+```
+{% endtab %}
+{% endtabs %}
+
+In those examples the types are _explicitly_ declared to be `Int` and `Double`, respectively.
+However, in Scala you generally don’t have to declare the type when defining value binders:
+
+{% tabs abm %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = 1
+val b = List(1, 2, 3)
+val m = Map(1 -> "one", 2 -> "two")
+```
+{% endtab %}
+{% endtabs %}
+
+When you do this, Scala _infers_ the types, as shown in the following REPL interaction:
+
+{% tabs abm2 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> val a = 1
+val a: Int = 1
+
+scala> val b = List(1, 2, 3)
+val b: List[Int] = List(1, 2, 3)
+
+scala> val m = Map(1 -> "one", 2 -> "two")
+val m: Map[Int, String] = Map(1 -> one, 2 -> two)
+```
+{% endtab %}
+{% endtabs %}
+
+Indeed, most variables are defined this way, and Scala’s ability to automatically infer types is one feature that makes it _feel_ like a dynamically typed language.
diff --git a/_overviews/scala3-book/types-intersection.md b/_overviews/scala3-book/types-intersection.md
new file mode 100644
index 0000000000..2c533ffd09
--- /dev/null
+++ b/_overviews/scala3-book/types-intersection.md
@@ -0,0 +1,64 @@
+---
+title: Intersection Types
+type: section
+description: This section introduces and demonstrates intersection types in Scala 3.
+languages: [ru, zh-cn]
+num: 52
+previous-page: types-generics
+next-page: types-union
+scala3: true
+versionSpecific: true
+---
+
+Used on types, the `&` operator creates a so called _intersection type_.
+The type `A & B` represents values that are **both** of the type `A` and of the type `B` at the same time.
+For instance, the following example uses the intersection type `Resettable & Growable[String]`:
+
+{% tabs intersection-reset-grow %}
+
+{% tab 'Scala 3 Only' %}
+
+```scala
+trait Resettable:
+ def reset(): Unit
+
+trait Growable[A]:
+ def add(a: A): Unit
+
+def f(x: Resettable & Growable[String]): Unit =
+ x.reset()
+ x.add("first")
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+In the method `f` in this example, the parameter `x` is required to be *both* a `Resettable` and a `Growable[String]`.
+
+The _members_ of an intersection type `A & B` are all the members of `A` and all the members of `B`.
+Therefore, as shown, `Resettable & Growable[String]` has member methods `reset` and `add`.
+
+Intersection types can be useful to describe requirements _structurally_.
+That is, in our example `f`, we directly express that we are happy with any value for `x` as long as it’s a subtype of both `Resettable` and `Growable`.
+We **did not** have to create a _nominal_ helper trait like the following:
+
+{% tabs normal-trait class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+trait Both[A] extends Resettable with Growable[A]
+def f(x: Both[String]): Unit
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+trait Both[A] extends Resettable, Growable[A]
+def f(x: Both[String]): Unit
+```
+{% endtab %}
+{% endtabs %}
+
+There is an important difference between the two alternatives of defining `f`: While both allow `f` to be called with instances of `Both`, only the former allows passing instances that are subtypes of `Resettable` and `Growable[String]`, but _not of_ `Both[String]`.
+
+> Note that `&` is _commutative_: `A & B` is the same type as `B & A`.
diff --git a/_overviews/scala3-book/types-introduction.md b/_overviews/scala3-book/types-introduction.md
new file mode 100644
index 0000000000..77a79a0844
--- /dev/null
+++ b/_overviews/scala3-book/types-introduction.md
@@ -0,0 +1,58 @@
+---
+title: Types and the Type System
+type: chapter
+description: This chapter provides an introduction to Scala 3 types and the type system.
+languages: [ru, zh-cn]
+num: 49
+previous-page: fp-summary
+next-page: types-inferred
+---
+
+
+Scala is a unique language in that it’s statically typed, but often _feels_ flexible and dynamic.
+For instance, thanks to type inference you can write code like this without explicitly specifying the variable types:
+
+{% tabs hi %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = 1
+val b = 2.0
+val c = "Hi!"
+```
+{% endtab %}
+{% endtabs %}
+
+That makes the code feel dynamically typed.
+And thanks to new features, like [union types][union-types] in Scala 3, you can also write code like the following that expresses very concisely which values are expected as arguments and which types are returned:
+
+{% tabs union-example %}
+{% tab 'Scala 3 Only' %}
+```scala
+def isTruthy(a: Boolean | Int | String): Boolean = ???
+def dogCatOrWhatever(): Dog | Plant | Car | Sun = ???
+```
+{% endtab %}
+{% endtabs %}
+
+As the example suggests, when using union types, the types don’t have to share a common hierarchy, and you can still accept them as arguments or return them from a method.
+
+If you’re an application developer, you’ll use features like type inference every day and generics every week.
+When you read the Scaladoc for classes and methods, you’ll also need to have some understanding of _variance_.
+Hopefully you’ll see that using types can be relatively simple and also offers a lot of expressive power, flexibility, and control for library developers.
+
+
+## Benefits of types
+
+Statically-typed programming languages offer a number of benefits, including:
+
+- Helping to provide strong IDE support
+- Eliminating many classes of potential errors at compile time
+- Assisting in refactoring
+- Providing strong documentation that cannot be outdated since it is type checked
+
+
+## Introducing features of Scala’s type system
+
+Given that brief introduction, the following sections provide an overview of the features of Scala’s type system.
+
+[union-types]: {% link _overviews/scala3-book/types-union.md %}
diff --git a/_overviews/scala3-book/types-opaque-types.md b/_overviews/scala3-book/types-opaque-types.md
new file mode 100644
index 0000000000..4076749050
--- /dev/null
+++ b/_overviews/scala3-book/types-opaque-types.md
@@ -0,0 +1,148 @@
+---
+title: Opaque Types
+type: section
+description: This section introduces and demonstrates opaque types in Scala 3.
+languages: [ru, zh-cn]
+num: 56
+previous-page: types-variance
+next-page: types-structural
+scala3: true
+versionSpecific: true
+---
+
+_Opaque type aliases_ provide type abstraction without any **overhead**.
+In Scala 2, a similar result could be achieved with [value classes][value-classes].
+
+## Abstraction Overhead
+
+Let us assume we want to define a module that offers arithmetic on numbers, which are represented by their logarithm.
+This can be useful to improve precision when the numerical values involved tend to be very large, or close to zero.
+
+Since it is important to distinguish “regular” double values from numbers stored as their logarithm, we introduce a class `Logarithm`:
+
+```scala
+class Logarithm(protected val underlying: Double):
+ def toDouble: Double = math.exp(underlying)
+ def + (that: Logarithm): Logarithm =
+ // here we use the apply method on the companion
+ Logarithm(this.toDouble + that.toDouble)
+ def * (that: Logarithm): Logarithm =
+ new Logarithm(this.underlying + that.underlying)
+
+object Logarithm:
+ def apply(d: Double): Logarithm = new Logarithm(math.log(d))
+```
+The apply method on the companion object lets us create values of type `Logarithm` which we can use as follows:
+```scala
+val l2 = Logarithm(2.0)
+val l3 = Logarithm(3.0)
+println((l2 * l3).toDouble) // prints 6.0
+println((l2 + l3).toDouble) // prints 4.999...
+```
+While the class `Logarithm` offers a nice abstraction for `Double` values that are stored in this particular logarithmic form, it imposes severe performance overhead: For every single mathematical operation, we need to extract the underlying value and then wrap it again in a new instance of `Logarithm`.
+
+
+## Module Abstractions
+Let us consider another approach to implement the same library.
+This time instead of defining `Logarithm` as a class, we define it using a _type alias_.
+First, we define an abstract interface of our module:
+
+```scala
+trait Logarithms:
+
+ type Logarithm
+
+ // operations on Logarithm
+ def add(x: Logarithm, y: Logarithm): Logarithm
+ def mul(x: Logarithm, y: Logarithm): Logarithm
+
+ // functions to convert between Double and Logarithm
+ def make(d: Double): Logarithm
+ def extract(x: Logarithm): Double
+
+ // extension methods to use `add` and `mul` as "methods" on Logarithm
+ extension (x: Logarithm)
+ def toDouble: Double = extract(x)
+ def + (y: Logarithm): Logarithm = add(x, y)
+ def * (y: Logarithm): Logarithm = mul(x, y)
+```
+Now, let us implement this abstract interface by saying type `Logarithm` is equal to `Double`:
+```scala
+object LogarithmsImpl extends Logarithms:
+
+ type Logarithm = Double
+
+ // operations on Logarithm
+ def add(x: Logarithm, y: Logarithm): Logarithm = make(x.toDouble + y.toDouble)
+ def mul(x: Logarithm, y: Logarithm): Logarithm = x + y
+
+ // functions to convert between Double and Logarithm
+ def make(d: Double): Logarithm = math.log(d)
+ def extract(x: Logarithm): Double = math.exp(x)
+```
+Within the implementation of `LogarithmsImpl`, the equation `Logarithm = Double` allows us to implement the various methods.
+
+#### Leaky Abstractions
+However, this abstraction is slightly leaky.
+We have to make sure to _only_ ever program against the abstract interface `Logarithms` and never directly use `LogarithmsImpl`.
+Directly using `LogarithmsImpl` would make the equality `Logarithm = Double` visible for the user, who might accidentally use a `Double` where a logarithmic double is expected.
+For example:
+
+```scala
+import LogarithmsImpl.*
+val l: Logarithm = make(1.0)
+val d: Double = l // type checks AND leaks the equality!
+```
+
+Having to separate the module into an abstract interface and implementation can be useful, but is also a lot of effort, just to hide the implementation detail of `Logarithm`.
+Programming against the abstract module `Logarithms` can be very tedious and often requires the use of advanced features like path-dependent types, as in the following example:
+
+```scala
+def someComputation(L: Logarithms)(init: L.Logarithm): L.Logarithm = ...
+```
+
+#### Boxing Overhead
+Type abstractions, such as `type Logarithm` [erase](https://www.scala-lang.org/files/archive/spec/2.13/03-types.html#type-erasure) to their bound (which is `Any` in our case).
+That is, although we do not need to manually wrap and unwrap the `Double` value, there will be still some boxing overhead related to boxing the primitive type `Double`.
+
+## Opaque Types
+Instead of manually splitting our `Logarithms` component into an abstract part and into a concrete implementation, we can simply use opaque types in Scala 3 to achieve a similar effect:
+
+```scala
+object Logarithms:
+//vvvvvv this is the important difference!
+ opaque type Logarithm = Double
+
+ object Logarithm:
+ def apply(d: Double): Logarithm = math.log(d)
+
+ extension (x: Logarithm)
+ def toDouble: Double = math.exp(x)
+ def + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y))
+ def * (y: Logarithm): Logarithm = x + y
+```
+The fact that `Logarithm` is the same as `Double` is only known in the scope where `Logarithm` is defined, which in the above example corresponds to the object `Logarithms`.
+The type equality `Logarithm = Double` can be used to implement the methods (like `*` and `toDouble`).
+
+However, outside of the module the type `Logarithm` is completely encapsulated, or “opaque.” To users of `Logarithm` it is not possible to discover that `Logarithm` is actually implemented as a `Double`:
+
+```scala
+import Logarithms.*
+val log2 = Logarithm(2.0)
+val log3 = Logarithm(3.0)
+println((log2 * log3).toDouble) // prints 6.0
+println((log2 + log3).toDouble) // prints 4.999...
+
+val d: Double = log2 // ERROR: Found Logarithm required Double
+```
+
+Even though we abstracted over `Logarithm`, the abstraction comes for free:
+Since there is only one implementation, at runtime there will be _no boxing overhead_ for primitive types like `Double`.
+
+### Summary of Opaque Types
+Opaque types offer a sound abstraction over implementation details, without imposing performance overhead.
+As illustrated above, opaque types are convenient to use, and integrate very well with the [Extension Methods][extension] feature.
+
+
+[extension]: {% link _overviews/scala3-book/ca-extension-methods.md %}
+[value-classes]: {% link _overviews/core/value-classes.md %}
diff --git a/_overviews/scala3-book/types-others.md b/_overviews/scala3-book/types-others.md
new file mode 100644
index 0000000000..9419073f95
--- /dev/null
+++ b/_overviews/scala3-book/types-others.md
@@ -0,0 +1,31 @@
+---
+title: Other Types
+type: section
+description: This section mentions other advanced types in Scala 3.
+languages: [ru, zh-cn]
+num: 59
+previous-page: types-dependent-function
+next-page: ca-contextual-abstractions-intro
+scala3: true
+versionSpecific: true
+---
+
+
+Scala has several other advanced types that are not shown in this book, including:
+
+- Type lambdas
+- Match types
+- Existential types
+- Higher-kinded types
+- Singleton types
+- Refinement types
+- Kind polymorphism
+
+For more details on most of these types, refer to the [Scala 3 Reference documentation][reference].
+For singleton types see the [literal types](https://scala-lang.org/files/archive/spec/3.4/03-types.html#literal-types) section of the Scala 3 spec,
+and for refinement types, see the [refined types](https://scala-lang.org/files/archive/spec/3.4/03-types.html) section.
+
+
+
+
+[reference]: {{ site.scala3ref }}/overview.html
diff --git a/_overviews/scala3-book/types-structural.md b/_overviews/scala3-book/types-structural.md
new file mode 100644
index 0000000000..afa74fe340
--- /dev/null
+++ b/_overviews/scala3-book/types-structural.md
@@ -0,0 +1,109 @@
+---
+title: Structural Types
+type: section
+description: This section introduces and demonstrates structural types in Scala 3.
+languages: [ru, zh-cn]
+num: 57
+previous-page: types-opaque-types
+next-page: types-dependent-function
+scala3: true
+versionSpecific: true
+---
+
+{% comment %}
+NOTE: It would be nice to simplify this more.
+{% endcomment %}
+
+_Scala 2 has a weaker form of structural types based on Java reflection, achieved with `import scala.language.reflectiveCalls`_.
+
+## Introduction
+
+Some use cases, such as modeling database access, are more awkward in statically typed languages than in dynamically typed languages.
+With dynamically typed languages, it’s natural to model a row as a record or object, and to select entries with simple dot notation, e.g. `row.columnName`.
+
+Achieving the same experience in a statically typed language requires defining a class for every possible row arising from database manipulation---including rows arising from joins and projections---and setting up a scheme to map between a row and the class representing it.
+
+This requires a large amount of boilerplate, which leads developers to trade the advantages of static typing for simpler schemes where column names are represented as strings and passed to other operators, e.g. `row.select("columnName")`.
+This approach forgoes the advantages of static typing, and is still not as natural as the dynamically typed version.
+
+Structural types help in situations where you’d like to support simple dot notation in dynamic contexts without losing the advantages of static typing.
+They allow developers to use dot notation and configure how fields and methods should be resolved.
+
+## Example
+
+Here’s an example of a structural type `Person`:
+
+```scala
+class Record(elems: (String, Any)*) extends Selectable:
+ private val fields = elems.toMap
+ def selectDynamic(name: String): Any = fields(name)
+
+type Person = Record {
+ val name: String
+ val age: Int
+}
+```
+
+The `Person` type adds a _refinement_ to its parent type `Record` that defines `name` and `age` fields.
+We say the refinement is _structural_ since `name` and `age` are not defined in the parent type.
+But they exist nevertheless as members of class `Person`.
+For instance, the following program would print `"Emma is 42 years old."`:
+
+```scala
+val person = Record(
+ "name" -> "Emma",
+ "age" -> 42
+).asInstanceOf[Person]
+
+println(s"${person.name} is ${person.age} years old.")
+```
+
+The parent type `Record` in this example is a generic class that can represent arbitrary records in its `elems` argument.
+This argument is a sequence of pairs of labels of type `String` and values of type `Any`.
+When you create a `Person` as a `Record` you have to assert with a typecast that the record defines the right fields of the right types.
+`Record` itself is too weakly typed, so the compiler cannot know this without help from the user.
+In practice, the connection between a structural type and its underlying generic representation would most likely be done by a database layer, and therefore would not be a concern of the end user.
+
+`Record` extends the marker trait `scala.Selectable` and defines a method `selectDynamic`, which maps a field name to its value.
+Selecting a structural type member is done by calling this method.
+The `person.name` and `person.age` selections are translated by the Scala compiler to:
+
+```scala
+person.selectDynamic("name").asInstanceOf[String]
+person.selectDynamic("age").asInstanceOf[Int]
+```
+
+## A second example
+
+To reinforce what you just saw, here’s another structural type named `Book` that represents a book that you might read from a database:
+
+```scala
+type Book = Record {
+ val title: String
+ val author: String
+ val year: Int
+ val rating: Double
+}
+```
+
+As with `Person`, this is how you create a `Book` instance:
+
+```scala
+val book = Record(
+ "title" -> "The Catcher in the Rye",
+ "author" -> "J. D. Salinger",
+ "year" -> 1951,
+ "rating" -> 4.5
+).asInstanceOf[Book]
+```
+
+## Selectable class
+
+Besides `selectDynamic`, a `Selectable` class sometimes also defines a method `applyDynamic`.
+This can then be used to translate function calls of structural members.
+So, if `a` is an instance of `Selectable`, a structural call like `a.f(b, c)` translates to:
+
+```scala
+a.applyDynamic("f")(b, c)
+```
+
diff --git a/_overviews/scala3-book/types-union.md b/_overviews/scala3-book/types-union.md
new file mode 100644
index 0000000000..e685646608
--- /dev/null
+++ b/_overviews/scala3-book/types-union.md
@@ -0,0 +1,95 @@
+---
+title: Union Types
+type: section
+description: This section introduces and demonstrates union types in Scala 3.
+languages: [ru, zh-cn]
+num: 53
+previous-page: types-intersection
+next-page: types-adts-gadts
+scala3: true
+versionSpecific: true
+---
+
+Used on types, the `|` operator creates a so-called _union type_.
+The type `A | B` represents values that are **either** of the type `A` **or** of the type `B`.
+
+In the following example, the `help` method accepts a parameter named `id` of the union type `Username | Password`, that can be either a `Username` or a `Password`:
+
+```scala
+case class Username(name: String)
+case class Password(hash: Hash)
+
+def help(id: Username | Password) =
+ val user = id match
+ case Username(name) => lookupName(name)
+ case Password(hash) => lookupPassword(hash)
+ // more code here ...
+```
+We implement the method `help` by distinguishing between the two alternatives using pattern matching.
+
+This code is a flexible and type-safe solution.
+If you attempt to pass in a type other than a `Username` or `Password`, the compiler flags it as an error:
+
+```scala
+help("hi") // error: Found: ("hi" : String)
+ // Required: Username | Password
+```
+
+You’ll also get an error if you attempt to add a `case` to the `match` expression that doesn’t match the `Username` or `Password` types:
+
+```scala
+case 1.0 => ??? // ERROR: this line won’t compile
+```
+
+### Alternative to Union Types
+As shown, union types can be used to represent alternatives of several different types, without requiring those types to be part of a custom-crafted class hierarchy, or requiring explicit wrapping.
+
+#### Pre-planning the Class Hierarchy
+Without union types, it would require pre-planning of the class hierarchy, like the following example illustrates:
+
+```scala
+trait UsernameOrPassword
+case class Username(name: String) extends UsernameOrPassword
+case class Password(hash: Hash) extends UsernameOrPassword
+def help(id: UsernameOrPassword) = ...
+```
+
+Pre-planning does not scale very well since, for example, requirements of API users might not be foreseeable.
+Additionally, cluttering the type hierarchy with marker traits like `UsernameOrPassword` also makes the code more difficult to read.
+
+#### Tagged Unions
+Another alternative is to define a separate enumeration type like:
+
+```scala
+enum UsernameOrPassword:
+ case IsUsername(u: Username)
+ case IsPassword(p: Password)
+```
+The enumeration `UsernameOrPassword` represents a _tagged_ union of `Username` and `Password`.
+However, this way of modeling the union requires _explicit wrapping and unwrapping_ and, for instance, `Username` is **not** a subtype of `UsernameOrPassword`.
+
+### Inference of Union Types
+The compiler assigns a union type to an expression _only if_ such a type is explicitly given.
+For instance, given these values:
+
+```scala
+val name = Username("Eve") // name: Username = Username(Eve)
+val password = Password(123) // password: Password = Password(123)
+```
+
+This REPL example shows how a union type can be used when binding a variable to the result of an `if`/`else` expression:
+
+````
+scala> val a = if true then name else password
+val a: Object = Username(Eve)
+
+scala> val b: Password | Username = if true then name else password
+val b: Password | Username = Username(Eve)
+````
+
+The type of `a` is `Object`, which is a supertype of `Username` and `Password`, but not the *least* supertype, `Password | Username`.
+If you want the least supertype you have to give it explicitly, as is done for `b`.
+
+> Union types are duals of intersection types.
+> And like `&` with intersection types, `|` is also commutative: `A | B` is the same type as `B | A`.
+
diff --git a/_overviews/scala3-book/types-variance.md b/_overviews/scala3-book/types-variance.md
new file mode 100644
index 0000000000..f2b8e3d931
--- /dev/null
+++ b/_overviews/scala3-book/types-variance.md
@@ -0,0 +1,235 @@
+---
+title: Variance
+type: section
+description: This section introduces and demonstrates variance in Scala 3.
+languages: [ru, zh-cn]
+num: 55
+previous-page: types-adts-gadts
+next-page: types-opaque-types
+---
+
+Type parameter _variance_ controls the subtyping of parameterized types (like classes or traits).
+
+To explain variance, let us assume the following type definitions:
+
+{% tabs types-variance-1 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+trait Item { def productNumber: String }
+trait Buyable extends Item { def price: Int }
+trait Book extends Buyable { def isbn: String }
+
+```
+{% endtab %}
+{% endtabs %}
+
+Let us also assume the following parameterized types:
+
+{% tabs types-variance-2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=types-variance-2 %}
+```scala
+// an example of an invariant type
+trait Pipeline[T] {
+ def process(t: T): T
+}
+
+// an example of a covariant type
+trait Producer[+T] {
+ def make: T
+}
+
+// an example of a contravariant type
+trait Consumer[-T] {
+ def take(t: T): Unit
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=types-variance-2 %}
+```scala
+// an example of an invariant type
+trait Pipeline[T]:
+ def process(t: T): T
+
+// an example of a covariant type
+trait Producer[+T]:
+ def make: T
+
+// an example of a contravariant type
+trait Consumer[-T]:
+ def take(t: T): Unit
+```
+{% endtab %}
+{% endtabs %}
+
+In general there are three modes of variance:
+
+- **invariant**---the default, written like `Pipeline[T]`
+- **covariant**---annotated with a `+`, such as `Producer[+T]`
+- **contravariant**---annotated with a `-`, like in `Consumer[-T]`
+
+We will now go into detail on what this annotation means and why we use it.
+
+### Invariant Types
+By default, types like `Pipeline` are invariant in their type argument (`T` in this case).
+This means that types like `Pipeline[Item]`, `Pipeline[Buyable]`, and `Pipeline[Book]` are in _no subtyping relationship_ to each other.
+
+And rightfully so! Assume the following method that consumes two values of type `Pipeline[Buyable]`, and passes its argument `b` to one of them, based on the price:
+
+{% tabs types-variance-3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=types-variance-3 %}
+```scala
+def oneOf(
+ p1: Pipeline[Buyable],
+ p2: Pipeline[Buyable],
+ b: Buyable
+): Buyable = {
+ val b1 = p1.process(b)
+ val b2 = p2.process(b)
+ if (b1.price < b2.price) b1 else b2
+ }
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=types-variance-3 %}
+```scala
+def oneOf(
+ p1: Pipeline[Buyable],
+ p2: Pipeline[Buyable],
+ b: Buyable
+): Buyable =
+ val b1 = p1.process(b)
+ val b2 = p2.process(b)
+ if b1.price < b2.price then b1 else b2
+```
+{% endtab %}
+{% endtabs %}
+
+Now, recall that we have the following _subtyping relationship_ between our types:
+
+{% tabs types-variance-4 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+Book <: Buyable <: Item
+```
+{% endtab %}
+{% endtabs %}
+
+We cannot pass a `Pipeline[Book]` to the method `oneOf` because in its implementation, we call `p1` and `p2` with a value of type `Buyable`.
+A `Pipeline[Book]` expects a `Book`, which can potentially cause a runtime error.
+
+We cannot pass a `Pipeline[Item]` because calling `process` on it only promises to return an `Item`; however, we are supposed to return a `Buyable`.
+
+#### Why Invariant?
+In fact, type `Pipeline` needs to be invariant since it uses its type parameter `T` _both_ as an argument _and_ as a return type.
+For the same reason, some types in the Scala collection library---like `Array` or `Set`---are also _invariant_.
+
+### Covariant Types
+In contrast to `Pipeline`, which is invariant, the type `Producer` is marked as **covariant** by prefixing the type parameter with a `+`.
+This is valid, since the type parameter is only used in a _return position_.
+
+Marking it as covariant means that we can pass (or return) a `Producer[Book]` where a `Producer[Buyable]` is expected.
+And in fact, this is sound. The type of `Producer[Buyable].make` only promises to _return_ a `Buyable`.
+As a caller of `make`, we will be happy to also accept a `Book`, which is a subtype of `Buyable`---that is, it is _at least_ a `Buyable`.
+
+This is illustrated by the following example, where the function `makeTwo` expects a `Producer[Buyable]`:
+
+{% tabs types-variance-5 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def makeTwo(p: Producer[Buyable]): Int =
+ p.make.price + p.make.price
+```
+{% endtab %}
+{% endtabs %}
+
+It is perfectly fine to pass a producer for books:
+
+{% tabs types-variance-6 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val bookProducer: Producer[Book] = ???
+makeTwo(bookProducer)
+```
+{% endtab %}
+{% endtabs %}
+
+The call to `price` within `makeTwo` is still valid also for books.
+
+#### Covariant Types for Immutable Containers
+You will encounter covariant types a lot when dealing with immutable containers, like those that can be found in the standard library (such as `List`, `Seq`, `Vector`, etc.).
+
+For example, `List` and `Vector` are approximately defined as:
+
+{% tabs types-variance-7 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+class List[+A] ...
+class Vector[+A] ...
+```
+{% endtab %}
+{% endtabs %}
+
+This way, you can use a `List[Book]` where a `List[Buyable]` is expected.
+This also intuitively makes sense: If you are expecting a collection of things that can be bought, it should be fine to give you a collection of books.
+They have an additional ISBN method in our example, but you are free to ignore these additional capabilities.
+
+### Contravariant Types
+In contrast to the type `Producer`, which is marked as covariant, the type `Consumer` is marked as **contravariant** by prefixing the type parameter with a `-`.
+This is valid, since the type parameter is only used in an _argument position_.
+
+Marking it as contravariant means that we can pass (or return) a `Consumer[Item]` where a `Consumer[Buyable]` is expected.
+That is, we have the subtyping relationship `Consumer[Item] <: Consumer[Buyable]`.
+Remember, for type `Producer`, it was the other way around, and we had `Producer[Buyable] <: Producer[Item]`.
+
+And in fact, this is sound. The method `Consumer[Item].take` accepts an `Item`.
+As a caller of `take`, we can also supply a `Buyable`, which will be happily accepted by the `Consumer[Item]` since `Buyable` is a subtype of `Item`---that is, it is _at least_ an `Item`.
+
+#### Contravariant Types for Consumers
+Contravariant types are much less common than covariant types.
+As in our example, you can think of them as “consumers.” The most important type that you might come across that is marked contravariant is the one of functions:
+
+{% tabs types-variance-8 class=tabs-scala-version %}
+{% tab 'Scala 2' for=types-variance-8 %}
+```scala
+trait Function[-A, +B] {
+ def apply(a: A): B
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=types-variance-8 %}
+```scala
+trait Function[-A, +B]:
+ def apply(a: A): B
+```
+{% endtab %}
+{% endtabs %}
+
+Its argument type `A` is marked as contravariant `A`---it consumes values of type `A`.
+In contrast, its result type `B` is marked as covariant---it produces values of type `B`.
+
+Here are some examples that illustrate the subtyping relationships induced by variance annotations on functions:
+
+{% tabs types-variance-9 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val f: Function[Buyable, Buyable] = b => b
+
+// OK to return a Buyable where a Item is expected
+val g: Function[Buyable, Item] = f
+
+// OK to provide a Book where a Buyable is expected
+val h: Function[Book, Buyable] = f
+```
+{% endtab %}
+{% endtabs %}
+
+## Summary
+In this section, we have encountered three different kinds of variance:
+
+- **Producers** are typically covariant, and mark their type parameter with `+`.
+ This also holds for immutable collections.
+- **Consumers** are typically contravariant, and mark their type parameter with `-`.
+- Types that are **both** producers and consumers have to be invariant, and do not require any marking on their type parameter.
+ Mutable collections like `Array` fall into this category.
diff --git a/_overviews/scala3-book/where-next.md b/_overviews/scala3-book/where-next.md
new file mode 100644
index 0000000000..8eed7a163f
--- /dev/null
+++ b/_overviews/scala3-book/where-next.md
@@ -0,0 +1,16 @@
+---
+title: Where To Go Next
+type: chapter
+description: Where to go next after reading the Scala Book
+languages: [zh-cn]
+num: 77
+previous-page: scala-for-python-devs
+next-page:
+---
+
+We hope you enjoyed this introduction to the Scala programming language, and we also hope we were able to share some of the beauty of the language.
+
+As you continue working with Scala, you can find many more details at the
+[Guides and Overviews section][overviews] of our website.
+
+[overviews]: {% link _overviews/index.md %}
diff --git a/_overviews/scala3-book/why-scala-3.md b/_overviews/scala3-book/why-scala-3.md
new file mode 100644
index 0000000000..639c04691e
--- /dev/null
+++ b/_overviews/scala3-book/why-scala-3.md
@@ -0,0 +1,501 @@
+---
+title: Why Scala 3?
+type: chapter
+description: This page describes the benefits of the Scala 3 programming language.
+languages: [ru, zh-cn]
+num: 3
+previous-page: scala-features
+next-page: taste-intro
+---
+
+{% comment %}
+TODO: Is “Scala 3 Benefits” a better title?
+NOTE: Could mention “grammar” as a way of showing that Scala isn’t a large language; see this slide: https://www.slideshare.net/Odersky/preparing-for-scala-3#13
+{% endcomment %}
+
+There are many benefits to using Scala, and Scala 3 in particular.
+It’s hard to list every benefit of Scala, but a “Top Ten” list might look like this:
+
+1. Scala embraces a fusion of functional programming (FP) and object-oriented programming (OOP)
+2. Scala is statically typed, but often feels like a dynamically typed language
+3. Scala’s syntax is concise, but still readable; it’s often referred to as _expressive_
+4. _Implicits_ in Scala 2 were a defining feature, and they have been improved and simplified in Scala 3
+5. Scala integrates seamlessly with Java, so you can create projects with mixed Scala and Java code, and Scala code easily uses the thousands of existing Java libraries
+6. Scala can be used on the server, and also in the browser with [Scala.js](https://www.scala-js.org)
+7. The Scala standard library has dozens of pre-built, functional methods to save you time, and greatly reduce the need to write custom `for` loops and algorithms
+8. “Best practices” are built into Scala, which favors immutability, anonymous functions, higher-order functions, pattern matching, classes that cannot be extended by default, and more
+9. The Scala ecosystem offers the most modern FP libraries in the world
+10. Strong type system
+
+## 1) FP/OOP fusion
+
+More than any other language, Scala supports a fusion of the FP and OOP paradigms.
+As Martin Odersky has stated, the essence of Scala is a fusion of functional and object-oriented programming in a typed setting, with:
+
+- Functions for the logic, and
+- Objects for the modularity
+
+Possibly some of the best examples of modularity are the classes in the standard library.
+For instance, a `List` is defined as a class---technically it’s an abstract class---and a new instance is created like this:
+
+{% tabs list %}
+{% tab 'Scala 2 and 3' for=list %}
+```scala
+val x = List(1, 2, 3)
+```
+{% endtab %}
+{% endtabs %}
+
+However, what appears to the programmer to be a simple `List` is actually built from a combination of several specialized types, including traits named `Iterable`, `Seq`, and `LinearSeq`.
+Those types are similarly composed of other small, modular units of code.
+
+In addition to building a type like `List` from a series of modular traits, the `List` API also consists of dozens of other methods, many of which are higher-order functions:
+
+{% tabs list-methods %}
+{% tab 'Scala 2 and 3' for=list-methods %}
+```scala
+val xs = List(1, 2, 3, 4, 5)
+
+xs.map(_ + 1) // List(2, 3, 4, 5, 6)
+xs.filter(_ < 3) // List(1, 2)
+xs.find(_ > 3) // Some(4)
+xs.takeWhile(_ < 3) // List(1, 2)
+```
+{% endtab %}
+{% endtabs %}
+
+In those examples, the values in the list can’t be modified.
+The `List` class is immutable, so all of those methods return new values, as shown by the data in each comment.
+
+## 2) A dynamic feel
+
+Scala’s _type inference_ often makes the language feel dynamically typed, even though it’s statically typed.
+This is true with variable declaration:
+
+{% tabs dynamic %}
+{% tab 'Scala 2 and 3' for=dynamic %}
+```scala
+val a = 1
+val b = "Hello, world"
+val c = List(1,2,3,4,5)
+val stuff = ("fish", 42, 1_234.5)
+```
+{% endtab %}
+{% endtabs %}
+
+It’s also true when passing anonymous functions to higher-order functions:
+
+{% tabs dynamic-hof %}
+{% tab 'Scala 2 and 3' for=dynamic-hof %}
+```scala
+list.filter(_ < 4)
+list.map(_ * 2)
+list.filter(_ < 4)
+ .map(_ * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+and when defining methods:
+
+{% tabs dynamic-method %}
+{% tab 'Scala 2 and 3' for=dynamic-method %}
+```scala
+def add(a: Int, b: Int) = a + b
+```
+{% endtab %}
+{% endtabs %}
+
+This is more true than ever in Scala 3, such as when using [union types][union-types]:
+
+{% tabs union %}
+{% tab 'Scala 3 Only' for=union %}
+```scala
+// union type parameter
+def help(id: Username | Password) =
+ val user = id match
+ case Username(name) => lookupName(name)
+ case Password(hash) => lookupPassword(hash)
+ // more code here ...
+
+// union type value
+val b: Password | Username = if (true) name else password
+```
+{% endtab %}
+{% endtabs %}
+
+## 3) Concise syntax
+
+Scala is a low ceremony, “concise but still readable” language. For instance, variable declaration is concise:
+
+{% tabs concise %}
+{% tab 'Scala 2 and 3' for=concise %}
+```scala
+val a = 1
+val b = "Hello, world"
+val c = List(1,2,3)
+```
+{% endtab %}
+{% endtabs %}
+
+Creating types like traits, classes, and enumerations are concise:
+
+{% tabs enum %}
+{% tab 'Scala 3 Only' for=enum %}
+```scala
+trait Tail:
+ def wagTail(): Unit
+ def stopTail(): Unit
+
+enum Topping:
+ case Cheese, Pepperoni, Sausage, Mushrooms, Onions
+
+class Dog extends Animal, Tail, Legs, RubberyNose
+
+case class Person(
+ firstName: String,
+ lastName: String,
+ age: Int
+)
+```
+{% endtab %}
+{% endtabs %}
+
+Higher-order functions are concise:
+
+{% tabs list-hof %}
+{% tab 'Scala 2 and 3' for=list-hof %}
+
+```scala
+list.filter(_ < 4)
+list.map(_ * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+All of these expressions and many more are concise, and still very readable: what we call _expressive_.
+
+## 4) Implicits, simplified
+
+Implicits in Scala 2 were a major distinguishing design feature.
+They represented _the_ fundamental way to abstract over context, with a unified paradigm that served a great variety of use cases, among them:
+
+- Implementing [type classes]({% link _overviews/scala3-book/ca-type-classes.md %})
+- Establishing context
+- Dependency injection
+- Expressing capabilities
+
+Since then, other languages have adopted similar concepts, all of which are variants of the core idea of _term inference_: Given a type, the compiler synthesizes a “canonical” term that has that type.
+
+While implicits were a defining feature in Scala 2, their design has been greatly improved in Scala 3:
+
+- There’s a single way to define “given” values
+- There’s a single way to introduce implicit parameters and arguments
+- There’s a separate way to import givens that does not allow them to hide in a sea of normal imports
+- There’s a single way to define an implicit conversion, which is clearly marked as such, and does not require special syntax
+
+Benefits of these changes include:
+
+- The new design avoids feature interactions and makes the language more consistent
+- It makes implicits easier to learn and harder to abuse
+- It greatly improves the clarity of the 95% of Scala programs that use implicits
+- It has the potential to enable term inference in a principled way that’s also accessible and friendly
+
+These capabilities are described in detail in other sections, so see the [Contextual Abstraction introduction][contextual], and the section on [`given` and `using` clauses][given] for more details.
+
+## 5) Seamless Java integration
+
+Scala/Java interaction is seamless in many ways.
+For instance:
+
+- You can use all of the thousands of Java libraries that are available in your Scala projects
+- A Scala `String` is essentially a Java `String`, with additional capabilities added to it
+- Scala seamlessly uses the date/time classes in the Java *java.time._* package
+
+You can also use Java collections classes in Scala, and to give them more functionality, Scala includes methods so you can transform them into Scala collections.
+
+While almost every interaction is seamless, the [“Interacting with Java” chapter][java] demonstrates how to use some features together better, including how to use:
+
+- Java collections in Scala
+- Java `Optional` in Scala
+- Java interfaces in Scala
+- Scala collections in Java
+- Scala `Option` in Java
+- Scala traits in Java
+- Scala methods that throw exceptions in Java code
+- Scala varargs parameters in Java
+
+See that chapter for more details on these features.
+
+## 6) Client & server
+
+Scala can be used on the server side with terrific frameworks:
+
+- The [Play Framework](https://www.playframework.com) lets you build highly scalable server-side applications and microservices
+- [Akka Actors](https://akka.io) let you use the actor model to greatly simplify distributed and concurrent software applications
+
+Scala can also be used in the browser with the [Scala.js project](https://www.scala-js.org), which is a type-safe replacement for JavaScript.
+The Scala.js ecosystem [has dozens of libraries](https://www.scala-js.org/libraries) to let you use React, Angular, jQuery, and many other JavaScript and Scala libraries in the browser.
+
+In addition to those tools, the [Scala Native](https://github.com/scala-native/scala-native) project “is an optimizing ahead-of-time compiler and lightweight managed runtime designed specifically for Scala.” It lets you build “systems” style binary executable applications with plain Scala code, and also lets you use lower-level primitives.
+
+## 7) Standard library methods
+
+You will rarely ever need to write a custom `for` loop again, because the dozens of pre-built functional methods in the Scala standard library will both save you time, and help make code more consistent across different applications.
+
+The following examples show some of the built-in collections methods, and there are many in addition to these.
+While these all use the `List` class, the same methods work with other collections classes like `Seq`, `Vector`, `LazyList`, `Set`, `Map`, `Array`, and `ArrayBuffer`.
+
+Here are some examples:
+
+{% tabs list-more %}
+{% tab 'Scala 2 and 3' for=list-more %}
+```scala
+List.range(1, 3) // List(1, 2)
+List.range(start = 1, end = 6, step = 2) // List(1, 3, 5)
+List.fill(3)("foo") // List(foo, foo, foo)
+List.tabulate(3)(n => n * n) // List(0, 1, 4)
+List.tabulate(4)(n => n * n) // List(0, 1, 4, 9)
+
+val a = List(10, 20, 30, 40, 10) // List(10, 20, 30, 40, 10)
+a.distinct // List(10, 20, 30, 40)
+a.drop(2) // List(30, 40, 10)
+a.dropRight(2) // List(10, 20, 30)
+a.dropWhile(_ < 25) // List(30, 40, 10)
+a.filter(_ < 25) // List(10, 20, 10)
+a.filter(_ > 100) // List()
+a.find(_ > 20) // Some(30)
+a.head // 10
+a.headOption // Some(10)
+a.init // List(10, 20, 30, 40)
+a.intersect(List(19,20,21)) // List(20)
+a.last // 10
+a.lastOption // Some(10)
+a.map(_ * 2) // List(20, 40, 60, 80, 20)
+a.slice(2, 4) // List(30, 40)
+a.tail // List(20, 30, 40, 10)
+a.take(3) // List(10, 20, 30)
+a.takeRight(2) // List(40, 10)
+a.takeWhile(_ < 30) // List(10, 20)
+a.filter(_ < 30).map(_ * 10) // List(100, 200, 100)
+
+val fruits = List("apple", "pear")
+fruits.map(_.toUpperCase) // List(APPLE, PEAR)
+fruits.flatMap(_.toUpperCase) // List(A, P, P, L, E, P, E, A, R)
+
+val nums = List(10, 5, 8, 1, 7)
+nums.sorted // List(1, 5, 7, 8, 10)
+nums.sortWith(_ < _) // List(1, 5, 7, 8, 10)
+nums.sortWith(_ > _) // List(10, 8, 7, 5, 1)
+```
+{% endtab %}
+{% endtabs %}
+
+## 8) Built-in best practices
+
+Scala idioms encourage best practices in many ways.
+For immutability, you’re encouraged to create immutable `val` declarations:
+
+{% tabs val %}
+{% tab 'Scala 2 and 3' for=val %}
+```scala
+val a = 1 // immutable variable
+```
+{% endtab %}
+{% endtabs %}
+
+You’re also encouraged to use immutable collections classes like `List` and `Map`:
+
+{% tabs list-map %}
+{% tab 'Scala 2 and 3' for=list-map %}
+```scala
+val b = List(1,2,3) // List is immutable
+val c = Map(1 -> "one") // Map is immutable
+```
+{% endtab %}
+{% endtabs %}
+
+Case classes are primarily intended for use in [domain modeling]({% link _overviews/scala3-book/domain-modeling-intro.md %}), and their parameters are immutable:
+
+{% tabs case-class %}
+{% tab 'Scala 2 and 3' for=case-class %}
+```scala
+case class Person(name: String)
+val p = Person("Michael Scott")
+p.name // Michael Scott
+p.name = "Joe" // compiler error (reassignment to val name)
+```
+{% endtab %}
+{% endtabs %}
+
+As shown in the previous section, Scala collections classes support higher-order functions, and you can pass methods (not shown) and anonymous functions into them:
+
+{% tabs higher-order %}
+{% tab 'Scala 2 and 3' for=higher-order %}
+```scala
+a.dropWhile(_ < 25)
+a.filter(_ < 25)
+a.takeWhile(_ < 30)
+a.filter(_ < 30).map(_ * 10)
+nums.sortWith(_ < _)
+nums.sortWith(_ > _)
+```
+{% endtab %}
+{% endtabs %}
+
+`match` expressions let you use pattern matching, and they truly are _expressions_ that return values:
+
+{% tabs match class=tabs-scala-version %}
+{% tab 'Scala 2' for=match %}
+```scala
+val numAsString = i match {
+ case 1 | 3 | 5 | 7 | 9 => "odd"
+ case 2 | 4 | 6 | 8 | 10 => "even"
+ case _ => "too big"
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=match %}
+```scala
+val numAsString = i match
+ case 1 | 3 | 5 | 7 | 9 => "odd"
+ case 2 | 4 | 6 | 8 | 10 => "even"
+ case _ => "too big"
+```
+{% endtab %}
+{% endtabs %}
+
+Because they can return values, they’re often used as the body of a method:
+
+{% tabs match-body class=tabs-scala-version %}
+{% tab 'Scala 2' for=match-body %}
+```scala
+def isTruthy(a: Matchable) = a match {
+ case 0 | "" => false
+ case _ => true
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=match-body %}
+```scala
+def isTruthy(a: Matchable) = a match
+ case 0 | "" => false
+ case _ => true
+```
+{% endtab %}
+{% endtabs %}
+
+## 9) Ecosystem libraries
+
+Scala libraries for functional programming like [Cats](https://typelevel.org/cats) and [Zio](https://zio.dev) are leading-edge libraries in the FP community.
+All of the buzzwords like high-performance, type safe, concurrent, asynchronous, resource-safe, testable, functional, modular, binary-compatible, efficient, effects/effectful, and more, can be said about these libraries.
+
+We could list hundreds of libraries here, but fortunately they’re all listed in another location: For those details, see the [“Awesome Scala” list](https://github.com/lauris/awesome-scala).
+
+## 10) Strong type system
+
+Scala has a strong type system, and it’s been improved even more in Scala 3.
+Scala 3’s goals were defined early on, and those related to the type system include:
+
+- Simplification
+- Eliminate inconsistencies
+- Safety
+- Ergonomics
+- Performance
+
+_Simplification_ comes about through dozens of changed and dropped features.
+For instance, the changes from the overloaded `implicit` keyword in Scala 2 to the terms `given` and `using` in Scala 3 make the language more clear, especially for beginning developers.
+
+_Eliminating inconsistencies_ is related to the dozens of [dropped features][dropped], [changed features][changed], and [added features][added] in Scala 3.
+Some of the most important features in this category are:
+
+- Intersection types
+- Union types
+- Implicit function types
+- Dependent function types
+- Trait parameters
+- Generic tuples
+
+{% comment %}
+A list of types from the Dotty documentation:
+
+- Inferred types
+- Generics
+- Intersection types
+- Union types
+- Structural types
+- Dependent function types
+- Type classes
+- Opaque types
+- Variance
+- Algebraic Data Types
+- Wildcard arguments in types: ? replacing _
+- Type lambdas
+- Match types
+- Existential types
+- Higher-kinded types
+- Singleton types
+- Refinement types
+- Kind polymorphism
+- Abstract type members and path-dependent types
+- Dependent function types
+- Bounds
+{% endcomment %}
+
+_Safety_ is related to several new and changed features:
+
+- Multiversal equality
+- Restricting implicit conversions
+- Null safety
+- Safe initialization
+
+Good examples of _ergonomics_ are enumerations and extension methods, which have been added to Scala 3 in a very readable manner:
+
+{% tabs extension %}
+{% tab 'Scala 3 Only' for=extension %}
+```scala
+// enumeration
+enum Color:
+ case Red, Green, Blue
+
+// extension methods
+extension (c: Circle)
+ def circumference: Double = c.radius * math.Pi * 2
+ def diameter: Double = c.radius * 2
+ def area: Double = math.Pi * c.radius * c.radius
+```
+{% endtab %}
+{% endtabs %}
+
+_Performance_ relates to several areas.
+One of those is [opaque types][opaque-types].
+In Scala 2 there were several attempts to create solutions to keep with the Domain-driven design (DDD) practice of giving values more meaningful types.
+These attempts included:
+
+- Type aliases
+- Value classes
+- Case classes
+
+Unfortunately all of these approaches had weaknesses, as described in the [_Opaque Types_ SIP](https://docs.scala-lang.org/sips/opaque-types.html).
+Conversely, the goal of opaque types, as described in that SIP, is that “operations on these wrapper types must not create any extra overhead at runtime while still providing a type safe use at compile time.”
+
+For more type system details, see the [Reference documentation][reference].
+
+## Other great features
+
+Scala has many great features, and choosing a Top 10 list can be subjective.
+Several surveys have shown that different groups of developers love different features.
+Hopefully you’ll discover more great Scala features as you use the language.
+
+[java]: {% link _overviews/scala3-book/interacting-with-java.md %}
+[given]: {% link _overviews/scala3-book/ca-context-parameters.md %}
+[contextual]: {% link _overviews/scala3-book/ca-contextual-abstractions-intro.md %}
+[reference]: {{ site.scala3ref }}
+[dropped]: {{ site.scala3ref }}/dropped-features
+[changed]: {{ site.scala3ref }}/changed-features
+[added]:{{ site.scala3ref }}/other-new-features
+
+[union-types]: {% link _overviews/scala3-book/types-union.md %}
+[opaque-types]: {% link _overviews/scala3-book/types-opaque-types.md %}
diff --git a/_overviews/scala3-contribution/arch-context.md b/_overviews/scala3-contribution/arch-context.md
new file mode 100644
index 0000000000..cbf342703f
--- /dev/null
+++ b/_overviews/scala3-contribution/arch-context.md
@@ -0,0 +1,5 @@
+---
+title: Contexts
+description: This page describes symbols in the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/architecture/context.html
+---
\ No newline at end of file
diff --git a/_overviews/scala3-contribution/arch-intro.md b/_overviews/scala3-contribution/arch-intro.md
new file mode 100644
index 0000000000..8b306a4e5c
--- /dev/null
+++ b/_overviews/scala3-contribution/arch-intro.md
@@ -0,0 +1,5 @@
+---
+title: High Level Architecture
+description: This page introduces the high level architecture of the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/architecture/index.html
+---
\ No newline at end of file
diff --git a/_overviews/scala3-contribution/arch-lifecycle.md b/_overviews/scala3-contribution/arch-lifecycle.md
new file mode 100644
index 0000000000..917e5a7824
--- /dev/null
+++ b/_overviews/scala3-contribution/arch-lifecycle.md
@@ -0,0 +1,5 @@
+---
+title: Compiler Overview
+description: This page describes the lifecycle for the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/architecture/lifecycle.html
+---
\ No newline at end of file
diff --git a/_overviews/scala3-contribution/arch-phases.md b/_overviews/scala3-contribution/arch-phases.md
new file mode 100644
index 0000000000..25db11e6a3
--- /dev/null
+++ b/_overviews/scala3-contribution/arch-phases.md
@@ -0,0 +1,5 @@
+---
+title: Compiler Phases
+description: This page describes the phases for the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/architecture/phases.html
+---
\ No newline at end of file
diff --git a/_overviews/scala3-contribution/arch-symbols.md b/_overviews/scala3-contribution/arch-symbols.md
new file mode 100644
index 0000000000..5ec3408b51
--- /dev/null
+++ b/_overviews/scala3-contribution/arch-symbols.md
@@ -0,0 +1,5 @@
+---
+title: Symbols
+description: This page describes symbols in the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/architecture/symbols.html
+---
\ No newline at end of file
diff --git a/_overviews/scala3-contribution/arch-time.md b/_overviews/scala3-contribution/arch-time.md
new file mode 100644
index 0000000000..a56fed21a5
--- /dev/null
+++ b/_overviews/scala3-contribution/arch-time.md
@@ -0,0 +1,5 @@
+---
+title: Time in the Compiler
+description: This page describes the concepts of time in the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/architecture/time.html
+---
\ No newline at end of file
diff --git a/_overviews/scala3-contribution/arch-types.md b/_overviews/scala3-contribution/arch-types.md
new file mode 100644
index 0000000000..cadcee16f2
--- /dev/null
+++ b/_overviews/scala3-contribution/arch-types.md
@@ -0,0 +1,5 @@
+---
+title: Compiler Types
+description: This page discusses the representation of types in the compiler
+redirect_to: https://dotty.epfl.ch/docs/contributing/architecture/types.html
+---
\ No newline at end of file
diff --git a/_overviews/scala3-contribution/contribution-intro.md b/_overviews/scala3-contribution/contribution-intro.md
new file mode 100644
index 0000000000..1708decf17
--- /dev/null
+++ b/_overviews/scala3-contribution/contribution-intro.md
@@ -0,0 +1,5 @@
+---
+title: Contribute to Scala 3
+description: This page describes the format of the contribution guide for the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/index.html
+---
diff --git a/_overviews/scala3-contribution/procedures-areas.md b/_overviews/scala3-contribution/procedures-areas.md
new file mode 100644
index 0000000000..74d593b4ac
--- /dev/null
+++ b/_overviews/scala3-contribution/procedures-areas.md
@@ -0,0 +1,5 @@
+---
+title: Common Issue Locations
+description: This page describes common areas of issues around the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/workflow/areas.html
+---
\ No newline at end of file
diff --git a/_overviews/scala3-contribution/procedures-cheatsheet.md b/_overviews/scala3-contribution/procedures-cheatsheet.md
new file mode 100644
index 0000000000..fdbf2a2435
--- /dev/null
+++ b/_overviews/scala3-contribution/procedures-cheatsheet.md
@@ -0,0 +1,5 @@
+---
+title: Cheatsheets
+description: This page describes a cheatsheet for working with the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/cheatsheet.html
+---
\ No newline at end of file
diff --git a/_overviews/scala3-contribution/procedures-checklist.md b/_overviews/scala3-contribution/procedures-checklist.md
new file mode 100644
index 0000000000..6908332d2d
--- /dev/null
+++ b/_overviews/scala3-contribution/procedures-checklist.md
@@ -0,0 +1,5 @@
+---
+title: Pull Request Checklist
+description: This page describes a checklist before opening a Pull Request to the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/workflow/checklist.html
+---
\ No newline at end of file
diff --git a/_overviews/scala3-contribution/procedures-debugging.md b/_overviews/scala3-contribution/procedures-debugging.md
new file mode 100644
index 0000000000..6fe158614d
--- /dev/null
+++ b/_overviews/scala3-contribution/procedures-debugging.md
@@ -0,0 +1,5 @@
+---
+title: Debugging the Compiler
+description: This page describes navigating around the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/workflow/debugging.html
+---
diff --git a/_overviews/scala3-contribution/procedures-inspection.md b/_overviews/scala3-contribution/procedures-inspection.md
new file mode 100644
index 0000000000..40ec4e2f92
--- /dev/null
+++ b/_overviews/scala3-contribution/procedures-inspection.md
@@ -0,0 +1,5 @@
+---
+title: How to Inspect Values
+description: This page describes inspecting semantic values in the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/workflow/inspection.html
+---
\ No newline at end of file
diff --git a/_overviews/scala3-contribution/procedures-intro.md b/_overviews/scala3-contribution/procedures-intro.md
new file mode 100644
index 0000000000..2cb292caf4
--- /dev/null
+++ b/_overviews/scala3-contribution/procedures-intro.md
@@ -0,0 +1,5 @@
+---
+title: Contributing to Scala 3
+description: This page introduces the compiler procedures for the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/procedures/index.html
+---
\ No newline at end of file
diff --git a/_overviews/scala3-contribution/procedures-navigation.md b/_overviews/scala3-contribution/procedures-navigation.md
new file mode 100644
index 0000000000..a0e869970c
--- /dev/null
+++ b/_overviews/scala3-contribution/procedures-navigation.md
@@ -0,0 +1,5 @@
+---
+title: Finding the Cause of an Issue
+description: This page describes navigating around the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/workflow/cause.html
+---
diff --git a/_overviews/scala3-contribution/procedures-reproduce.md b/_overviews/scala3-contribution/procedures-reproduce.md
new file mode 100644
index 0000000000..aa31ecedde
--- /dev/null
+++ b/_overviews/scala3-contribution/procedures-reproduce.md
@@ -0,0 +1,5 @@
+---
+title: Reproducing an Issue
+description: This page describes reproducing an issue in the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/workflow/reproduce.html
+---
\ No newline at end of file
diff --git a/_overviews/scala3-contribution/procedures-testing.md b/_overviews/scala3-contribution/procedures-testing.md
new file mode 100644
index 0000000000..7c68dc18af
--- /dev/null
+++ b/_overviews/scala3-contribution/procedures-testing.md
@@ -0,0 +1,5 @@
+---
+title: Testing Your Changes
+description: This page describes test procedures in the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/workflow/testing.html
+---
diff --git a/_overviews/scala3-contribution/start-intro.md b/_overviews/scala3-contribution/start-intro.md
new file mode 100644
index 0000000000..48e6100fbd
--- /dev/null
+++ b/_overviews/scala3-contribution/start-intro.md
@@ -0,0 +1,5 @@
+---
+title: Getting Started
+description: This page describes the high level architecture for the Scala 3 compiler.
+redirect_to: https://dotty.epfl.ch/docs/contributing/getting-started.html
+---
diff --git a/_overviews/scala3-macros/best-practices.md b/_overviews/scala3-macros/best-practices.md
new file mode 100644
index 0000000000..1122c98620
--- /dev/null
+++ b/_overviews/scala3-macros/best-practices.md
@@ -0,0 +1,155 @@
+---
+type: chapter
+title: Best Practices
+num: 8
+---
+## Inline
+
+### Be careful when inlining for performance
+To take the most advantage of the JVM JIT optimisations, you want to avoid generating large methods.
+
+
+## Macros
+**Coming soon**
+
+
+## Quoted code
+
+### Keep quotes readable
+* Try to avoid `${...}` with arbitrary expressions inside
+ * Use `$someExpr`
+ * Use `${ someExprFrom('localExpr) }`
+
+To illustrate, consider the following example:
+```scala
+val sc: StringContext = ...
+'{ StringContext(${Varargs(sc.parts.map(Expr(_)))}: _*) }
+```
+Instead, we can write the following:
+
+```scala
+val sc: StringContext = ...
+val partExprs = sc.parts.map(Expr(_))
+val partsExpr = Varargs(partExprs)
+'{ StringContext($partsExpr: _*) }
+```
+The contents of the quote are much more clear in the second example.
+
+### Avoid nested contexts
+
+Consider the following code:
+
+```scala
+val y: Expr[Int] = ...
+def body(x: Expr[Int])(using quotes.Nested) = '{ $x + $y }
+'{ (x: Int) => ${ body('x) } }
+```
+
+Instead, use a normal context and pass all needed expressions.
+This has also the advantage of allowing the function to not be defined locally.
+```scala
+def body(x: Expr[Int], y: Expr[Int])(using Quotes) =
+ '{ $x + $y }
+
+val y: Expr[Int] = ...
+'{ (x: Int) => ${ body('x, y) } }
+```
+
+## Quotes Reflect
+
+For this section, consider the following setup:
+
+```scala
+object Box:
+ sealed trait Base
+ case class Leaf(x: Int) extends Base
+
+// Quotes in contextual scope
+val boxTpe : TypeRepr = TypeRepr.of[Box.type]
+val baseTpe: TypeRepr = TypeRepr.of[Box.Base]
+val baseSym: Symbol = baseTpe.typeSymbol
+val leafTpe: TypeRepr = TypeRepr.of[Box.Leaf]
+val leafSym: Symbol = leafTpe.typeSymbol
+```
+
+### Avoid `Symbol.tree`
+
+On an object `sym: Symbol`, `sym.tree` returns the `Tree` associated with the symbol.
+Be careful when using this method, as the tree for a symbol might not be defined.
+When the code associated with a symbol is defined at a different time than this access, if the `-Yretain-trees` compilation option is not used, then the `tree` of the symbol will not be available.
+Symbols originating from Java code do not have an associated `tree`.
+
+### Obtaining a `TypeRepr` from a `Symbol`
+
+In the previous heading, we saw that `Symbol.tree` should be avoided and that therefore you should not use `sym.tree.tpe` on `sym: Symbol`.
+Thus, to obtain the `TypeRepr` corresponding to a `Symbol`, it is recommended to use `tpe.memberType` on `tpe: TypeRepr` objects.
+
+We can obtain the `TypeRepr` of `Leaf` in two ways:
+ 1. `TypeRepr.of[Box.Leaf]`
+ 2. `boxTpe.memberType(leafSym)`
+(In other words, we request the `TypeRepr` of the member of `Box` whose symbol is equal to the symbol of `leafSym`.)
+
+While the two approaches are equivalent, the first is only possible if you already know that you are looking for the type `Box.Leaf`.
+The second approach allows you to explore an unknown API.
+
+### Use `Symbol`s to compare definitions
+
+Read more about Symbols [here][symbol].
+
+Symbols allow you to compare definitions using `==`:
+```scala
+leafSym == baseSym.children.head // Is true
+```
+
+However, `==` on `TypeRepr`s does not produce the same result:
+```scala
+boxTpe.memberType(baseSym.children.head) == leafTpe // Is false
+```
+
+### Obtaining a Symbol for a type
+
+There is a handy shortcut to get the symbol for the definition of `T`.
+Instead of
+
+```scala
+TypeTree.of[T].tpe.typeSymbol
+```
+you can use
+
+```scala
+TypeRepr.of[T].typeSymbol
+```
+
+### Pattern match your way into the API
+
+Pattern matching is a very ergonomic approach to the API. Always have a look at
+the `unapply` method defined in `*Module` objects.
+
+### Search the contextual scope in your macros
+
+You can search for given instances using `Implicits.search`.
+
+For example:
+
+```scala
+def summonOrFail[T: Type]: Expr[T] =
+ val tpe = TypeRepr.of[T]
+ Implicits.search(tpe) match
+ case success: ImplicitSearchSuccess =>
+ val implicitTerm = success.tree
+ implicitTerm.asExprOf[T]
+ case failure: ImplicitSearchFailure =>
+ reflect.report.throwError("Could not find an implicit for " + Type.show[T])
+```
+
+If you are writing a macro and prefer to handle `Expr`s, `Expr.summon` is a
+convenient wrapper around `Implicits.search`:
+
+```scala
+def summonOrFail[T: Type]: Expr[T] =
+ Expr.summon[T] match
+ case Some(imp) => imp
+ case None => reflect.report.throwError("Could not find an implicit for " + Type.show[T])
+```
+
+[symbol]: {% link _overviews/scala3-macros/tutorial/reflection.md %}
diff --git a/_overviews/scala3-macros/faq.md b/_overviews/scala3-macros/faq.md
new file mode 100644
index 0000000000..7a809cdd60
--- /dev/null
+++ b/_overviews/scala3-macros/faq.md
@@ -0,0 +1,76 @@
+---
+type: chapter
+title: FAQ
+num: 7
+---
+
+## Which should I use `Expr(...)` or `'{...}`?
+If you can write your code using `Expr(...)`, you will evaluate more at compile time.
+Only use `'{...}` if you really need to evaluate the code later at runtime, usually because it depends on runtime values.
+
+## Which is better between `Expr(true)` or `'{true}`?
+All quotes containing a value of a primitive type is optimised to an `Expr.apply`.
+Choose one in your project and stick with a single notation to avoid confusion.
+
+## How do I get a value out of an `Expr`?
+If the expression represents a value, you can use `.value`, `.valueOrAbort` or `Expr.unapply`
+
+## How can I get the precise type of an `Expr`?
+We can get the precise type (`Type`) of an `Expr` using the following pattern match:
+```scala
+val x: Expr[X] = ...
+x match
+ case '{ $x: t } =>
+ // `x: Expr[X & t]` where `t` is the precise type of `x`
+```
+
+## How do I summon all types of a tuple type?
+If I have a type `(T1, T2, ...)` how do I generate the term for `(summon[T1], summon[T2], ...)` or get the individual expressions with the summoned values?
+
+Depending on your use case the way you will summon them will vary.
+In particular, the code you will need depends on the kind of output you want (`Expr[Tuple]`, `List[Expr[Any]]`, or something else) and how you need errors to be reported.
+Here are two examples that should give you the basic skeleton for two different variant of this code.
+
+```scala
+ def summonAllInList[T](using Type[T])(using Quotes): List[Expr[Any]] = {
+ Type.of[T] match
+ case '[ head *: tail ] =>
+ Expr.summon[head] match
+ case Some(headExpr) => headExpr :: summonAllInList[tail]
+ case _ => quotes.reflect.report.throwError(s"Could not summon ${Type.show[head]}")
+ case '[ EmptyTuple ] => Nil
+ case _ => quotes.reflect.report.throwError(s"Could not `summonAllInList` of tuple with unknown size: ${Type.show[T]}")
+ }
+```
+
+```scala
+ def summonAll[T](using Type[T])(using Quotes): Option[Expr[Tuple]]] = {
+ Type.of[T] match
+ case '[ head *: tail ] =>
+ for headExpr <- Expr.summon[head]
+ tailExpr <- summonAll[tail]
+ yield '{ headExpr *: tailExpr }
+ case '[ EmptyTuple ] => Some('{ EmptyTuple })
+ case _ => None
+ }
+```
+
+## How do I summon an expression for statically unknown types?
+
+You can summon an expression from either a `TypeRepr` or a `Type` as shown below.
+
+If you have a `TypeRepr` use:
+```scala
+val tpe: TypeRepr = ...
+Implicits.search(tpe) match
+ case result: ImplicitSearchSuccess => result.tree
+ case _ =>
+```
+
+Instead, if you have a `Type[_]` use:
+```scala
+val tpe: Type[_] = ...
+tpe match
+ // (1) Use `a` as the name of the unknown type and (2) bring a given `Type[a]` into scope
+ case '[a] => Expr.summon[a]
+```
diff --git a/_overviews/scala3-macros/other-resources.md b/_overviews/scala3-macros/other-resources.md
new file mode 100644
index 0000000000..a50aefa23e
--- /dev/null
+++ b/_overviews/scala3-macros/other-resources.md
@@ -0,0 +1,27 @@
+---
+type: chapter
+title: Other Resources
+num: 9
+---
+
+## Scala 2 migration
+ * [Scala 2 migration and cross-compilation][migration]
+ * [Migration status][migration-status]
+
+## Dotty documentation
+- [Dotty Documentation]({{ site.scala3ref }}/metaprogramming)
+- [Macros: The Plan For Scala 3](https://www.scala-lang.org/blog/2018/04/30/in-a-nutshell.html)
+- [Examples](https://github.com/lampepfl/dotty-macro-examples) - a repository with small, self-contained examples of various tasks done with Dotty macros.
+
+## Talks
+* [Scala Days - Metaprogramming in Dotty](https://www.youtube.com/watch?v=ZfDS_gJyPTc)
+
+## Projects and examples
+* [dotty-macro-examples](https://github.com/lampepfl/dotty-macro-examples)
+* [XML Interpolator](https://github.com/dotty-staging/xml-interpolator/tree/master)
+* [Shapeless 3](https://github.com/dotty-staging/shapeless/tree/shapeless-3)
+* *More Coming soon*
+
+
+[migration]: {% link _overviews/scala3-migration/tutorial-macro-cross-building.md %}
+[migration-status]: https://scalacenter.github.io/scala-3-migration-guide/docs/macros/macro-libraries.html#macro-libraries
diff --git a/_overviews/scala3-macros/tutorial/compiletime.md b/_overviews/scala3-macros/tutorial/compiletime.md
new file mode 100644
index 0000000000..0204efa4c4
--- /dev/null
+++ b/_overviews/scala3-macros/tutorial/compiletime.md
@@ -0,0 +1,75 @@
+---
+type: section
+title: Scala Compile-time Operations
+num: 3
+
+previous-page: inline
+next-page: macros
+---
+
+Operations in [scala.compiletime][compiletime-api] are metaprogramming operations that can be used within an `inline` method.
+These operation do cover some common use cases of macros without you needing to define a macro.
+
+## Reporting
+
+It is possible to emit error messages when inlining code.
+
+```scala
+inline def doSomething(inline mode: Boolean): Unit =
+ if mode then ...
+ else if !mode then ...
+ else error("Mode must be a known value")
+
+doSomething(true)
+doSomething(false)
+val bool: Boolean = ...
+doSomething(bool) // error: Mode must be a known value
+```
+
+If `error` is called outside an inline method, the error will be emitted when compiling that call.
+If the `error` is written inside an inline method, the error will be emitted only if, after inlining the call, it is not removed as part of a dead branch.
+In the previous example, if the value of `mode` were known at compile time, we would only keep one of the first two branches.
+
+If we want to include part of the source code of the arguments in the error message, we can use the `codeOf` method.
+
+```scala
+inline def doSomething(inline mode: Boolean): Unit =
+ if mode then ...
+ else if !mode then ...
+ else error("Mode must be a known value but got: " + codeOf(mode))
+
+val bool: Boolean = ...
+doSomething(bool) // error: Mode must be a known value but got: bool
+```
+
+## Summoning
+
+There are two ways to summon values in inline methods, the first is with a `using` parameter and the second is with one of `summonInline`, `summonAll` or `summonFrom`.
+`using` will summon the value at call site before inlining as if the method was not `inline`.
+On the other hand, `summonInline` will summon after inlining if the call is not eliminated from a dead branch.
+`summonAll` provides a way to summon multiple values at the same time from a tuple type.
+`summonFrom` provides a way to try several implicit searches.
+
+## Values
+* `constValue`, `constValueOpt` and `constValueTuple`
+* `S`
+*Coming soon*
+
+## Testing
+* `testing.typeChecks` and `testing.typeCheckErrors`
+
+## Assertions
+* `byName`
+
+*Coming soon*
+
+## Inline Matching
+* `erasedValue`
+
+*Coming soon*
+
+## Ops (scala.compiletime.ops)
+*Coming soon*
+
+
+[compiletime-api]: https://scala-lang.org/api/3.x/scala/compiletime.html
diff --git a/_overviews/scala3-macros/tutorial/index.md b/_overviews/scala3-macros/tutorial/index.md
new file mode 100644
index 0000000000..e70c39ef45
--- /dev/null
+++ b/_overviews/scala3-macros/tutorial/index.md
@@ -0,0 +1,36 @@
+---
+type: chapter
+title: Tutorial
+description: A tutorial to cover all the features involved in writing macros in Scala 3.
+num: 1
+
+next-page: inline
+---
+
+This tutorial covers all the features involved in writing macros in Scala 3.
+
+The metaprogramming API of Scala 3 is designed in layers to gradually
+support different levels of use-cases. Each successive layer exposes additional
+abstractions and offers more fine-grained control.
+
+- As a starting point, the new [`inline` feature][inline] allows some abstractions (values and methods) to be marked as statically reducible.
+ It provides the entry point for macros and other metaprogramming utilities.
+
+- [Compile-time operations][compiletime] offer additional metaprogramming utilities that can be used within `inline` methods (for example to improve error reporting), without having to define a macro.
+
+- Starting from `inline` methods, [macros][macros] are programs that explicitly operate on programs.
+
+ - Macros can be defined in terms of a _high-level_ API of [quoted expressions][quotes], that admits simple construction and deconstruction of programs expressions.
+
+ - Macros can also be defined in terms of a more _low-level_ API of [Reflection][reflection], that allows detailed inspection of programs.
+
+> The tutorial uses the API of Scala 3.0.0-RC3. The API had many small changes in this revision.
+
+> 🚧 We are still in the process of writing the tutorial. You can [help us][contributing] 🚧
+
+[contributing]: {% link scala3/contribute-to-docs.md %}
+[compiletime]: {% link _overviews/scala3-macros/tutorial/compiletime.md %}
+[inline]: {% link _overviews/scala3-macros/tutorial/inline.md %}
+[macros]: {% link _overviews/scala3-macros/tutorial/macros.md %}
+[quotes]: {% link _overviews/scala3-macros/tutorial/quotes.md %}
+[reflection]: {% link _overviews/scala3-macros/tutorial/reflection.md %}
diff --git a/_overviews/scala3-macros/tutorial/inline.md b/_overviews/scala3-macros/tutorial/inline.md
new file mode 100644
index 0000000000..0fe620f162
--- /dev/null
+++ b/_overviews/scala3-macros/tutorial/inline.md
@@ -0,0 +1,512 @@
+---
+type: section
+title: Inline
+num: 2
+
+previous-page: index
+next-page: compiletime
+---
+
+Inlining is a common compile-time metaprogramming technique, typically used to achieve performance optimizations. As we will see, in Scala 3, the concept of inlining provides us with an entrypoint to programming with macros.
+
+1. It introduces inline as a [soft keyword][soft-modifier].
+2. It guarantees that inlining actually happens instead of being best-effort.
+3. It introduces operations that are guaranteed to evaluate at compile-time.
+
+## Inline Constants
+
+The simplest form of inlining is to inline constants in programs:
+
+
+```scala
+inline val pi = 3.141592653589793
+inline val pie = "🥧"
+```
+
+The usage of the keyword `inline` in the _inline value definitions_ above *guarantees* that all references to `pi` and `pie` are inlined:
+
+```scala
+val pi2 = pi + pi // val pi2 = 6.283185307179586
+val pie2 = pie + pie // val pie2 = "🥧🥧"
+```
+
+In the code above, the references `pi` and `pie` are inlined.
+Then an optimization called "constant folding" is applied by the compiler, which computes the resulting value `pi2` and `pie2` at _compile-time_.
+
+> ##### Inline (Scala 3) vs. final (Scala 2)
+> In Scala 2, we would have used the modifier `final` in the definition that is without a return type:
+>
+> ```scala
+> final val pi = 3.141592653589793
+> final val pie = "🥧"
+> ```
+>
+> The `final` modifier will ensure that `pi` and `pie` will take a _literal type_.
+> Then the constant propagation optimization in the compiler can perform inlining for such definitions.
+> However, this form of constant propagation is _best-effort_ and not guaranteed.
+> Scala 3.0 also supports `final val`-inlining as _best-effort_ inlining for migration purposes.
+
+Currently, only constant expressions may appear on the right-hand side of an inline value definition.
+Therefore, the following code is invalid, though the compiler knows that the right-hand side is a compile-time constant value:
+
+```Scala
+val pi = 3.141592653589793
+inline val pi2 = pi + pi // error
+```
+Note that by defining `inline val pi`, the addition can be computed at compile time.
+This resolves the above error and `pi2` will receive the literal type `6.283185307179586d`.
+
+## Inline Methods
+
+We can also use the modifier `inline` to define a method that should be inlined at the call-site:
+
+```scala
+inline def logged[T](level: Int, message: => String)(inline op: T): T =
+ println(s"[$level]Computing $message")
+ val res = op
+ println(s"[$level]Result of $message: $res")
+ res
+```
+
+When an inline method like `logged` is called, its body will be expanded at the call-site at compile time!
+That is, the call to `logged` will be replaced by the body of the method.
+The provided arguments are statically substituted for the parameters of `logged`, correspondingly.
+Therefore, the compiler inlines the following call
+
+```scala
+logged(logLevel, getMessage()) {
+ computeSomething()
+}
+```
+
+and rewrites it to:
+
+```Scala
+val level = logLevel
+def message = getMessage()
+
+println(s"[$level]Computing $message")
+val res = computeSomething()
+println(s"[$level]Result of $message: $res")
+res
+```
+
+### Semantics of Inline Methods
+Our example method `logged` uses three different kinds of parameters, illustrating
+that inlining handles those parameters differently:
+
+1. __By-value parameters__. The compiler generates a `val` binding for *by-value* parameters. This way, the argument expression is evaluated only once before the method body is reduced.
+
+ This can be seen in the parameter `level` from the example.
+ In some cases, when the arguments are pure constant values, the binding is omitted and the value is inlined directly.
+
+2. __By-Name parameters__. The compiler generates a `def` binding for *by-name* parameters. This way, the argument expression is evaluated every time it is used, but the code is shared.
+
+ This can be seen in the parameter `message` from the example.
+
+3. __Inline parameters__. Inline parameters do not create bindings and are simply inlined. This way, their code is duplicated everywhere they are used.
+
+ This can be seen in the parameter `op` from the example.
+
+The way the different parameters are translated guarantees that inlining a call **will not change** its semantics.
+This implies that the initial elaboration (overloading resolution, implicit search, ...), performed while typing the body of the inline method, will not change when inlined.
+
+For example, consider the following code:
+
+```scala
+class Logger:
+ def log(x: Any): Unit = println(x)
+
+class RefinedLogger extends Logger:
+ override def log(x: Any): Unit = println("Any: " + x)
+ def log(x: String): Unit = println("String: " + x)
+
+inline def logged[T](logger: Logger, x: T): Unit =
+ logger.log(x)
+```
+
+The separate type checking of `logger.log(x)` will resolve the call to the method `Logger.log` which takes an argument of the type `Any`.
+Now, given the following code:
+
+```scala
+logged(new RefinedLogger, "✔️")
+```
+
+It expands to:
+
+```
+val logger = new RefinedLogger
+val x = "✔️"
+logger.log(x)
+```
+Even though now we know that `x` is a `String`, the call `logger.log(x)` still resolves to the method `Logger.log` which takes an argument of the type `Any`. Note that because of late-binding, the actual method called at runtime will be the overridden method `RefinedLogger.log`.
+
+> ##### Inlining preserves semantics
+> Regardless of whether `logged` is defined as a `def` or `inline def`, it performs the same operations with only some differences in performance.
+
+### Inline Parameters
+
+One important application of inlining is to enable constant folding optimisation across method boundaries.
+Inline parameters do not create bindings and their code is duplicated everywhere they are used.
+
+```scala
+inline def perimeter(inline radius: Double): Double =
+ 2.0 * pi * radius
+```
+In the above example, we expect that if the `radius` is statically known then the whole computation can be performed at compile-time.
+The following call
+
+```scala
+perimeter(5.0)
+```
+
+is rewritten to:
+
+```Scala
+2.0 * pi * 5.0
+```
+
+Then `pi` is inlined (we assume the `inline val` definition from the start):
+
+```Scala
+2.0 * 3.141592653589793 * 5.0
+```
+
+Finally, it is constant folded to
+
+```
+31.4159265359
+```
+
+> ##### Inline parameters should be used only once
+> We need to be careful when using an inline parameter **more than once**.
+> Consider the following code:
+>
+> ```scala
+> inline def printPerimeter(inline radius: Double): Double =
+> println(s"Perimeter (r = $radius) = ${perimeter(radius)}")
+> ```
+> It works perfectly fine when a constant or reference to a val is passed to it.
+> ```scala
+> printPerimeter(5.0)
+> // inlined as
+> println(s"Perimeter (r = ${5.0}) = ${31.4159265359}")
+> ```
+>
+> But if a larger expression (possibly with side-effects) is passed, we might accidentally duplicate work.
+>
+> ```scala
+> printPerimeter(longComputation())
+> // inlined as
+> println(s"Perimeter (r = ${longComputation()}) = ${6.283185307179586 * longComputation()}")
+> ```
+
+A useful application of inline parameters is to avoid the creation of _closures_, incurred by the use of by-name parameters.
+
+```scala
+inline def assert1(cond: Boolean, msg: => String) =
+ if !cond then
+ throw new Exception(msg)
+
+assert1(x, "error1")
+// is inlined as
+val cond = x
+def msg = "error1"
+if !cond then
+ throw new Exception(msg)
+```
+In the above example, we can see that the use of a by-name parameter leads to a local definition `msg`, which allocates a closure before the condition is checked.
+
+If we use an inline parameter instead, we can guarantee that the condition is checked before any of the code that handles the exception is reached.
+In the case of an assertion, this code should never be reached.
+```scala
+inline def assert2(cond: Boolean, inline msg: String) =
+ if !cond then
+ throw new Exception(msg)
+
+assert2(x, "error2")
+// is inlined as
+val cond = x
+if !cond then
+ throw new Exception("error2")
+```
+
+### Inline Conditionals
+If the condition of an `if` is a known constant (`true` or `false`), possibly after inlining and constant folding, then the conditional is partially evaluated and only one branch will be kept.
+
+For example, the following power method contains some `if` that will potentially unroll the recursion and remove all method calls.
+
+```scala
+inline def power(x: Double, inline n: Int): Double =
+ if (n == 0) 1.0
+ else if (n % 2 == 1) x * power(x, n - 1)
+ else power(x * x, n / 2)
+```
+Calling `power` with statically known constants results in the following code:
+ ```scala
+ power(2, 2)
+ // first inlines as
+ val x = 2
+ if (2 == 0) 1.0 // dead branch
+ else if (2 % 2 == 1) x * power(x, 2 - 1) // dead branch
+ else power(x * x, 2 / 2)
+ // partially evaluated to
+ val x = 2
+ power(x * x, 1)
+ ```
+
+{::options parse_block_html="true" /}
+
+ See rest of inlining steps
+
+
+```scala
+// then inlined as
+val x = 2
+val x2 = x * x
+if (1 == 0) 1.0 // dead branch
+else if (1 % 2 == 1) x2 * power(x2, 1 - 1)
+else power(x2 * x2, 1 / 2) // dead branch
+// partially evaluated to
+val x = 2
+val x2 = x * x
+x2 * power(x2, 0)
+// then inlined as
+val x = 2
+val x2 = x * x
+x2 * {
+ if (0 == 0) 1.0
+ else if (0 % 2 == 1) x2 * power(x2, 0 - 1) // dead branch
+ else power(x2 * x2, 0 / 2) // dead branch
+}
+// partially evaluated to
+val x = 2
+val x2 = x * x
+x2 * 1.0
+```
+
+
+{::options parse_block_html="false" /}
+
+In contrast, let us imagine we do not know the value of `n`:
+
+```scala
+power(2, unknownNumber)
+```
+Driven by the inline annotation on the parameter, the compiler will try to unroll the recursion.
+But without any success, since the parameter is not statically known.
+
+{::options parse_block_html="true" /}
+
+ See inlining steps
+
+
+```scala
+// first inlines as
+val x = 2
+if (unknownNumber == 0) 1.0
+else if (unknownNumber % 2 == 1) x * power(x, unknownNumber - 1)
+else power(x * x, unknownNumber / 2)
+// then inlined as
+val x = 2
+if (unknownNumber == 0) 1.0
+else if (unknownNumber % 2 == 1) x * {
+ if (unknownNumber - 1 == 0) 1.0
+ else if ((unknownNumber - 1) % 2 == 1) x2 * power(x2, unknownNumber - 1 - 1)
+ else power(x2 * x2, (unknownNumber - 1) / 2)
+}
+else {
+ val x2 = x * x
+ if (unknownNumber / 2 == 0) 1.0
+ else if ((unknownNumber / 2) % 2 == 1) x2 * power(x2, unknownNumber / 2 - 1)
+ else power(x2 * x2, unknownNumber / 2 / 2)
+}
+// Oops this will never finish compiling
+...
+```
+
+{::options parse_block_html="false" /}
+
+To guarantee that the branching can indeed be performed at compile-time, we can use the `inline if` variant of `if`.
+Annotating a conditional with `inline` will guarantee that the conditional can be reduced at compile-time and emits an error if the condition is not a statically known constant.
+
+```scala
+inline def power(x: Double, inline n: Int): Double =
+ inline if (n == 0) 1.0
+ else inline if (n % 2 == 1) x * power(x, n - 1)
+ else power(x * x, n / 2)
+```
+
+```scala
+power(2, 2) // Ok
+power(2, unknownNumber) // error
+```
+
+We will come back to this example later and see how we can get more control on how code is generated.
+
+
+### Inline Method Overriding
+
+To ensure the correct behavior of combining the static feature of `inline def` with the dynamic feature of interfaces and overriding, some restrictions have to be imposed.
+
+#### Effectively final
+Firstly, all inline methods are _effectively final_.
+This ensures that the overload resolution at compile-time behaves the same as the one at runtime.
+
+#### Signature preservation
+Secondly, overrides must have the _exact same signature_ as the overridden method including the inline parameters.
+This ensures that the call semantics are the same for both methods.
+
+#### Retained inline methods
+It is possible to implement or override a normal method with an inline method.
+
+Consider the following example:
+
+```scala
+trait Logger:
+ def log(x: Any): Unit
+
+class PrintLogger extends Logger:
+ inline def log(x: Any): Unit = println(x)
+```
+However, calling the `log` method directly on `PrintLogger` will inline the code, while calling it on `Logger` will not.
+To also admit the latter, the code of `log` must exist at runtime.
+We call this a _retained inline_ method.
+
+For any non-retained inline `def` or `val` the code can always be fully inlined at all call sites.
+Hence, those methods will not be needed at runtime and can be erased from the bytecode.
+However, retained inline methods must be compatible with the case that they are not inlined.
+In particular, retained inline methods cannot take any inline parameters.
+Furthermore, an `inline if` (as in the `power` example) will not work, since the `if` cannot be constant folded in the retained case.
+Other examples involve metaprogramming constructs that only have meaning when inlined.
+
+#### Abstract inline methods
+It is also possible to create _abstract inline definitions_.
+
+```scala
+trait InlineLogger:
+ inline def log(inline x: Any): Unit
+
+class PrintLogger extends InlineLogger:
+ inline def log(inline x: Any): Unit = println(x)
+```
+
+This forces the implementation of `log` to be an inline method and also allows `inline` parameters.
+Counterintuitively, the `log` on the interface `InlineLogger` cannot be directly called. The method implementation is not statically known and we thus do not know what to inline.
+Calling an abstract inline method thus results in an error.
+The usefulness of abstract inline methods becomes apparent when used in another inline method:
+
+```scala
+inline def logged(logger: InlineLogger, x: Any) =
+ logger.log(x)
+```
+Let us assume a call to `logged` on a concrete instance of `PrintLogger`:
+```scala
+logged(new PrintLogger, "🥧")
+// inlined as
+val logger = new PrintLogger
+val x = "🥧"
+logger.log(x)
+```
+After inlining, the call to `log` is de-virtualized and known to be on `PrintLogger`.
+Therefore also the code of `log` can be inlined.
+
+#### Summary of inline methods
+* All `inline` methods are final.
+* Abstract `inline` methods can only be implemented by inline methods.
+* If an inline method overrides/implements a normal method then it must be retained and retained methods cannot have inline parameters.
+* Abstract `inline` methods cannot be called directly (except in inline code).
+
+## Transparent Inline Methods
+Transparent inlines are a simple, yet powerful, extension to `inline` methods and unlock many metaprogramming usecases.
+Calls to transparents allow for an inline piece of code to refine the return type based on the precise type of the inlined expression.
+In Scala 2 parlance, transparents capture the essence of _whitebox macros_.
+
+
+```scala
+transparent inline def default(inline name: String): Any =
+ inline if name == "Int" then 0
+ else inline if name == "String" then ""
+ else ...
+```
+
+```scala
+val n0: Int = default("Int")
+val s0: String = default("String")
+```
+
+Note that even if the return type of `default` is `Any`, the first call is typed as an `Int` and the second as a `String`.
+The return type represents the upper bound of the type within the inlined term.
+We could also have been more precise and have written instead
+```scala
+transparent inline def default(inline name: String): 0 | "" = ...
+```
+While in this example it seems the return type is not necessary, it is important when the inline method is recursive.
+There it should be precise enough for the recursion to type but will get more precise after inlining.
+
+> ##### Transparents affect binary compatibility
+> It is important to note that changing the body of a `transparent inline def` will change how the call site is typed.
+> This implies that the body plays a part in the binary and source compatibility of this interface.
+
+
+## Compiletime Operations
+
+We also provide some operations that evaluate at compiletime.
+
+### Inline Matches
+Like inline `if`, inline matches guarantee that the pattern matching can be statically reduced at compile time and only one branch is kept.
+
+In the following example, the scrutinee, `x`, is an inline parameter that we can pattern match on at compile time.
+
+```scala
+inline def half(x: Any): Any =
+ inline x match
+ case x: Int => x / 2
+ case x: String => x.substring(0, x.length / 2)
+
+half(6)
+// expands to:
+// val x = 6
+// x / 2
+
+half("hello world")
+// expands to:
+// val x = "hello world"
+// x.substring(0, x.length / 2)
+```
+This illustrates that inline matches provide a way to match on the static type of some expression.
+As we match on the _static_ type of an expression, the following code would fail to compile.
+
+```scala
+val n: Any = 3
+half(n) // error: n is not statically known to be an Int or a Double
+```
+Notably, The value `n` is not marked as `inline` and in consequence at compile time
+there is not enough information about the scrutinee to decide which branch to take.
+
+### scala.compiletime
+The package `scala.compiletime` provides useful metaprogramming abstractions that can be used within `inline` methods to provide custom semantics.
+
+## Macros
+Inlining is also the core mechanism used to write macros.
+Macros provide a way to control the code generation and analysis after the call is inlined.
+
+
+```scala
+inline def power(x: Double, inline n: Int) =
+ ${ powerCode('x, 'n) }
+
+def powerCode(x: Expr[Double], n: Expr[Int])(using Quotes): Expr[Double] = ...
+```
+
+
+[soft-modifier]: {{ site.scala3ref }}/soft-modifier.html
+
+[contributing]: {% link scala3/contribute-to-docs.md %}
+[best-practices]: {% link _overviews/scala3-macros/best-practices.md %}
+[compiletime]: {% link _overviews/scala3-macros/tutorial/compiletime.md %}
+[faq]: {% link _overviews/scala3-macros/faq.md %}
+[inline]: {% link _overviews/scala3-macros/tutorial/inline.md %}
+[macros]: {% link _overviews/scala3-macros/tutorial/macros.md %}
+[quotes]: {% link _overviews/scala3-macros/tutorial/quotes.md %}
+[tasty]: {% link _overviews/scala3-macros/tutorial/reflection.md %}
diff --git a/_overviews/scala3-macros/tutorial/macros.md b/_overviews/scala3-macros/tutorial/macros.md
new file mode 100644
index 0000000000..1c90c15928
--- /dev/null
+++ b/_overviews/scala3-macros/tutorial/macros.md
@@ -0,0 +1,304 @@
+---
+type: section
+title: Scala 3 Macros
+num: 4
+
+previous-page: compiletime
+next-page: quotes
+---
+
+[Inline methods][inline] provide us with a elegant technique for metaprogramming by performing some operations at compile time.
+However, sometimes inlining is not enough and we need more powerful ways to analyze and synthesize programs at compile time.
+Macros enable us to do exactly this: treat **programs as data** and manipulate them.
+
+
+## Macros Treat Programs as Values
+With a macro, we can treat programs as values, which allows us to analyze and generate them at compile time.
+
+A Scala expression with type `T` is represented by an instance of the type `scala.quoted.Expr[T]`.
+
+We will dig into the details of the type `Expr[T]`, as well as the different ways of analyzing and constructing instances, when talking about [Quoted Code][quotes] and [Reflection][tasty].
+For now, it suffices to know that macros are metaprograms that manipulate expressions of type `Expr[T]`.
+
+The following macro implementation prints the expression of the provided argument at compile-time in the standard output of the compiler process:
+```scala
+import scala.quoted.* // imports Quotes, Expr
+
+def inspectCode(x: Expr[Any])(using Quotes): Expr[Any] =
+ println(x.show)
+ x
+```
+After printing the argument expression, we return the original argument as a Scala expression of type `Expr[Any]`.
+
+As foreshadowed in the section on [Inline][inline], inline methods provide the entry point for macro definitions:
+
+```scala
+inline def inspect(inline x: Any): Any = ${ inspectCode('x) }
+```
+All macros are defined with an `inline def`.
+The implementation of this entry point always has the same shape:
+
+- they only contain a single [splice][quotes] `${ ... }`
+- the splice contains a single call to the method that implements the macro (for example `inspectCode`).
+- the call to the macro implementation receives the _quoted_ parameters (that is `'x` instead of `x`) and a contextual `Quotes`.
+
+We will dig deeper into these concepts later in this and the following sections.
+
+Calling our `inspect` macro `inspect(sys error "abort")` prints a string representation of the argument expression at compile time:
+```
+scala.sys.error("abort")
+```
+
+
+### Macros and Type Parameters
+
+If the macro has type parameters, the implementation will also need to know about them.
+Just like `scala.quoted.Expr[T]` represents a Scala expression of type `T`, we use `scala.quoted.Type[T]` to represent the Scala type `T`.
+
+```scala
+inline def logged[T](inline x: T): T = ${ loggedCode('x) }
+
+def loggedCode[T](x: Expr[T])(using Type[T], Quotes): Expr[T] = ...
+```
+Both the instance of `Type[T]` and the contextual `Quotes` are automatically provided by the splice in the corresponding inline method (that is, `logged`) and can be used by the macro implementation.
+
+
+### Defining and Using Macros
+
+A key difference between inlining and macros is the way they are evaluated.
+Inlining works by rewriting code and performing optimisations based on rules the compiler knows.
+On the other hand, a macro executes user-written code that generates the code that the macro expands to.
+
+Technically, compiling the inlined code `${ inspectCode('x) }` calls the method `inspectCode` _at compile time_ (through Java reflection), and the method `inspectCode` then executes as normal code.
+
+To be able to execute `inspectCode`, we need to compile its source code first.
+As a technical consequence, we cannot define and use a macro in the **same class/file**.
+However, it is possible to have the macro definition and its call in the **same project** as long as the implementation of the macro can be compiled first.
+
+> ##### Suspended Files
+> To allow defining and using macros in the same project, only those calls to macros that have already been compiled are expanded.
+> For all other (unknown) macro calls, the compilation of the file is _suspended_.
+> Suspended files are only compiled after all non suspended files have been successfully compiled.
+> In some cases, you will have _cyclic dependencies_ that will block the completion of the compilation.
+> To get more information on which files are suspended you can use the `-Xprint-suspension` compiler flag.
+
+
+### Example: Statically Evaluating `power` with Macros
+
+Let us recall our definition of `power` from the section on [Inline][inline] that specialized the computation of `xⁿ` for statically known values of `n`.
+```scala
+inline def power(x: Double, inline n: Int): Double =
+ inline if n == 0 then 1.0
+ else inline if n % 2 == 1 then x * power(x, n - 1)
+ else power(x * x, n / 2)
+```
+In the remainder of this section, we will define a macro that computes `xⁿ` for a statically known values `x` and `n`.
+While this is also possible purely with `inline`, implementing it with macros will illustrate a few things.
+
+```scala
+inline def power(inline x: Double, inline n: Int) =
+ ${ powerCode('x, 'n) }
+
+def powerCode(
+ x: Expr[Double],
+ n: Expr[Int]
+)(using Quotes): Expr[Double] = ...
+```
+
+## Simple Expressions
+
+We could implement `powerCode` as follows:
+```scala
+def pow(x: Double, n: Int): Double =
+ if n == 0 then 1 else x * pow(x, n - 1)
+
+def powerCode(
+ x: Expr[Double],
+ n: Expr[Int]
+)(using Quotes): Expr[Double] =
+ val value: Double = pow(x.valueOrAbort, n.valueOrAbort)
+ Expr(value)
+```
+Here, the `pow` operation is a simple Scala function that computes the value of `xⁿ`.
+The interesting part is how we create and look into the `Expr`s.
+
+
+### Creating Expression From Values
+
+Let's first look at `Expr.apply(value)`. Given a value of type `T`, this call will return an expression containing the code representing the given value (that is, of type `Expr[T]`).
+The argument value to `Expr` is computed at compile-time, at runtime we only need to instantiate this value.
+
+Creating expressions from values works for all _primitive types_, _tuples_ of any arity, `Class`, `Array`, `Seq`, `Set`, `List`, `Map`, `Option`, `Either`, `BigInt`, `BigDecimal`, `StringContext`.
+Other types can also work if a `ToExpr` is implemented for it, we will [see this later][quotes].
+
+
+### Extracting Values from Expressions
+
+The second method we use in the implementation of `powerCode` is `Expr[T].valueOrAbort`, which has an effect opposite to `Expr.apply`.
+It attempts to extract a value of type `T` from an expression of type `Expr[T]`.
+This can only succeed, if the expression directly contains the code of a value, otherwise, it will throw an exception that stops the macro expansion and reports that the expression did not correspond to a value.
+
+Instead of `valueOrAbort`, we could also use the `value` operation, which will return an `Option`.
+This way we can report the error with a custom error message.
+
+#### Reporting Custom Error Messages
+
+The contextual `Quotes` parameter provides a `report` object that we can use to report a custom error message.
+Within a macro implementation method, you can access the contextual `Quotes` parameter with the `quotes` method
+(imported with `import scala.quoted.*`), then import the `report` object by `import quotes.reflect.report`.
+
+#### Providing the Custom Error
+
+We will provide the custom error message by calling `errorAndAbort` on the `report` object as follows:
+```scala
+def powerCode(
+ x: Expr[Double],
+ n: Expr[Int]
+)(using Quotes): Expr[Double] =
+ import quotes.reflect.report
+ (x.value, n.value) match
+ case (Some(base), Some(exponent)) =>
+ val value: Double = pow(base, exponent)
+ Expr(value)
+ case (Some(_), _) =>
+ report.errorAndAbort("Expected a known value for the exponent, but was " + n.show, n)
+ case _ =>
+ report.errorAndAbort("Expected a known value for the base, but was " + x.show, x)
+```
+
+Alternatively, we can also use the `Expr.unapply` extractor
+
+```scala
+ ...
+ (x, n) match
+ case (Expr(base), Expr(exponent)) =>
+ val value: Double = pow(base, exponent)
+ Expr(value)
+ case (Expr(_), _) => ...
+ case _ => ...
+```
+The operations `value`, `valueOrAbort`, and `Expr.unapply` will work for all _primitive types_, _tuples_ of any arity, `Option`, `Seq`, `Set`, `Map`, `Either` and `StringContext`.
+Other types can also work if an `FromExpr` is implemented for it, we will [see this later][quotes].
+
+
+### Showing Expressions
+
+In the implementation of `inspectCode`, we have already seen how to convert expressions to the string representation of their _source code_ using the `.show` method.
+This can be useful to perform debugging on macro implementations:
+
+
+```scala
+def debugPowerCode(
+ x: Expr[Double],
+ n: Expr[Int]
+)(using Quotes): Expr[Double] =
+ println(
+ s"powerCode \n" +
+ s" x := ${x.show}\n" +
+ s" n := ${n.show}")
+ val code = powerCode(x, n)
+ println(s" code := ${code.show}")
+ code
+```
+
+
+### Working with Varargs
+
+Varargs in Scala are represented with `Seq`, hence when we write a macro with a _vararg_, it will be passed as an `Expr[Seq[T]]`.
+It is possible to recover each individual argument (of type `Expr[T]`) using the `scala.quoted.Varargs` extractor.
+
+```scala
+import scala.quoted.* // imports `Varargs`, `Quotes`, etc.
+
+inline def sumNow(inline nums: Int*): Int =
+ ${ sumCode('nums) }
+
+def sumCode(nums: Expr[Seq[Int]])(using Quotes): Expr[Int] =
+ import quotes.reflect.report
+ nums match
+ case Varargs(numberExprs) => // numberExprs: Seq[Expr[Int]]
+ val numbers: Seq[Int] = numberExprs.map(_.valueOrAbort)
+ Expr(numbers.sum)
+ case _ => report.errorAndAbort(
+ "Expected explicit varargs sequence. " +
+ "Notation `args*` is not supported.", nums)
+```
+
+The extractor will match a call to `sumNow(1, 2, 3)` and extract a `Seq[Expr[Int]]` containing the code of each parameter.
+But, if we try to match the argument of the call `sumNow(nums*)`, the extractor will not match.
+
+`Varargs` can also be used as a constructor. `Varargs(Expr(1), Expr(2), Expr(3))` will return an `Expr[Seq[Int]]`.
+We will see how this can be useful later.
+
+
+## Complex Expressions
+So far, we have only seen how to construct and destruct expressions that correspond to simple values.
+In order to work with more complex expressions, Scala 3 offers different metaprogramming facilities ranging from
+
+- additional constructors like `Expr.apply`,
+- over [quoted pattern matching][quotes],
+- to a full [reflection API][tasty];
+
+each increasing in complexity and potentially losing safety guarantees.
+It is generally recommended to prefer simple APIs over more advanced ones.
+In the remainder of this section, we introduce some more additional constructors and destructors,
+while subsequent chapters introduce the more advanced APIs.
+
+### Collections
+
+We have seen how to convert a `List[Int]` into an `Expr[List[Int]]` using `Expr.apply`.
+How about converting a `List[Expr[Int]]` into an `Expr[List[Int]]`?
+We mentioned that `Varargs.apply` can do this for sequences; likewise, for other collection types, corresponding methods are available:
+
+* `Expr.ofList`: Transform a `List[Expr[T]]` into `Expr[List[T]]`
+* `Expr.ofSeq`: Transform a `Seq[Expr[T]]` into `Expr[Seq[T]]` (just like `Varargs`)
+* `Expr.ofTupleFromSeq`: Transform a `Seq[Expr[T]]` into `Expr[Tuple]`
+* `Expr.ofTuple`: Transform a `(Expr[T1], ..., Expr[Tn])` into `Expr[(T1, ..., Tn)]`
+
+### Simple Blocks
+
+The constructor `Expr.block` provides a simple way to create a block of code `{ stat1; ...; statn; expr }`.
+Its first arguments is a list with all the statements and the second argument is the expression at the end of the block.
+
+```scala
+inline def test(inline ignore: Boolean, computation: => Unit): Boolean =
+ ${ testCode('ignore, 'computation) }
+
+def testCode(ignore: Expr[Boolean], computation: Expr[Unit])(using Quotes) =
+ if ignore.valueOrAbort then Expr(false)
+ else Expr.block(List(computation), Expr(true))
+```
+
+The `Expr.block` constructor is useful when we want to generate code contanining several side effects.
+The macro call `test(false, EXPRESSION)` will generate `{ EXPRESSION; true}`, while the call `test(true, EXPRESSION)` will result in `false`.
+
+### Simple Matching
+
+The method `Expr.matches` can be used to check if one expression is equal to another.
+With this method we could implement an `value` operation for `Expr[Boolean]` as follows.
+
+```scala
+def value(boolExpr: Expr[Boolean]): Option[Boolean] =
+ if boolExpr.matches(Expr(true)) then Some(true)
+ else if boolExpr.matches(Expr(false)) then Some(false)
+ else None
+```
+
+It may also be used to compare two user written expression.
+Note, that `matches` only performs a limited amount of normalization and while for instance the Scala expression `2` matches the expression `{ 2 }`, this is _not the case_ for the expression `{ val x: Int = 2; x }`.
+
+### Arbitrary Expressions
+
+Last but not least, it is possible to create an `Expr[T]` from arbitary Scala code by enclosing it in [quotes][quotes].
+For example, `'{ ${expr}; true }` will generate an `Expr[Boolean]` equivalent to `Expr.block(List(expr), Expr(true))`.
+The subsequent section on [Quoted Code][quotes] presents quotes in more detail.
+
+[contributing]: {% link scala3/contribute-to-docs.md %}
+[best-practices]: {% link _overviews/scala3-macros/best-practices.md %}
+[compiletime]: {% link _overviews/scala3-macros/tutorial/compiletime.md %}
+[migration]: https://scalacenter.github.io/scala-3-migration-guide/docs/macros/macro-libraries.html
+[faq]: {% link _overviews/scala3-macros/faq.md %}
+[inline]: {% link _overviews/scala3-macros/tutorial/inline.md %}
+[macros]: {% link _overviews/scala3-macros/tutorial/macros.md %}
+[quotes]: {% link _overviews/scala3-macros/tutorial/quotes.md %}
+[tasty]: {% link _overviews/scala3-macros/tutorial/reflection.md %}
diff --git a/_overviews/scala3-macros/tutorial/quotes.md b/_overviews/scala3-macros/tutorial/quotes.md
new file mode 100644
index 0000000000..b94d4bb6ab
--- /dev/null
+++ b/_overviews/scala3-macros/tutorial/quotes.md
@@ -0,0 +1,605 @@
+---
+type: section
+title: Quoted Code
+num: 5
+
+previous-page: macros
+next-page: reflection
+---
+
+## Code blocks
+A quoted code block `'{ ... }` is syntactically similar to a string quote `" ... "` with the difference that the first contains typed code.
+To insert code into other code, we can use the syntax `$expr` or `${ expr }`, where `expr` is of type `Expr[T]`.
+Intuitively, the code directly within the quote (`'{ ... }`) is not executed now, while the code within the splice (`${ ... }`) is evaluated and the results spliced into the surrounding expression.
+
+```scala
+val msg = Expr("Hello")
+val printHello = '{ print($msg) }
+println(printHello.show) // print("Hello")
+```
+
+In general, the quote delays the execution while the splice makes it happen before the surrounding code.
+This generalisation allows us to also give meaning to a `${ ... }` that is not within a quote. This evaluates the code within the splice at compile-time and places the result in the generated code.
+Due to some technical considerations, only top-level splices are allowed directly within `inline` definitions that we call a [macro][macros].
+
+It is possible to write a quote within a quote, but this pattern is not common when writing macros.
+
+## Level consistency
+One cannot simply write any arbitrary code within quotes and within splices, as one part of the program will live at compile-time and the other will live at runtime.
+Consider the following ill-constructed code:
+
+```scala
+def myBadCounter1(using Quotes): Expr[Int] = {
+ var x = 0
+ '{ x += 1; x }
+}
+```
+The problem with this code is that `x` exists during compilation, but then we try to use it after the compiler has finished (maybe even in another machine).
+Clearly, it would be impossible to access its value and update it.
+
+Now consider the dual version, where we define the variable at runtime and try to access it at compile-time:
+```scala
+def myBadCounter2(using Quotes): Expr[Int] = '{
+ var x = 0
+ ${ x += 1; 'x }
+}
+```
+Clearly, this should not work as the variable does not exist yet.
+
+To make sure you cannot write programs that contain these kinds of problems, we restrict the kinds of references allowed in quote environments.
+
+We introduce _levels_ as a count of the number of quotes minus the number of splices surrounding an expression or definition.
+
+```scala
+// level 0
+'{ // level 1
+ var x = 0
+ ${ // level 0
+ x += 1
+ 'x // level 1
+ }
+}
+```
+
+The system will allow references to global definitions such as `println` at any level, but will restrict references to local definitions.
+A local definition can only be accessed if it is defined at the same level as its reference.
+This will catch the errors in `myBadCounter1` and `myBadCounter2`.
+
+Even though we cannot refer to a variable inside of a quote, we can still pass its current value through a quote by lifting the value to an expression using `Expr.apply`.
+
+
+## Generics
+
+When using type parameters or other kinds of abstract types with quoted code, we will need to keep track of some of these types explicitly.
+Scala uses erased-types semantics for its generics.
+This implies that types are removed from the program when compiling and the runtime does not have to track all types at runtime.
+
+Consider the following code:
+```scala
+def evalAndUse[T](x: Expr[T])(using Quotes) = '{
+ val x2: T = $x // error
+ ... // use x2
+}
+```
+
+Here, we will get an error telling us that we are missing a contextual `Type[T]`.
+Therefore, we can easily fix it by writing:
+```scala
+def evalAndUse[T](x: Expr[T])(using Type[T])(using Quotes) = '{
+ val x2: T = $x
+ ... // use x2
+}
+```
+This code will be equivalent to this more verbose version:
+```scala
+def evalAndUse[T](x: Expr[T])(using t: Type[T])(using Quotes) = '{
+ val x2: t.Underlying = $x
+ ... // use x2
+}
+```
+Note that `Type` has a type member called `Underlying` that refers to the type held within the `Type`; in this case, `t.Underlying` is `T`.
+Even if we use the `Type` implicitly, is generally better to keep it contextual as some changes inside the quote may require it.
+The less verbose version is usually the best way to write the types as it is much simpler to read.
+In some cases, we will not statically know the type within the `Type` and will need to use the `t.Underlying` to refer to it.
+
+When do we need this extra `Type` parameter?
+* When a type is abstract and it is used at a level that is higher than the current level.
+
+When you add a `Type` contextual parameter to a method, you will either get it from another context parameter or implicitly with a call to `Type.of`:
+```scala
+evalAndUse(Expr(3))
+// is equivalent to
+evalAndUse[Int](Expr(3))(using Type.of[Int])
+```
+As you may have guessed, not every type can be used as a parameter to `Type.of[..]` out of the box.
+For example, we cannot recover abstract types that have already been erased:
+```scala
+def evalAndUse[T](x: Expr[T])(using Quotes) =
+ given Type[T] = Type.of[T] // error
+ '{
+ val x2: T = $x
+ ... // use x2
+ }
+```
+
+But we can write more complex types that depend on these abstract types.
+For example, if we look for or explicitly construct a `Type[List[T]]`, then the system will require a `Type[T]` in the current context to compile.
+
+Good code should only add `Type`s to the context parameters and never use them explicitly.
+However, explicit use is useful while debugging, though it comes at the cost of conciseness and clarity.
+
+
+## ToExpr
+The `Expr.apply` method uses instances of `ToExpr` to generate an expression that will create a copy of the value.
+```scala
+object Expr:
+ def apply[T](x: T)(using Quotes, ToExpr[T]): Expr[T] =
+ summon[ToExpr[T]].apply(x)
+```
+
+`ToExpr` is defined as follows:
+```scala
+trait ToExpr[T]:
+ def apply(x: T)(using Quotes): Expr[T]
+```
+
+The `ToExpr.apply` method will take a value `T` and generate code that will construct a copy of this value at runtime.
+
+We can define our own `ToExpr`s like:
+```scala
+given ToExpr[Boolean] with {
+ def apply(x: Boolean)(using Quotes) =
+ if x then '{true}
+ else '{false}
+}
+
+given ToExpr[StringContext] with {
+ def apply(stringContext: StringContext)(using Quotes) =
+ val parts = Varargs(stringContext.parts.map(Expr(_)))
+ '{ StringContext($parts*) }
+}
+```
+The `Varargs` constructor just creates an `Expr[Seq[T]]` which we can efficiently splice as a varargs.
+In general, any sequence can be spliced with `$mySeq*` to splice it as a varargs.
+
+## Quoted patterns
+Quotes can also be used to check if an expression is equivalent to another or to deconstruct an expression into its parts.
+
+
+### Matching exact expression
+
+The simplest thing we can do is to check if an expression matches another known expression.
+Below, we show how we can match some expressions using `case '{...} =>`.
+
+```scala
+def valueOfBoolean(x: Expr[Boolean])(using Quotes): Option[Boolean] =
+ x match
+ case '{ true } => Some(true)
+ case '{ false } => Some(false)
+ case _ => None
+
+def valueOfBooleanOption(x: Expr[Option[Boolean]])(using Quotes): Option[Option[Boolean]] =
+ x match
+ case '{ Some(true) } => Some(Some(true))
+ case '{ Some(false) } => Some(Some(false))
+ case '{ None } => Some(None)
+ case _ => None
+```
+
+### Matching partial expression
+
+To make things more compact, we can also match a part of the expression using a splice (`$`) to match arbitrary code and extract it.
+
+```scala
+def valueOfBooleanOption(x: Expr[Option[Boolean]])(using Quotes): Option[Option[Boolean]] =
+ x match
+ case '{ Some($boolExpr) } => Some(valueOfBoolean(boolExpr))
+ case '{ None } => Some(None)
+ case _ => None
+```
+
+### Matching types of expression
+
+We can also match against code of an arbitrary type `T`.
+Below, we match against `$x` of type `T` and we get out an `x` of type `Expr[T]`.
+
+```scala
+def exprOfOption[T: Type](x: Expr[Option[T]])(using Quotes): Option[Expr[T]] =
+ x match
+ case '{ Some($x) } => Some(x) // x: Expr[T]
+ case '{ None } => Some(None)
+ case _ => None
+```
+
+We can also check for the type of an expression:
+
+```scala
+def valueOf(x: Expr[Any])(using Quotes): Option[Any] =
+ x match
+ case '{ $x: Boolean } => valueOfBoolean(x) // x: Expr[Boolean]
+ case '{ $x: Option[Boolean] } => valueOfBooleanOption(x) // x: Expr[Option[Boolean]]
+ case _ => None
+```
+Or similarly for a partial expression:
+
+```scala
+case '{ Some($x: Boolean) } => // x: Expr[Boolean]
+```
+
+### Matching receiver of methods
+
+When we want to match the receiver of a method, we need to explicitly state its type:
+
+```scala
+case '{ ($ls: List[Int]).sum } =>
+```
+
+If we would have written `$ls.sum`, we would not have been able to know the type of `ls` and which `sum` method we are calling.
+
+Another common case where we need type annotations is for infix operations:
+```scala
+case '{ ($x: Int) + ($y: Int) } =>
+case '{ ($x: Double) + ($y: Double) } =>
+case ...
+```
+
+### Matching function expressions
+
+Let's start with the most straightforward example, matching an identity function expression:
+
+```scala
+def matchIdentityFunction[A: Type](func: Expr[A => A])(using Quotes): Unit =
+ func match
+ case '{ (arg: A) => arg } =>
+```
+The above matches function expressions that just return their arguments, like:
+
+```scala
+(value: Int) => value
+```
+
+We can also match more complex expressions, like method call chains:
+
+```scala
+def matchMethodCallChain(func: Expr[String => String])(using Quotes) =
+ func match
+ case '{ (arg: String) => arg.toLowerCase.strip.trim } =>
+```
+
+But what about the cases where we want more flexibility (eg. we know the subset of methods that will be called but not neccessarily their order)?
+
+#### Iterative deconstruction of a function expression
+
+Let's imagine we need a macro that collects names of methods used in an expression of type `FieldName => FieldName`, for a definition of `FieldName`:
+
+```scala
+trait FieldName:
+ def uppercase: FieldName
+ def lowercase: FieldName
+```
+
+The implementation itself would look like this:
+
+```scala
+def collectUsedMethods(func: Expr[FieldName => FieldName])(using Quotes): List[String] =
+ def recurse(current: Expr[FieldName => FieldName], acc: List[String])(using Quotes): List[String] =
+ current match
+ // $body is the next tree with the '.lowercase' call stripped away
+ case '{ (arg: FieldName) => ($body(arg): FieldName).lowercase } =>
+ recurse(body, "lowercase" :: acc) // body: Expr[FieldName => FieldName]
+
+ // $body is the next tree with the '.uppercase' call stripped away
+ case '{ (arg: FieldName) => ($body(arg): FieldName).uppercase } =>
+ recurse(body, "uppercase" :: acc) // body: Expr[FieldName => FieldName]
+
+ // this matches an identity function, i.e. the end of our loop
+ case '{ (arg: FieldName) => arg } => acc
+ end recurse
+
+ recurse(func, Nil)
+```
+
+For more details on how patterns like `$body(arg)` work please refer to a docs section on [the HOAS pattern](https://dotty.epfl.ch/docs/reference/metaprogramming/macros.html#hoas-patterns-1).
+
+If we were to use this on an expression like this one:
+```scala
+(name: FieldName) => name.lowercase.uppercase.lowercase
+```
+the result would evaluate to `List("lowercase", "uppercase", "lowercase")`.
+
+### Matching types
+
+So far, we assumed that the types within quote patterns would be statically known.
+Quote patterns also allow for type parameters, which we will see in this section.
+
+#### Type parameters in patterns
+
+Consider the function `exprOfOption` that we have already seen:
+```scala
+def exprOfOption[T: Type](x: Expr[Option[T]])(using Quotes): Option[Expr[T]] =
+ x match
+ case '{ Some($x: T) } => Some(x) // x: Expr[T]
+ // ^^^ type ascription with type T
+ ...
+```
+
+Note that this time we have added the `T` explicitly in the pattern, even though it could be inferred.
+By referring to the type parameter `T` in the pattern, we are required to have a given `Type[T]` in scope.
+This implies that `$x: T` will only match if `x` is of type `Expr[T]`.
+In this particular case, this condition will always be true.
+
+Now consider the following variant where `x` is an optional value with a (statically) unknown element type:
+
+```scala
+def exprOfOptionOf[T: Type](x: Expr[Option[Any]])(using Quotes): Option[Expr[T]] =
+ x match
+ case '{ Some($x: T) } => Some(x) // x: Expr[T]
+ case _ => None
+```
+This time, the pattern `Some($x: T)` will only match if the type of the `Option` is `Some[T]`.
+
+```scala
+exprOfOptionOf[Int]('{ Some(3) }) // Some('{3})
+exprOfOptionOf[Int]('{ Some("a") }) // None
+```
+
+#### Type variables in quoted patterns
+
+Quoted code may contain types that are not known outside of the quote.
+We can match on them using pattern type variables.
+Just as in a normal pattern, the type variables are written using lower case names.
+
+```scala
+def exprOptionToList(x: Expr[Option[Any]])(using Quotes): Option[Expr[List[Any]]] =
+ x match
+ case '{ Some($x: t) } =>
+ // ^^^ this binds the type `t` in the body of the case
+ Some('{ List[t]($x) }) // x: Expr[List[t]]
+ case '{ None } =>
+ Some('{ Nil })
+ case _ => None
+```
+
+The pattern `$x: t` will match an expression of any type and `t` will be bound to the type of the pattern.
+This type variable is only valid in the right-hand side of the `case`.
+In this example, we use it to construct the list `List[t]($x)` (`List($x)` would also work).
+As this is a type that is not statically, known we need a given `Type[t]` in scope.
+Luckily, the quoted pattern will automatically provide this for us.
+
+The simple pattern `case '{ $expr: tpe } =>` is very useful if we want to know the precise type of the expression.
+```scala
+val expr: Expr[Option[Int]] = ...
+expr match
+ case '{ $expr: tpe } =>
+ Type.show[tpe] // could be: Option[Int], Some[Int], None, Option[1], Option[2], ...
+ '{ val x: tpe = $expr; x } // binds the value without widening the type
+ ...
+```
+
+In some cases we need to define a pattern variable that is referenced several times or has some type bounds.
+To achieve this, it is possible to create pattern variables at the start of the pattern using `type t` with a type pattern variable.
+
+```scala
+/**
+ * Use: Converts a redundant `list.map(f).map(g)` to only use one call
+ * to `map`: `list.map(y => g(f(y)))`.
+ */
+def fuseMap[T: Type](x: Expr[List[T]])(using Quotes): Expr[List[T]] = x match {
+ case '{
+ type u
+ type v
+ ($ls: List[`u`])
+ .map($f: `u` => `v`)
+ .map($g: `v` => T)
+ } =>
+ '{ $ls.map(y => $g($f(y))) }
+ case _ => x
+}
+```
+
+Here, we define two type variables `u` and `v` and then refer to them using `` `u` `` and `` `v` ``.
+We do not refer to them using `u` or `v` (without backticks) because those would be interpreted as new type variables with the same variable name.
+This notation follows the normal [stable identifier patterns](https://www.scala-lang.org/files/archive/spec/2.13/08-pattern-matching.html#stable-identifier-patterns) syntax.
+Furthermore, if the type variable needs to be constrained, we can add bounds directly on the type definition: `case '{ type u <: AnyRef; ... } =>`.
+
+Note that the previous case could also be written as `case '{ ($ls: List[u]).map[v]($f).map[T]($g) =>`.
+
+#### Quote types patterns
+
+Types represented with `Type[T]` can be matched on using the patten `case '[...] =>`.
+
+```scala
+inline def mirrorFields[T]: List[String] = ${mirrorFieldsImpl[T]}
+
+def mirrorFieldsImpl[T: Type](using Quotes): Expr[List[String]] =
+
+ def rec[A : Type]: List[String] = Type.of[A] match
+ case '[field *: fields] =>
+ Type.show[field] :: rec[fields]
+ case '[EmptyTuple] =>
+ Nil
+ case _ =>
+ quotes.reflect.report.errorAndAbort("Expected known tuple but got: " + Type.show[A])
+
+ Expr(rec)
+```
+```scala
+mirrorFields[EmptyTuple] // Nil
+mirrorFields[(Int, String, Int)] // List("scala.Int", "java.lang.String", "scala.Int")
+mirrorFields[Tuple] // error: Expected known tuple but got: Tuple
+```
+
+As with expression quote patterns, type variables are represented using lower case names.
+
+## FromExpr
+
+The `Expr.value`, `Expr.valueOrAbort`, and `Expr.unapply` methods use instances of `FromExpr` to extract the value if possible.
+```scala
+extension [T](expr: Expr[T]):
+ def value(using Quotes)(using fromExpr: FromExpr[T]): Option[T] =
+ fromExpr.unapply(expr)
+
+ def valueOrError(using Quotes)(using fromExpr: FromExpr[T]): T =
+ fromExpr.unapply(expr).getOrElse(eport.throwError("...", expr))
+end extension
+
+object Expr:
+ def unapply[T](expr: Expr[T])(using Quotes)(using fromExpr: FromExpr[T]): Option[T] =
+ fromExpr.unapply(expr)
+```
+
+`FromExpr` is defined as follows:
+```scala
+trait FromExpr[T]:
+ def unapply(x: Expr[T])(using Quotes): Option[T]
+```
+
+The `FromExpr.unapply` method will take a value `x` and generate code that will construct a copy of this value at runtime.
+
+We can define our own `FromExpr`s like so:
+```scala
+given FromExpr[Boolean] with {
+ def unapply(x: Expr[Boolean])(using Quotes): Option[Boolean] =
+ x match
+ case '{ true } => Some(true)
+ case '{ false } => Some(false)
+ case _ => None
+}
+
+given FromExpr[StringContext] with {
+ def unapply(x: Expr[StringContext])(using Quotes): Option[StringContext] = x match {
+ case '{ new StringContext(${Varargs(Exprs(args))}*) } => Some(StringContext(args*))
+ case '{ StringContext(${Varargs(Exprs(args))}*) } => Some(StringContext(args*))
+ case _ => None
+ }
+}
+```
+Note that we handled two cases for `StringContext`.
+As it is a `case class`, it can be created with `new StringContext` or with `StringContext.apply` from the companion object.
+We also used the `Varargs` extractor to match the arguments of type `Expr[Seq[String]]` into a `Seq[Expr[String]]`.
+Then we used the `Exprs` to match known constants in the `Seq[Expr[String]]` to get a `Seq[String]`.
+
+
+## The Quotes
+The `Quotes` is the main entry point for the creation of all quotes.
+This context is usually just passed around through contextual abstractions (`using` and `?=>`).
+Each quote scope will have its own `Quotes`.
+New scopes are introduced each time a splice is introduced (`${ ... }`).
+Though it looks like a splice takes an expression as argument, it actually takes a `Quotes ?=> Expr[T]`.
+Therefore, we could actually write it explicitly as `${ (using q) => ... }`.
+This might be useful when debugging to avoid generated names for these scopes.
+
+The method `scala.quoted.quotes` provides a simple way to use the current `Quotes` without naming it.
+It is usually imported along with the `Quotes` using `import scala.quoted.*`.
+
+```scala
+${ (using q1) => body(using q1) }
+// equivalent to
+${ body(using quotes) }
+```
+Warning: If you explicitly name a `Quotes` `quotes`, you will shadow this definition.
+
+When we write a top-level splice in a macro, we are calling something similar to the following definition.
+This splice will provide the initial `Quotes` associated with the macro expansion.
+```scala
+def $[T](x: Quotes ?=> Expr[T]): T = ...
+```
+
+When we have a splice within a quote, the inner quote context will depend on the outer one.
+This link is represented using the `Quotes.Nested` type.
+Users of quotes will almost never need to use `Quotes.Nested`.
+These details are only useful for advanced macros that will inspect code and may encounter details of quotes and splices.
+
+```scala
+def f(using q1: Quotes) = '{
+ ${ (using q2: q1.Nested) ?=>
+ ...
+ }
+}
+```
+
+We can imagine that a nested splice is like the following method, where `ctx` is the context received by the surrounding quote.
+```scala
+def $[T](using q: Quotes)(x: q.Nested ?=> Expr[T]): T = ...
+```
+
+## β-reduction
+When we have a lambda applied to an argument in a quote `'{ ((x: Int) => x + x)(y) }`, we do not reduce it within the quote; the code is kept as-is.
+There is an optimisation that will β-reduce all lambdas directly applied to parameters to avoid the creation of a closure.
+This will not be visible from the quote's perspective.
+
+Sometimes it is useful to perform this β-reduction on the quotes directly.
+We provide the function `Expr.betaReduce[T]` that receives an `Expr[T]` and β-reduces if it contains a directly-applied lambda.
+
+```scala
+Expr.betaReduce('{ ((x: Int) => x + x)(y) }) // returns '{ val x = y; x + x }
+```
+
+
+## Summon values
+There are two ways to summon values in a macro.
+The first is to have a `using` parameter in the inline method that is passed explicitly to the macro implementation.
+
+```scala
+inline def setOf[T](using ord: Ordering[T]): Set[T] =
+ ${ setOfCode[T]('ord) }
+
+def setOfCode[T: Type](ord: Expr[Ordering[T]])(using Quotes): Expr[Set[T]] =
+ '{ TreeSet.empty[T](using $ord) }
+```
+
+In this scenario, the context parameter is found before the macro is expanded.
+If not found, the macro will not be expanded.
+
+The second way is using `Expr.summon`.
+This allows us to programatically search for distinct given expressions.
+The following example is similar to the previous example:
+
+```scala
+inline def setOf[T]: Set[T] =
+ ${ setOfCode[T] }
+
+def setOfCode[T: Type](using Quotes): Expr[Set[T]] =
+ Expr.summon[Ordering[T]] match
+ case Some(ord) => '{ TreeSet.empty[T](using $ord) }
+ case _ => '{ HashSet.empty[T] }
+```
+
+The difference is that, in the second scenario, we expand the macro before the implicit search is performed. We can therefore write arbitrary code to handle the case when an `Ordering[T]` is not found.
+Here, we used `HashSet` instead of `TreeSet` because the former does not need an `Ordering`.
+
+## Quoted Type Classes
+
+In the previous example we showed how to use the `Expr[Ordering[T]]` type class explicitly by leveraging the `using` argument clause. This is perfectly fine, but it is not very convenient if we need to use the type class multiple times. To show this we will
+use a `powerCode` function that can be used on any numeric type.
+
+First, it can be useful to make `Expr` type class can make it a given parameter. To do this we do need to explicitly in `power` to `powerCode` because we have a given `Numeric[Num]` but require an `Expr[Numeric[Num]]`. But then we can ignore it in `powerMacro` and any other place that only passes it around.
+
+```scala
+inline def power[Num](x: Num, inline n: Int)(using num: Numeric[Num]) =
+ ${ powerMacro('x, 'n)(using 'num) }
+
+def powerMacro[Num: Type](x: Expr[Num], n: Expr[Int])(using Expr[Numeric[Num]])(using Quotes): Expr[Num] =
+ powerCode(x, n.valueOrAbort)
+```
+
+To use a this type class we need a given `Numeric[Num]` but we have a `Expr[Numeric[Num]]` and therefore we need to splice this expression in the generated code. To make it available we can just splice it in a given definition.
+
+```scala
+def powerCode[Num: Type](x: Expr[Num], n: Int)(using num: Expr[Numeric[Num]])(using Quotes): Expr[Num] =
+ if (n == 0) '{ $num.one }
+ else if (n % 2 == 0) '{
+ given Numeric[Num] = $num
+ val y = $x * $x
+ ${ powerCode('y, n / 2) }
+ }
+ else '{
+ given Numeric[Num] = $num
+ $x * ${ powerCode(x, n - 1) }
+ }
+```
+
+
+
+[macros]: {% link _overviews/scala3-macros/tutorial/macros.md %}
+[quotes]: {% link _overviews/scala3-macros/tutorial/quotes.md %}
diff --git a/_overviews/scala3-macros/tutorial/reflection.md b/_overviews/scala3-macros/tutorial/reflection.md
new file mode 100644
index 0000000000..46618a1d4f
--- /dev/null
+++ b/_overviews/scala3-macros/tutorial/reflection.md
@@ -0,0 +1,235 @@
+---
+type: section
+title: Reflection
+num: 6
+
+previous-page: quotes
+---
+
+The reflection API provides a more complex and comprehensive view on the structure of the code.
+It provides a view of *Typed Abstract Syntax Trees* and their properties such as types, symbols, positions and comments.
+
+The API can be used in macros as well as for [inspecting TASTy files][tasty inspection].
+
+## How to use the API
+
+The reflection API is defined in the type `Quotes` as `reflect`.
+The actual instance depends on the current scope, in which quotes or quoted pattern matching is used.
+Hence, every macro method receives Quotes as an additional argument.
+Since `Quotes` is contextual, to access its members we either need to name the parameter or summon it.
+The following definition from the standard library details the canonical way of accessing it:
+
+```scala
+package scala.quoted
+
+transparent inline def quotes(using inline q: Quotes): q.type = q
+```
+
+We can use `scala.quoted.quotes` to import the current `Quotes` in scope:
+
+```scala
+import scala.quoted.* // Import `quotes`, `Quotes`, and `Expr`
+
+def f(x: Expr[Int])(using Quotes): Expr[Int] =
+ import quotes.reflect.* // Import `Tree`, `TypeRepr`, `Symbol`, `Position`, .....
+ val tree: Tree = ...
+ ...
+```
+
+This will import all the types and modules (with extension methods) of the API.
+
+## How to navigate the API
+
+The full API can be found in the [API documentation for `scala.quoted.Quotes.reflectModule`][reflection doc].
+Unfortunately, at this stage, this automatically-generated documentation is not very easy to navigate.
+
+The most important element on the page is the hierarchy tree which provides a synthetic overview of the subtyping relationships of
+the types in the API. For each type `Foo` in the tree:
+
+ - the trait `FooMethods` contains the methods available on the type `Foo`
+ - the trait `FooModule` contains the static methods available on the object `Foo`.
+Most notably, constructors (`apply/copy`) and the `unapply` method which provides the extractor(s) required for pattern matching are found here
+ - For all types `Upper` such that `Foo <: Upper`, the methods defined in `UpperMethods` are also available on `Foo`
+
+For example, [`TypeBounds`](https://scala-lang.org/api/3.x/scala/quoted/Quotes$reflectModule.html#TypeBounds-0), a subtype of `TypeRepr`, represents a type tree of the form `T >: L <: U`: a type `T` which is a super type of `L`
+and a subtype of `U`. In [`TypeBoundsMethods`](https://scala-lang.org/api/3.x/scala/quoted/Quotes$reflectModule$TypeBoundsMethods.html), you will find the methods `low` and `hi`, which allow you to access the
+representations of `L` and `U`. In [`TypeBoundsModule`](https://scala-lang.org/api/3.x/scala/quoted/Quotes$reflectModule$TypeBoundsModule.html), you will find the `unapply` method, which allows you to write:
+
+```scala
+def f(tpe: TypeRepr) =
+ tpe match
+ case TypeBounds(l, u) =>
+```
+
+Because `TypeBounds <: TypeRepr`, all the methods defined in `TypeReprMethods` are available on `TypeBounds` values:
+
+```scala
+def f(tpe: TypeRepr) =
+ tpe match
+ case tpe: TypeBounds =>
+ val low = tpe.low
+ val hi = tpe.hi
+```
+
+## Relation with Expr/Type
+
+### Expr and Term
+
+Expressions (`Expr[T]`) can be seen as wrappers around a `Term`, where `T` is the statically-known type of the term.
+Below, we use the extension method `asTerm` to transform an expression into a term.
+This extension method is only available after importing `quotes.reflect.asTerm`.
+Then we use `asExprOf[Int]` to transform the term back into `Expr[Int]`.
+This operation will fail if the term does not have the provided type (in this case, `Int`) or if the term is not a valid expression.
+For example, an `Ident(fn)` is an invalid term if the method `fn` takes type parameters, in which case we would need an `Apply(Ident(fn), args)`.
+
+```scala
+def f(x: Expr[Int])(using Quotes): Expr[Int] =
+ import quotes.reflect.*
+ val tree: Term = x.asTerm
+ val expr: Expr[Int] = tree.asExprOf[Int]
+ expr
+```
+
+### Type and TypeRepr
+
+Similarly, we can also see `Type[T]` as a wrapper over `TypeRepr`, with `T` being the statically-known type.
+To get a `TypeRepr`, we use `TypeRepr.of[T]`, which expects a given `Type[T]` in scope (similar to `Type.of[T]`).
+We can also transform it back into a `Type[?]` using the `asType` method.
+As the type of `Type[?]` is not statically known, we need to name it with an existential type to use it. This can be achieved using the `'[t]` pattern.
+
+```scala
+def g[T: Type](using Quotes) =
+ import quotes.reflect.*
+ val tpe: TypeRepr = TypeRepr.of[T]
+ tpe.asType match
+ case '[t] => '{ val x: t = ${...} }
+ ...
+```
+
+## Symbols
+
+The APIs of `Term` and `TypeRepr` are relatively *closed* in the sense that methods produce and accept values whose types are defined in the API.
+However, you might notice the presence of `Symbol`s which identify definitions.
+
+Both `Term`s and `TypeRepr`s (and therefore `Expr`s and `Type`s) have an associated symbol.
+`Symbol`s make it possible to compare two definitions using `==` to know if they are the same.
+In addition, `Symbol` exposes and is used by many useful methods. For example:
+
+ - `declaredFields` and `declaredMethods` allow you to iterate on the fields and members defined inside a symbol
+ - `flags` allows you to check multiple properties of a symbol
+ - `companionClass` and `companionModule` provide a way to jump to and from the companion object/class
+ - `TypeRepr.baseClasses` returns the list of symbols of classes extended by a type
+ - `Symbol.pos` gives you access to the position where the symbol is defined, the source code of the definition, and even the filename where the symbol is defined
+ - many others that you can find in [`SymbolMethods`](https://scala-lang.org/api/3.x/scala/quoted/Quotes$reflectModule$SymbolMethods.html)
+
+### To Symbol and back
+
+Consider an instance of the type `TypeRepr` named `val tpe: TypeRepr = ...`. Then:
+
+ - `tpe.typeSymbol` returns the symbol of the type represented by `TypeRepr`. The recommended way to obtain a `Symbol` given a `Type[T]` is `TypeRepr.of[T].typeSymbol`
+ - For a singleton type, `tpe.termSymbol` returns the symbol of the underlying object or value
+ - `tpe.memberType(symbol)` returns the `TypeRepr` of the provided symbol
+ - On objects `t: Tree`, `t.symbol` returns the symbol associated with a tree.
+ Given that `Term <: Tree`, `Expr.asTerm.symbol` is the best way to obtain the symbol associated with an `Expr[T]`
+ - On objects `sym: Symbol`, `sym.tree` returns the `Tree` associated to the symbol.
+Be careful when using this method as the tree for a symbol might not be defined.
+Read more on the [best practices page][best practices]
+
+## Macro API design
+
+It will often be useful to create helper methods or extractors that perform some common logic of your macros.
+
+The simplest methods will be those that only mention `Expr`, `Type`, and `Quotes` in their signature.
+Internally, they may use reflection, but this will not be seen at the use site of the method.
+
+```scala
+def f(x: Expr[Int])(using Quotes): Expr[Int] =
+ import quotes.reflect.*
+ ...
+```
+
+In some cases, it may be inevitable that some methods will expect or return `Tree`s or other types in `quotes.reflect`.
+For these cases, the best practice is to follow the following method signature examples:
+
+A method that takes a `quotes.reflect.Term` parameter
+```scala
+def f(using Quotes)(term: quotes.reflect.Term): String =
+ import quotes.reflect.*
+ ...
+```
+
+An extension method for a `quotes.reflect.Term` returning a `quotes.reflect.Tree`
+```scala
+extension (using Quotes)(term: quotes.reflect.Term)
+ def g: quotes.reflect.Tree = ...
+```
+
+An extractor that matches on `quotes.reflect.Term`s
+```scala
+object MyExtractor:
+ def unapply(using Quotes)(x: quotes.reflect.Term) =
+ ...
+ Some(y)
+```
+
+> **Avoid saving the `Quotes` context in a field.**
+> `Quotes` in fields inevitably make its use harder by causing errors involving `Quotes` with different paths.
+>
+> Usually, these patterns have been seen in code that uses the Scala 2 ways to define extension methods or contextual unapplies.
+> Now that we have `given` parameters that can be added before other parameters, all these old workarounds are not needed anymore.
+> The new abstractions make it simpler both at the definition site and at the use site.
+
+## Debugging
+
+### Runtime checks
+
+Expressions (`Expr[T]`) can be seen as wrappers around a `Term`, where `T` is the statically-known type of the term.
+Hence, these checks will be done at runtime (i.e. compile-time when the macro expands).
+
+It is recommended to enable the `-Xcheck-macros` flag while developing macros or on the tests for the macro.
+This flag will enable extra runtime checks that will try to find ill-formed trees or types as soon as they are created.
+
+There is also the `-Ycheck:all` flag that checks all compiler invariants for tree well-formedness.
+These checks will usually fail with an assertion error.
+
+### Printing the trees
+
+The `toString` methods on types in the `quotes.reflect` package are not great for debugging as they show the internal representation rather than the `quotes.reflect` representation.
+In many cases these are similar, but they may sometimes lead the debugging process astray, so they shouldn't be relied on.
+
+Instead, `quotes.reflect.Printers` provides a set of useful printers for debugging.
+Notably the `TreeStructure`, `TypeReprStructure`, and `ConstantStructure` classes can be quite useful.
+These will print the tree structure following loosely the extractors that would be needed to match it.
+
+```scala
+val tree: Tree = ...
+println(tree.show(using Printer.TreeStructure))
+```
+
+One of the most useful places where this can be added is at the end of a pattern match on a `Tree`.
+
+```scala
+tree match
+ case Ident(_) =>
+ case Select(_, _) =>
+ ...
+ case _ =>
+ throw new MatchError(tree.show(using Printer.TreeStructure))
+```
+This way, if a case is missed the error will report a familiar structure that can be copy-pasted to start fixing the issue.
+
+You can make this printer the default if desired:
+```scala
+ import quotes.reflect.*
+ given Printer[Tree] = Printer.TreeStructure
+ ...
+ println(tree.show)
+```
+
+## More
+*Coming soon*
+
+[tasty inspection]: {{ site.scala3ref }}/metaprogramming/tasty-inspect.html
+[reflection doc]: https://scala-lang.org/api/3.x/scala/quoted/Quotes$reflectModule.html
+
+[best practices]: {% link _overviews/scala3-macros/best-practices.md %}
diff --git a/_overviews/scala3-migration/compatibility-classpath.md b/_overviews/scala3-migration/compatibility-classpath.md
new file mode 100644
index 0000000000..6b25280994
--- /dev/null
+++ b/_overviews/scala3-migration/compatibility-classpath.md
@@ -0,0 +1,141 @@
+---
+title: Classpath Level
+type: section
+description: This section describes the compatibility between Scala 2.13 and Scala 3 class files.
+num: 3
+previous-page: compatibility-source
+next-page: compatibility-runtime
+---
+
+In your code you can use public types and terms, and call public methods that are defined in a different module or library.
+It works well as long as the type checker, which is the compiler phase that validates the semantic consistency of the code, is able to read the signatures of those types, terms and methods, from the class files containing them.
+
+In Scala 2 the signatures are stored in a dedicated format called the Pickle format.
+In Scala 3 the story is a bit different because it relies on the TASTy format which is a lot more than a signature layout.
+But, for the purpose of moving from Scala 2.13 to Scala 3, only the signatures are useful.
+
+## The Scala 3 Unpickler
+
+The first piece of good news is that the Scala 3 compiler is able to read the Scala 2.13 Pickle format and thus it can type check code that depends on modules or libraries compiled with Scala 2.13.
+
+The Scala 3 unpickler has been extensively tested in the community build for many years now. It is safe to use.
+
+### A Scala 3 module can depend on a Scala 2.13 artifact
+
+
+
+As an sbt build, it looks like this:
+
+```scala
+// build.sbt (sbt 1.5 or higher)
+lazy val foo = project.in(file("foo"))
+ .settings(scalaVersion := "3.3.1")
+ .dependsOn(bar)
+
+lazy val bar = project.in(file("bar"))
+ .settings(scalaVersion := "2.13.11")
+```
+
+Or, in case bar is a published Scala 2.13 library, we can have:
+
+```scala
+lazy val foo = project.in(file("foo"))
+ .settings(
+ scalaVersion := "3.3.1",
+ libraryDependencies += ("org.bar" %% "bar" % "1.0.0").cross(CrossVersion.for3Use2_13)
+ )
+```
+
+We use `CrossVersion.for3Use2_13` in sbt to resolve `bar_2.13` instead of `bar_3`.
+
+### The Standard Library
+
+One notable example is the Scala 2.13 library.
+We have indeed decided that the Scala 2.13 library is the official standard library for Scala 3.
+
+Let's note that the standard library is automatically provided by the build tool, you should not need to configure it manually.
+
+## The Scala 2.13 TASTy Reader
+
+The second piece of good news is that Scala 2.13 can consume Scala 3 libraries with `-Ytasty-reader`.
+
+### Supported Features
+
+The TASTy reader supports all the traditional language features as well as the following Scala 3 features:
+- [Enumerations]({{ site.scala3ref }}/enums/enums.html)
+- [Intersection Types]({{ site.scala3ref }}/new-types/intersection-types.html)
+- [Opaque Type Aliases]({{ site.scala3ref }}/other-new-features/opaques.html)
+- [Type Lambdas]({{ site.scala3ref }}/new-types/type-lambdas.html)
+- [Contextual Abstractions]({{ site.scala3ref }}/contextual) (new syntax)
+- [Open Classes]({{ site.scala3ref }}/other-new-features/open-classes.html) (and inheritance of super traits)
+- [Export Clauses]({{ site.scala3ref }}/other-new-features/export.html)
+
+It partially supports:
+- [Top-Level Definitions]({{ site.scala3ref }}/dropped-features/package-objects.html)
+- [Extension Methods]({{ site.scala3ref }}/contextual/extension-methods.html)
+
+It does not support the more advanced features:
+- [Context Functions]({{ site.scala3ref }}/contextual/context-functions.html)
+- [Polymorphic Function Types]({{ site.scala3ref }}/new-types/polymorphic-function-types.html)
+- [Trait Parameters]({{ site.scala3ref }}/other-new-features/trait-parameters.html)
+- `@static` Annotation
+- `@alpha` Annotation
+- [Functions and Tuples larger than 22 parameters]({{ site.scala3ref }}/dropped-features/limit22.html)
+- [Match Types]({{ site.scala3ref }}/new-types/match-types.html)
+- [Union Types]({{ site.scala3ref }}/new-types/union-types.html)
+- [Multiversal Equality]({{ site.scala3ref }}/contextual/multiversal-equality.html) (unless explicit)
+- [Inline]({{ site.scala3ref }}/metaprogramming/inline.html) (including Scala 3 macros)
+- [Kind Polymorphism]({{ site.scala3ref }}/other-new-features/kind-polymorphism.html) (the `scala.AnyKind` upper bound)
+
+### A Scala 2.13 module can depend on a Scala 3 artifact
+
+By enabling the TASTy reader with `-Ytasty-reader`, a Scala 2.13 module can depend on a Scala 3 artifact.
+
+
+
+As an sbt build, it looks like this:
+
+```scala
+// build.sbt (sbt 1.5 or higher)
+lazy val foo = project.in.file("foo")
+ .settings(
+ scalaVersion := "2.13.11",
+ scalacOptions += "-Ytasty-reader"
+ )
+ .dependsOn(bar)
+
+lazy val bar = project.in(file("bar"))
+ .settings(scalaVersion := "3.3.1")
+```
+
+Or, in case `bar` is a published Scala 3 library:
+
+```scala
+lazy val foo = project.in.file("foo")
+ .settings(
+ scalaVersion := "2.13.11",
+ scalacOptions += "-Ytasty-reader",
+ libraryDependencies += ("org.bar" %% "bar" % "1.0.0").cross(CrossVersion.for2_13Use3)
+ )
+```
+
+Similarly to `CrossVersion.for2_13Use3`, we use `CrossVersion.for3Use2_13` in sbt to resolve `bar_3` instead of `bar_2.13`.
+
+## Interoperability Overview
+
+In short, we have backward and forward compatibility and so **migration can happen gradually**.
+
+You can port a big Scala application one module at a time, even if its library dependencies have not yet been ported (excepting the macro libraries).
+
+During the transition period, you can have a Scala 3 module layered in between two 2.13 modules.
+
+
+
+This is permitted as long as all libraries are resolved to a single binary version: you can have `lib-foo_3` and `lib-bar_2.13` in the same classpath, but you cannot have `lib-foo_3` and `lib-foo_2.13`.
+
+The inverted pattern, with a 2.13 module in the middle, is also possible.
+
+> #### Disclaimer for library maintainers
+>
+> Unless you know exactly what you are doing, it is discouraged to publish a Scala 3 library that depends on a Scala 2.13 library (the scala-library being excluded) or vice versa.
+> The reason is to prevent library users from ending up with two conflicting versions `foo_2.13` and `foo_3` of the same foo library in their classpath, this problem being unsolvable in some cases.
diff --git a/_overviews/scala3-migration/compatibility-intro.md b/_overviews/scala3-migration/compatibility-intro.md
new file mode 100644
index 0000000000..b511567a2b
--- /dev/null
+++ b/_overviews/scala3-migration/compatibility-intro.md
@@ -0,0 +1,36 @@
+---
+title: Compatibility Reference
+type: chapter
+description: This chapter describes the compatibility between Scala 2.13 and Scala 3.
+num: 1
+previous-page:
+next-page: compatibility-source
+---
+
+Scala 3 is a game changer in terms of compatibility in the Scala ecosystem that will greatly improve the day-to-day experience of every Scala programmer.
+This new compatibility era starts with the migration.
+
+Moving from Scala 2 to Scala 3 is a big leap forward.
+Scala 3 is a shiny new compiler, built upon a complete redesign of the core foundations of the language.
+Yet we claim the migration will not be harder than before, when we moved from Scala 2.12 to Scala 2.13.
+
+It will even be simpler in some respects, thanks to the interoperability between Scala 2.13 and Scala 3.
+
+This chapter details the level of compatibility between the two versions at the different stages of the program.
+This is where you will find answers to the following questions:
+
+**[Source Level](compatibility-source.html)**
+- Is Scala 3 a different language?
+- How hard is it to translate a Scala 2.13 project into Scala 3?
+
+**[Classpath Level](compatibility-classpath.html)**
+- Can we use a Scala 2.13 library in Scala 3?
+- Inversely, can we use a Scala 3 library in Scala 2.13?
+
+**[Runtime](compatibility-runtime.html)**
+- Is it safe to deploy a Scala 3 program in a production environment?
+- How fast are Scala 3 programs compared to Scala 2.13?
+
+**[Metaprogramming](compatibility-metaprogramming.html)**
+- Will my Scala 2.13 project be affected by the replacement of the Scala 2 macro feature?
+- How can I port my Scala 2.13 macro library to Scala 3?
diff --git a/_overviews/scala3-migration/compatibility-metaprogramming.md b/_overviews/scala3-migration/compatibility-metaprogramming.md
new file mode 100644
index 0000000000..675f5fc4a3
--- /dev/null
+++ b/_overviews/scala3-migration/compatibility-metaprogramming.md
@@ -0,0 +1,89 @@
+---
+title: Metaprogramming
+type: section
+description: This section discuss the metaprogramming transition
+num: 5
+previous-page: compatibility-runtime
+next-page: tooling-tour
+---
+
+A call to a macro method is executed during the compiler phase called macro expansion to generate a part of the program---an abstract syntax tree.
+
+The Scala 2.13 macro API is closely tied to the Scala 2.13 compiler internals.
+Therefore it is not possible for the Scala 3 compiler to expand any Scala 2.13 macro.
+
+In contrast, Scala 3 introduces a new principled approach of metaprogramming that is designed for stability.
+Scala 3 macros, and inline methods in general, will be compatible with future versions of the Scala 3 compiler.
+While this is an uncontested improvement, it also means that all Scala 2.13 macros have to be rewritten from the ground up, using the new metaprogramming features.
+
+## Macro Dependencies
+
+A Scala 3 module can depend on a Scala 2.13 artifact even if it contains a macro definition but the compiler will not be able to expand its macros.
+When you try to, it simply returns an error.
+
+{% highlight text %}
+ -- Error: /src/main/scala/example/Example.scala:10:45
+ 10 | val documentFormat = Json.format[Document]
+ | ^
+ |Scala 2 macro cannot be used in Scala 3. See https://dotty.epfl.ch/docs/reference/dropped-features/macros.html
+ |To turn this error into a warning, pass -Xignore-scala2-macros to the compiler
+{% endhighlight %}
+
+Let's note that using `-Xignore-scala2-macros` is helpful to type check the code but it produces incomplete class files.
+
+When this error appears in your project, you have eventually no other choice than upgrading to a Scala 3-compiled version of the macro artifact.
+
+## Porting the Macro Ecosystem
+
+While being experimental, the Scala community has largely adopted the Scala 2 macro feature in multiple ways: code generation, optimizations, ergonomic DSLs...
+
+A large part of the ecosystem now depends on Scala 2.13 macros defined in external libraries.
+Identifying and porting those libraries is key to move the ecosystem forward.
+
+A migration status of many open-source macro libraries is available in [this page](https://scalacenter.github.io/scala-3-migration-guide/docs/macros/macro-libraries.html).
+
+## Rewriting a Macro
+
+The new metaprogramming features are completely different from Scala 2.
+They are comprised of:
+- [Inline Methods][inline]
+- [Compile-time operations][compiletime]
+- [Macros][macros]
+- [Quoted code][quotes]
+- [Reflection over Abstract Syntax Trees (AST)][reflection]
+
+Before getting deep into reimplementing a macro you should ask yourself:
+- Can I use `inline` and the `scala.compiletime` operations to reimplement my logic?
+- Can I use the simpler and safer expression-based macros?
+- Do I really need to access the AST?
+- Can I use a [match type]({{ site.scala3ref }}/new-types/match-types.html) as return type?
+
+You can learn all the new metaprogramming concepts by reading the [Macros in Scala 3][scala3-macros] tutorial.
+
+## Cross-building a Macro Library
+
+You have written a wonderful macro library and you would like it to be available in Scala 2.13 and Scala 3.
+There are two different approaches, the traditional cross-building technique and the more flexible macro mixing technique.
+
+The benefit of macro mixing is that consumers who take advantage of the `-Ytasty-reader` option can still use your macros.
+
+You can learn about them by reading these tutorials:
+- [Cross-Building a Macro Library](tutorial-macro-cross-building.html)
+- [Mixing Scala 2.13 and Scala 3 Macros](tutorial-macro-mixing.html)
+
+## Additional Resources
+
+Blog posts and talks:
+- [Macros: The Plan For Scala 3](https://www.scala-lang.org/blog/2018/04/30/in-a-nutshell.html)
+- [Scala Days - Metaprogramming in Dotty](https://www.youtube.com/watch?v=ZfDS_gJyPTc)
+
+Early-adopter projects:
+- [XML Interpolator](https://github.com/dotty-staging/xml-interpolator/tree/master)
+- [Shapeless 3](https://github.com/dotty-staging/shapeless/tree/shapeless-3)
+
+[inline]: {% link _overviews/scala3-macros/tutorial/inline.md %}
+[compiletime]: {% link _overviews/scala3-macros/tutorial/compiletime.md %}
+[macros]: {% link _overviews/scala3-macros/tutorial/macros.md %}
+[quotes]: {% link _overviews/scala3-macros/tutorial/quotes.md %}
+[reflection]: {% link _overviews/scala3-macros/tutorial/reflection.md %}
+[scala3-macros]: {% link _overviews/scala3-macros/tutorial/index.md %}
diff --git a/_overviews/scala3-migration/compatibility-runtime.md b/_overviews/scala3-migration/compatibility-runtime.md
new file mode 100644
index 0000000000..729faae7aa
--- /dev/null
+++ b/_overviews/scala3-migration/compatibility-runtime.md
@@ -0,0 +1,28 @@
+---
+title: Runtime
+type: section
+description: This section describes the run-time characteristics of a Scala 3 program.
+num: 4
+previous-page: compatibility-classpath
+next-page: compatibility-metaprogramming
+---
+
+Scala 2.13 and Scala 3 share the same Application Binary Interface (ABI).
+
+> The ABI is the representation of Scala code in bytecode or Scala.js IR.
+> It determines the run-time behavior of Scala programs.
+
+Compiling the same source code with Scala 2.13 and Scala 3 produces very similar bytecodes.
+The difference being that some features have changed, for instance the initialization of lazy vals has been improved.
+
+Sharing the ABI also ensures that Scala 2.13 and Scala 3 class files can be loaded by the same JVM class loader.
+Similarly, that Scala 2.13 and Scala 3 `sjsir` files can be linked together by the Scala.js linker.
+
+Furthermore it relieves us from surprising behaviors at runtime.
+It makes the migration from Scala 2.13 to Scala 3 very safe in terms of run-time crashes and performance.
+
+At first sight the run-time characteristics of a Scala program is neither better nor worse in Scala 3 compare to Scala 2.13.
+However some new features will help you optimize your program:
+- [Opaque Type Aliases](http://dotty.epfl.ch/docs/reference/other-new-features/opaques.html)
+- [Inline Methods](http://dotty.epfl.ch/docs/reference/metaprogramming/inline.html)
+- [@threadUnsafe annotation](http://dotty.epfl.ch/docs/reference/other-new-features/threadUnsafe-annotation.html)
diff --git a/_overviews/scala3-migration/compatibility-source.md b/_overviews/scala3-migration/compatibility-source.md
new file mode 100644
index 0000000000..b3e4ad5c41
--- /dev/null
+++ b/_overviews/scala3-migration/compatibility-source.md
@@ -0,0 +1,28 @@
+---
+title: Source Level
+type: section
+description: This section describes the level of compatibility between Scala 2.13 and Scala 3 sources.
+num: 2
+previous-page: compatibility-intro
+next-page: compatibility-classpath
+---
+
+Scala 3 is an improved version of the Scala 2 language.
+
+Despite the new syntax, a very large subset of the Scala 2.13 language is still valid.
+Not all of it though, some constructs have been simplified, restricted or dropped altogether.
+However those decisions were made for good reasons and by taking care that a good workaround is possible.
+
+In general there is a straightforward cross-compiling solution to every incompatibility, so that the migration from Scala 2.13 to Scala 3 is easy and smooth.
+You can find a corpus of incompatibilities in the [Incompatibility Table](incompatibility-table.html).
+
+There is an exception though, which is the new metaprogramming framework that replaces the Scala 2 experimental macros.
+Further explanations are given at the end of this chapter in the [Metaprogramming](compatibility-metaprogramming.html) section.
+
+Metaprogramming aside, a Scala 2.13 source code can rather easily be ported to Scala 3.
+Once done, you will be able to use the new powerful features of Scala 3, which have no equivalent in Scala 2.
+The downside is those sources cannot be compiled with Scala 2.13 anymore.
+But amazingly, this new Scala 3 artifact can be consumed as a dependency in Scala 2.13.
+
+As we will see in more detail, it permits backward and forward compatibility.
+This is a breakthrough in the history of the Scala programming language.
diff --git a/_overviews/scala3-migration/external-resources.md b/_overviews/scala3-migration/external-resources.md
new file mode 100644
index 0000000000..1055f4bc95
--- /dev/null
+++ b/_overviews/scala3-migration/external-resources.md
@@ -0,0 +1,34 @@
+---
+title: External Resources
+type: chapter
+description: This section lists external resources about the migration to Scala 3.
+num: 29
+previous-page: plugin-kind-projector
+next-page:
+---
+
+## Courses
+
+### Lunatech's [_Moving from Scala 2 to Scala 3_](https://github.com/lunatech-labs/lunatech-scala-2-to-scala3-course)
+
+If you're a Scala 2 application developer who's looking at getting up-to-speed on Scala 3 or who's considering a migration of an existing Scala 2 application to Scala 3, Lunatech's [_"Moving from Scala 2 to Scala 3"_](https://github.com/lunatech-labs/lunatech-scala-2-to-scala3-course) course is a good way to get started.
+
+This course guides you through a migration of a single-module Akka Typed Sudoku solver in a series of about 10 steps. It covers the practical application of the following Scala 3 features:
+
+- New Control Structure syntax
+- Indentation Based syntax
+- Syntax rewriting by the Scala 3 compiler
+- Top Level definitions
+- Parameter untupling
+- Contextual Abstractions:
+ - Extension methods new syntax
+ - Given instances and Using clauses
+- Enumerations and Export clauses
+- Intersection and Union Types
+- Opaque Type Aliases
+- Multiversal Equality
+
+## Talks
+
+- [Scala 3: Python 3 or Easiest Upgrade Ever?](https://www.youtube.com/watch?v=jWJ5A1irH_E) by Daniel Spiewak (Weehawken-Lang)
+- [Taste the difference with Scala 3: Migrating the ecosystem and more](https://www.youtube.com/watch?v=YQmVrUdx8TU) by Jamie Thompson (f(by) 2020)
diff --git a/_overviews/scala3-migration/incompat-contextual-abstractions.md b/_overviews/scala3-migration/incompat-contextual-abstractions.md
new file mode 100644
index 0000000000..ea5947f2e4
--- /dev/null
+++ b/_overviews/scala3-migration/incompat-contextual-abstractions.md
@@ -0,0 +1,150 @@
+---
+title: Contextual Abstractions
+type: section
+description: This chapter details all incompatibilities caused by the redesign of contextual abstractions
+num: 19
+previous-page: incompat-dropped-features
+next-page: incompat-other-changes
+---
+
+The redesign of [contextual abstractions]({{ site.scala3ref }}/contextual) brings some incompatibilities.
+
+|Incompatibility|Scala 2.13|Scala 3 Migration Rewrite|Scalafix Rule|Runtime Incompatibiltiy|
+|--- |--- |--- |--- |--- |
+|[Type of implicit def](#type-of-implicit-definition)|||[✅](https://scalacenter.github.io/scalafix/docs/rules/ExplicitResultTypes.html)||
+|[Implicit views](#implicit-views)||||**Possible**|
+|[View bounds](#view-bounds)|Deprecation||||
+|[Ambiguous conversion on `A` and `=> A`](#ambiguous-conversion-on-a-and--a)|||||
+
+## Type Of Implicit Definition
+
+The type of implicit definitions (`val` or `def`) needs to be given explicitly in Scala 3.
+They cannot be inferred anymore.
+
+The Scalafix rule named [ExplicitResultTypes](https://scalacenter.github.io/scalafix/docs/rules/ExplicitResultTypes.html) can write the missing type annotations automatically.
+
+## Implicit Views
+
+Scala 3 does not support implicit conversion from an implicit function value, of the form `implicit val ev: A => B`.
+
+{% tabs scala-2-implicit_1 %}
+{% tab 'Scala 2 Only' %}
+
+The following piece of code is now invalid in Scala 3:
+~~~ scala
+trait Pretty {
+ val print: String
+}
+
+def pretty[A](a: A)(implicit ev: A => Pretty): String =
+ a.print // In Scala 3, Error: value print is not a member of A
+~~~
+{% endtab %}
+{% endtabs %}
+
+The [Scala 3 migration compilation](tooling-migration-mode.html) can warn you about those cases, but it does not try to fix it.
+
+Be aware that this incompatibility can produce a runtime incompatibility and break your program.
+Indeed the compiler can find another implicit conversion from a broader scope, which would eventually cause an undesired behavior at runtime.
+
+{% tabs shared-implicit_2 %}
+{% tab 'Scala 2 and 3' %}
+
+This example illustrates the case:
+~~~ scala
+trait Pretty {
+ val print: String
+}
+
+implicit def anyPretty(any: Any): Pretty = new Pretty { val print = "any" }
+
+def pretty[A](a: A)(implicit ev: A => Pretty): String =
+ a.print // always print "any"
+~~~
+{% endtab %}
+{% endtabs %}
+
+The resolved conversion depends on the compiler mode:
+ - `-source:3.0-migration`: the compiler performs the `ev` conversion
+ - `-source:3.0`: the compiler cannot perform the `ev` conversion but it can perform the `anyPretty`, which is undesired
+
+In Scala 3, one simple fix is to supply the right conversion explicitly:
+
+{% highlight diff %}
+def pretty[A](a: A)(implicit ev: A => Pretty): String =
+- a.print
++ ev(a).print
+{% endhighlight %}
+
+## View Bounds
+
+View bounds have been deprecated for a long time but they are still supported in Scala 2.13.
+They cannot be compiled with Scala 3 anymore.
+
+{% tabs scala-2-bounds_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+def foo[A <% Long](a: A): Long = a
+~~~
+{% endtab %}
+{% endtabs %}
+
+In this example, in Scala 3, we get this following error message:
+
+{% highlight text %}
+-- Error: src/main/scala/view-bound.scala:2:12
+2 | def foo[A <% Long](a: A): Long = a
+ | ^
+ | view bounds `<%' are deprecated, use a context bound `:' instead
+{% endhighlight %}
+
+The message suggests to use a context bound instead of a view bound but it would change the signature of the method.
+It is probably easier and safer to preserve the binary compatibility.
+To do so the implicit conversion must be declared and called explicitly.
+
+Be careful not to fall in the runtime incompatibility described above, in [Implicit Views](#implicit-views).
+
+{% highlight diff %}
+-def foo[A <% Long](a: A): Long = a
++def foo[A](a: A)(implicit ev: A => Long): Long = ev(a)
+{% endhighlight %}
+
+## Ambiguous Conversion On `A` And `=> A`
+
+In Scala 2.13 the implicit conversion on `A` wins over the implicit conversion on `=> A`.
+It is not the case in Scala 3 anymore, and leads to an ambiguous conversion.
+
+For instance, in this example:
+
+{% tabs scala-2-ambiguous_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+implicit def boolFoo(bool: Boolean): Foo = ???
+implicit def lazyBoolFoo(lazyBool: => Boolean): Foo = ???
+
+true.foo()
+~~~
+{% endtab %}
+{% endtabs %}
+
+The Scala 2.13 compiler chooses the `boolFoo` conversion but the Scala 3 compiler fails to compile.
+
+{% highlight text %}
+-- Error: src/main/scala/ambiguous-conversion.scala:4:19
+9 | true.foo()
+ | ^^^^
+ |Found: (true : Boolean)
+ |Required: ?{ foo: ? }
+ |Note that implicit extension methods cannot be applied because they are ambiguous;
+ |both method boolFoo in object Foo and method lazyBoolFoo in object Foo provide an extension method `foo` on (true : Boolean)
+{% endhighlight %}
+
+A temporary solution is to write the conversion explicitly.
+
+{% highlight diff %}
+implicit def boolFoo(bool: Boolean): Foo = ???
+implicit def lazyBoolFoo(lazyBool: => Boolean): Foo = ???
+
+-true.foo()
++boolFoo(true).foo()
+{% endhighlight %}
diff --git a/_overviews/scala3-migration/incompat-dropped-features.md b/_overviews/scala3-migration/incompat-dropped-features.md
new file mode 100644
index 0000000000..845a58b143
--- /dev/null
+++ b/_overviews/scala3-migration/incompat-dropped-features.md
@@ -0,0 +1,308 @@
+---
+title: Dropped Features
+type: section
+description: This chapter details all the dropped features
+num: 18
+previous-page: incompat-syntactic
+next-page: incompat-contextual-abstractions
+---
+
+Some features are dropped to simplify the language.
+Most of these changes can be handled automatically during the [Scala 3 migration compilation](tooling-migration-mode.html).
+
+|Incompatibility|Scala 2.13|Scala 3 Migration Rewrite|Scalafix Rule|
+|--- |--- |--- |--- |
+|[Symbol literals](#symbol-literals)|Deprecation|✅||
+|[`do`-`while` construct](#do-while-construct)||✅||
+|[Auto-application](#auto-application)|Deprecation|✅|[✅](https://github.com/scala/scala-rewrites/blob/main/rewrites/src/main/scala/fix/scala213/ExplicitNonNullaryApply.scala)|
+|[Value eta-expansion](#value-eta-expansion)|Deprecation|✅|[✅](https://github.com/scala/scala-rewrites/blob/main/rewrites/src/main/scala/fix/scala213/ExplicitNullaryEtaExpansion.scala)|
+|[`any2stringadd` conversion](#any2stringadd-conversion)|Deprecation||[✅](https://github.com/scala/scala-rewrites/blob/main/rewrites/src/main/scala/fix/scala213/Any2StringAdd.scala)|
+|[Early initializer](#early-initializer)|Deprecation|||
+|[Existential type](#existential-type)|Feature warning|||
+|[@specialized](#specialized)|Deprecation|||
+
+## Symbol literals
+
+The Symbol literal syntax is deprecated in Scala 2.13 and dropped in Scala 3.
+But the `scala.Symbol` class still exists so that each string literal can be safely replaced by an application of `Symbol`.
+
+This piece of code cannot be compiled with Scala 3:
+
+{% tabs scala-2-literals_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+val values: Map[Symbol, Int] = Map('abc -> 1)
+
+val abc = values('abc) // In Scala 3, Migration Warning: symbol literal 'abc is no longer supported
+~~~
+{% endtab %}
+{% endtabs %}
+
+The [Scala 3 migration compilation](tooling-migration-mode.html) rewrites the code into:
+{% highlight diff %}
+val values: Map[Symbol, Int] = Map(Symbol("abc") -> 1)
+
+-val abc = values('abc)
++val abc = values(Symbol("abc"))
+{% endhighlight %}
+
+Although the `Symbol` class is useful during the transition, beware that it is deprecated and will be removed from the `scala-library` in a future version.
+You are recommended, as a second step, to replace every use of `Symbol` with a plain string literals `"abc"` or a custom dedicated class.
+
+## `do`-`while` construct
+
+The `do` keyword has acquired a different meaning in the [New Control Syntax]({{ site.scala3ref }}/other-new-features/control-syntax.html).
+
+To avoid confusion, the traditional `do while ()` construct is dropped.
+It is recommended to use the equivalent `while ({ ; }) ()` that can be cross-compiled, or the new Scala 3 syntax `while { ; } do ()`.
+
+The following piece of code cannot be compiled with Scala 3.
+
+{% tabs scala-2-do_while_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+do { // In Scala 3, Migration Warning: `do while ` is no longer supported
+ i += 1
+} while (f(i) == 0)
+~~~
+{% endtab %}
+{% endtabs %}
+
+The [Scala 3 migration compilation](tooling-migration-mode.html) rewrites it into.
+{% tabs scala-3-do_while_2 %}
+{% tab 'Scala 3 Only' %}
+~~~ scala
+while ({ {
+ i += 1
+} ; f(i) == 0}) ()
+~~~
+{% endtab %}
+{% endtabs %}
+
+## Auto-application
+
+Auto-application is the syntax of calling an empty-paren method such as `def toInt(): Int` without passing an empty argument list.
+It is deprecated in Scala 2.13 and dropped in Scala 3.
+
+The following code is invalid in Scala 3:
+
+{% tabs scala-2-auto_application_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+object Hello {
+ def message(): String = "Hello"
+}
+
+println(Hello.message) // In Scala 3, Migration Warning: method message must be called with () argument
+~~~
+{% endtab %}
+{% endtabs %}
+
+The [Scala 3 migration compilation](tooling-migration-mode.html) rewrites it into:
+{% highlight diff %}
+object Hello {
+ def message(): String = "Hello"
+}
+
+-println(Hello.message)
++println(Hello.message())
+{% endhighlight %}
+
+Auto-application is covered in detail in [this page]({{ site.scala3ref }}/dropped-features/auto-apply.html) of the Scala 3 reference documentation.
+
+## Value eta-expansion
+
+Scala 3 introduces [Automatic Eta-Expansion]({{ site.scala3ref }}/changed-features/eta-expansion-spec.html) which will deprecate the method to value syntax `m _`.
+Furthermore Scala 3 does not allow eta-expansion of values to nullary functions anymore.
+
+Thus, this piece of code is invalid in Scala 3:
+
+{% tabs scala-2-eta_expansion_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+val x = 1
+val f: () => Int = x _ // In Scala 3, Migration Warning: The syntax ` _` is no longer supported;
+~~~
+{% endtab %}
+{% endtabs %}
+
+The [Scala 3 migration compilation](tooling-migration-mode.html) rewrites it into:
+{% highlight diff %}
+val x = 1
+-val f: () => Int = x _
++val f: () => Int = (() => x)
+{% endhighlight %}
+
+## `any2stringadd` conversion
+
+The implicit `Predef.any2stringadd` conversion is deprecated in Scala 2.13 and dropped in Scala 3.
+
+This piece of code does not compile anymore in Scala 3.
+
+{% tabs scala-2-any2stringadd_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+val str = new AnyRef + "foo" // In Scala 3, Error: value + is not a member of Object
+~~~
+{% endtab %}
+{% endtabs %}
+
+The conversion to `String` must be applied explicitly, for instance with `String.valueOf`.
+{% highlight diff %}
+-val str = new AnyRef + "foo"
++val str = String.valueOf(new AnyRef) + "foo"
+{% endhighlight %}
+
+This rewrite can be applied by the `fix.scala213.Any2StringAdd` Scalafix rule in [`scala/scala-rewrites`](https://index.scala-lang.org/scala/scala-rewrites/scala-rewrites/0.1.2?target=_2.13).
+
+## Early Initializer
+
+Early initializers are deprecated in Scala 2.13 and dropped in Scala 3.
+They were rarely used, and mostly to compensate for the lack of [Trait parameters]({{ site.scala3ref }}/other-new-features/trait-parameters.html) which are now supported in Scala 3.
+
+That is why the following piece of code does not compile anymore in Scala 3.
+
+{% tabs scala-2-initializer_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+trait Bar {
+ val name: String
+ val size: Int = name.size
+}
+
+object Foo extends {
+ val name = "Foo"
+} with Bar
+~~~
+{% endtab %}
+{% endtabs %}
+
+The Scala 3 compiler produces two error messages:
+
+{% highlight text %}
+-- Error: src/main/scala/early-initializer.scala:6:19
+6 |object Foo extends {
+ | ^
+ | `extends` must be followed by at least one parent
+{% endhighlight %}
+{% highlight text %}
+-- [E009] Syntax Error: src/main/scala/early-initializer.scala:8:2
+8 |} with Bar
+ | ^^^^
+ | Early definitions are not supported; use trait parameters instead
+{% endhighlight %}
+
+It suggests to use trait parameters which would give us:
+
+{% tabs scala-3-initializer_2 %}
+{% tab 'Scala 3 Only' %}
+~~~ scala
+trait Bar(name: String) {
+ val size: Int = name.size
+}
+
+object Foo extends Bar("Foo")
+~~~
+{% endtab %}
+{% endtabs %}
+
+Since trait parameters are not available in Scala 2.13, it does not cross-compile.
+If you need a cross-compiling solution you can use an intermediate class that carries the early initialized `val`s and `var`s as constructor parameters.
+
+{% tabs shared-initializer_4 %}
+{% tab 'Scala 2 and 3' %}
+~~~ scala
+abstract class BarEarlyInit(val name: String) extends Bar
+
+object Foo extends BarEarlyInit("Foo")
+~~~
+
+In the case of a class, it is also possible to use a secondary constructor with a fixed value, as shown by:
+~~~ scala
+class Fizz private (val name: String) extends Bar {
+ def this() = this("Fizz")
+}
+~~~
+{% endtab %}
+{% endtabs %}
+
+Another use case for early initializers in Scala 2 is private state in the subclass that is accessed (through an overridden method) by the constructor of the superclass:
+
+{% tabs scala-2-initializer_5 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+class Adder {
+ var sum = 0
+ def add(x: Int): Unit = sum += x
+ add(1)
+}
+class LogAdder extends {
+ private var added: Set[Int] = Set.empty
+} with Adder {
+ override def add(x: Int): Unit = { added += x; super.add(x) }
+}
+~~~
+{% endtab %}
+{% endtabs %}
+
+This case can be refactored by moving the private state into a nested `object`, which is initialized on demand:
+
+{% tabs shared-initializer_6 %}
+{% tab 'Scala 2 and 3' %}
+~~~ scala
+class Adder {
+ var sum = 0
+ def add(x: Int): Unit = sum += x
+ add(1)
+}
+class LogAdder extends Adder {
+ private object state {
+ var added: Set[Int] = Set.empty
+ }
+ import state._
+ override def add(x: Int): Unit = { added += x; super.add(x) }
+}
+~~~
+{% endtab %}
+{% endtabs %}
+
+## Existential Type
+
+Existential type is a [dropped feature]({{ site.scala3ref }}/dropped-features/existential-types.html), which makes the following code invalid.
+
+{% tabs scala-2-existential_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+def foo: List[Class[T]] forSome { type T } // In Scala 3, Error: Existential types are no longer supported
+~~~
+{% endtab %}
+{% endtabs %}
+
+> Existential type is an experimental feature in Scala 2.13 that must be enabled explicitly either by importing `import scala.language.existentials` or by setting the `-language:existentials` compiler flag.
+
+In Scala 3, the proposed solution is to introduce an enclosing type that carries the dependent type:
+
+{% tabs shared-existential_1 %}
+{% tab 'Scala 2 and 3' %}
+~~~ scala
+trait Bar {
+ type T
+ val value: List[Class[T]]
+}
+
+def foo: Bar
+~~~
+{% endtab %}
+{% endtabs %}
+
+Note that using a wildcard argument, `_` or `?`, is often simpler but is not always possible.
+For instance you could replace `List[T] forSome { type T }` by `List[?]`.
+
+## Specialized
+
+The `@specialized` annotation from Scala 2 is ignored in Scala 3.
+
+However, there is limited support for specialized `Function` and `Tuple`.
+
+Similar benefits can be derived from `inline` declarations.
+
diff --git a/_overviews/scala3-migration/incompat-other-changes.md b/_overviews/scala3-migration/incompat-other-changes.md
new file mode 100644
index 0000000000..a7a003d8ec
--- /dev/null
+++ b/_overviews/scala3-migration/incompat-other-changes.md
@@ -0,0 +1,328 @@
+---
+title: Other Changed Features
+type: section
+description: This chapter details all incompatibilities caused by changed features
+num: 20
+previous-page: incompat-contextual-abstractions
+next-page: incompat-type-checker
+---
+
+Some other features are simplified or restricted to make the language easier, safer or more consistent.
+
+|Incompatibility|Scala 3 Migration Rewrite|
+|--- |--- |
+|[Inheritance shadowing](#inheritance-shadowing)|✅|
+|[Non-private constructor in private class](#non-private-constructor-in-private-class)|Migration Warning|
+|[Abstract override](#abstract-override)||
+|[Case class companion](#case-class-companion)||
+|[Explicit call to unapply](#explicit-call-to-unapply)||
+|[Invisible bean property](#invisible-bean-property)||
+|[`=>T` as type argument](#-t-as-type-argument)||
+|[Wildcard type argument](#wildcard-type-argument)||
+
+## Inheritance Shadowing
+
+An inherited member, from a parent trait or class, can shadow an identifier defined in an outer scope.
+That pattern is called inheritance shadowing.
+
+{% tabs shared-inheritance_1 %}
+{% tab 'Scala 2 and 3' %}
+~~~ scala
+object B {
+ val x = 1
+ class C extends A {
+ println(x)
+ }
+}
+~~~
+{% endtab %}
+{% endtabs %}
+
+For instance, in this preceding piece of code, the `x` term in C can refer to the `x` member defined in the outer class `B` or it can refer to a `x` member of the parent class `A`.
+You cannot know until you go to the definition of `A`.
+
+This is known for being error prone.
+
+That's why, in Scala 3, the compiler requires disambiguation if the parent class `A` does actually have a member `x`.
+
+It prevents the following piece of code from compiling.
+{% tabs scala-2-inheritance_2 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+class A {
+ val x = 2
+}
+
+object B {
+ val x = 1
+ class C extends A {
+ println(x)
+ }
+}
+~~~
+{% endtab %}
+{% endtabs %}
+
+But if you try to compile with Scala 3 you should see an error of the same kind as:
+{% highlight text %}
+-- [E049] Reference Error: src/main/scala/inheritance-shadowing.scala:9:14
+9 | println(x)
+ | ^
+ | Reference to x is ambiguous,
+ | it is both defined in object B
+ | and inherited subsequently in class C
+{% endhighlight %}
+
+The [Scala 3 migration compilation](tooling-migration-mode.html) can automatically disambiguate the code by replacing `println(x)` with `println(this.x)`.
+
+## Non-private Constructor In Private Class
+
+The Scala 3 compiler requires the constructor of private classes to be private.
+
+For instance, in the example:
+{% tabs scala-2-constructor_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+package foo
+
+private class Bar private[foo] () {}
+~~~
+{% endtab %}
+{% endtabs %}
+
+If you try to compile in scala 3 you should get the following error message:
+{% highlight text %}
+-- Error: /home/piquerez/scalacenter/scala-3-migration-guide/incompat/access-modifier/src/main/scala-2.13/access-modifier.scala:4:19
+4 | private class Bar private[foo] ()
+ | ^
+ | non-private constructor Bar in class Bar refers to private class Bar
+ | in its type signature (): foo.Foo.Bar
+{% endhighlight %}
+
+The [Scala 3 migration compilation](tooling-migration-mode.html) warns about this but no automatic rewrite is provided.
+
+The solution is to make the constructor private, since the class is private.
+
+## Abstract Override
+
+In Scala 3, overriding a concrete def with an abstract def causes subclasses to consider the def abstract, whereas in Scala 2 it was considered as concrete.
+
+In the following piece of code, the `bar` method in `C` is considered concrete by the Scala 2.13 compiler but abstract by the Scala 3 compiler, causing the following error.
+{% tabs scala-2-abstract_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+trait A {
+ def bar(x: Int): Int = x + 3
+}
+
+trait B extends A {
+ def bar(x: Int): Int
+}
+
+class C extends B // In Scala 3, Error: class C needs to be abstract, since def bar(x: Int): Int is not defined
+~~~
+{% endtab %}
+{% endtabs %}
+
+This behavior was decided in [Dotty issue #4770](https://github.com/scala/scala3/issues/4770).
+
+An easy fix is simply to remove the abstract def, since in practice it had no effect in Scala 2.
+
+## Case Class Companion
+
+The companion object of a case class does not extend any of the `Function{0-23}` traits anymore.
+In particular, it does not inherit their methods: `tupled`, `curried`, `andThen`, `compose`...
+
+For instance, this is not permitted anymore:
+{% tabs scala-2-companion_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+case class Foo(x: Int, b: Boolean)
+
+Foo.curried(1)(true)
+Foo.tupled((2, false))
+~~~
+{% endtab %}
+{% endtabs %}
+
+A cross-compiling solution is to explicitly eta-expand the method `Foo.apply`.
+{% highlight diff %}
+
+-Foo.curried(1)(true)
++(Foo.apply _).curried(1)(true)
+
+-Foo.tupled((2, false))
++(Foo.apply _).tupled((2, false))
+{% endhighlight %}
+
+Or, for performance reasons, you can introduce an intermediate function value.
+{% tabs scala-3-companion_2 %}
+{% tab 'Scala 2 and 3' %}
+~~~ scala
+val fooCtr: (Int, Boolean) => Foo = (x, b) => Foo(x, b)
+
+fooCtr.curried(1)(true)
+fooCtr.tupled((2, false))
+~~~
+{% endtab %}
+{% endtabs %}
+## Explicit Call to `unapply`
+
+In Scala, case classes have an auto-generated extractor method, called `unapply` in their companion object.
+Its signature has changed between Scala 2.13 and Scala 3.
+
+The new signature is option-less (see the new [Pattern Matching]({{ site.scala3ref }}/changed-features/pattern-matching.html) reference), which causes an incompatibility when `unapply` is called explicitly.
+
+Note that this problem does not affect user-defined extractors, whose signature stays the same across Scala versions.
+
+Given the following case class definition:
+{% tabs shared-unapply_1 %}
+{% tab 'Scala 2 and 3' %}
+~~~ scala
+case class Location(lat: Double, long: Double)
+~~~
+{% endtab %}
+{% endtabs %}
+
+The Scala 2.13 compiler generates the following `unapply` method:
+{% tabs scala-2-unapply_2 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+object Location {
+ def unapply(location: Location): Option[(Double, Double)] = Some((location.lat, location.long))
+}
+~~~
+{% endtab %}
+{% endtabs %}
+
+Whereas the Scala 3 compiler generates:
+{% tabs scala-3-unapply_2 %}
+{% tab 'Scala 3 Only' %}
+~~~ scala
+object Location {
+ def unapply(location: Location): Location = location
+}
+~~~
+{% endtab %}
+{% endtabs %}
+
+Consequently the following code does not compile anymore in Scala 3.
+{% tabs scala-2-unapply_3 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+def tuple(location: Location): (Int, Int) = {
+ Location.unapply(location).get // [E008] In Scala 3, Not Found Error: value get is not a member of Location
+}
+~~~
+{% endtab %}
+{% endtabs %}
+
+A possible solution, in Scala 3, is to use pattern binding:
+
+{% highlight diff %}
+def tuple(location: Location): (Int, Int) = {
+- Location.unapply(location).get
++ val Location(lat, lon) = location
++ (lat, lon)
+}
+{% endhighlight %}
+
+## Invisible Bean Property
+
+The getter and setter methods generated by the `BeanProperty` annotation are now invisible in Scala 3 because their primary use case is the interoperability with Java frameworks.
+
+For instance, the below Scala 2 code would fail to compile in Scala 3:
+{% tabs scala-2-bean_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+class Pojo() {
+ @BeanProperty var fooBar: String = ""
+}
+
+val pojo = new Pojo()
+
+pojo.setFooBar("hello") // [E008] In Scala 3, Not Found Error: value setFooBar is not a member of Pojo
+
+println(pojo.getFooBar()) // [E008] In Scala 3, Not Found Error: value getFooBar is not a member of Pojo
+~~~
+{% endtab %}
+{% endtabs %}
+
+In Scala 3, the solution is to call the more idiomatic `pojo.fooBar` getter and setter.
+
+{% highlight diff %}
+val pojo = new Pojo()
+
+-pojo.setFooBar("hello")
++pojo.fooBar = "hello"
+
+-println(pojo.getFooBar())
++println(pojo.fooBar)
+{% endhighlight %}
+
+## `=> T` as Type Argument
+
+A type of the form `=> T` cannot be used as an argument to a type parameter anymore.
+
+This decision is explained in [this comment](https://github.com/scala/scala3/blob/0f1a23e008148f76fd0a1c2991b991e1dad600e8/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala#L144-L152) of the Scala 3 source code.
+
+For instance, it is not allowed to pass a function of type `Int => (=> Int) => Int` to the `uncurried` method since it would assign `=> Int` to the type parameter `T2`.
+
+{% highlight text %}
+-- [E134] Type Mismatch Error: src/main/scala/by-name-param-type-infer.scala:3:41
+3 | val g: (Int, => Int) => Int = Function.uncurried(f)
+ | ^^^^^^^^^^^^^^^^^^
+ |None of the overloaded alternatives of method uncurried in object Function with types
+ | [T1, T2, T3, T4, T5, R]
+ | (f: T1 => T2 => T3 => T4 => T5 => R): (T1, T2, T3, T4, T5) => R
+ | [T1, T2, T3, T4, R](f: T1 => T2 => T3 => T4 => R): (T1, T2, T3, T4) => R
+ | [T1, T2, T3, R](f: T1 => T2 => T3 => R): (T1, T2, T3) => R
+ | [T1, T2, R](f: T1 => T2 => R): (T1, T2) => R
+ |match arguments ((Test.f : Int => (=> Int) => Int))
+{% endhighlight %}
+
+The solution depends on the situation. In the given example, you can either:
+ - define your own `uncurried` method with the appropriate signature
+ - inline the implementation of `uncurried` locally
+
+## Wildcard Type Argument
+
+Scala 3 cannot reduce the application of a higher-kinded abstract type member to the wildcard argument.
+
+For instance, the below Scala 2 code would fail to compile in Scala 3:
+{% tabs scala-2-wildcard_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+trait Example {
+ type Foo[A]
+
+ def f(foo: Foo[_]): Unit // [E043] In Scala 3, Type Error: unreducible application of higher-kinded type Example.this.Foo to wildcard arguments
+}
+~~~
+{% endtab %}
+{% endtabs %}
+
+We can fix this by using a type parameter:
+
+{% highlight diff %}
+-def f(foo: Foo[_]): Unit
++def f[A](foo: Foo[A]): Unit
+{% endhighlight %}
+
+But this simple solution does not work when `Foo` is itself used as a type argument.
+{% tabs scala-2-wildcard_2 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+def g(foos: Seq[Foo[_]]): Unit
+~~~
+{% endtab %}
+{% endtabs %}
+
+In such case, we can use a wrapper class around `Foo`:
+
+{% highlight diff %}
++class FooWrapper[A](foo: Foo[A])
+
+-def g(foos: Seq[Foo[_]]): Unit
++def g(foos: Seq[FooWrapper[_]]): Unit
+{% endhighlight %}
\ No newline at end of file
diff --git a/_overviews/scala3-migration/incompat-syntactic.md b/_overviews/scala3-migration/incompat-syntactic.md
new file mode 100644
index 0000000000..0e88e2b034
--- /dev/null
+++ b/_overviews/scala3-migration/incompat-syntactic.md
@@ -0,0 +1,239 @@
+---
+title: Syntactic Changes
+type: section
+description: This chapter details all the incompatibilities caused by syntactic changes
+num: 17
+previous-page: incompatibility-table
+next-page: incompat-dropped-features
+---
+
+Scala 3 introduces the optional-braces syntax and the new control structure syntax.
+It comes at the cost of some minimal restrictions in the preexisting syntax.
+
+Other syntactic changes are intended to make the syntax less surprising and more consistent.
+
+It is worth noting that most of the changes can be automatically handled during the [Scala 3 migration compilation](tooling-migration-mode.html).
+
+|Incompatibility|Scala 2.13|Scala 3 Migration Rewrite|Scalafix Rule|
+|--- |--- |--- |--- |
+|[Restricted keywords](#restricted-keywords)||✅||
+|[Procedure syntax](#procedure-syntax)|Deprecation|✅|[✅](https://scalacenter.github.io/scalafix/docs/rules/ProcedureSyntax.html)|
+|[Parentheses around lambda parameter](#parentheses-around-lambda-parameter)||✅||
+|[Open brace indentation for passing an argument](#open-brace-indentation-for-passing-an-argument)||✅||
+|[Wrong indentation](#wrong-indentation)||||
+|[`_` as a type parameter](#_-as-a-type-parameter)||||
+|[`+` and `-` as type parameters](#-and---as-type-parameters)||||
+
+## Restricted Keywords
+
+The list of Scala 3 keywords can be found [here](https://dotty.epfl.ch/docs/internals/syntax.html#keywords).
+_Regular_ keywords cannot be used as identifiers, whereas _soft_ keywords are not restricted.
+
+For the matter of migrating from Scala 2.13 to Scala 3, only the subset of new _regular_ keywords are problematic.
+It is composed of:
+- `enum`
+- `export`
+- `given`
+- `then`
+- `=>>`
+- `?=>`
+
+{% tabs scala-2-keywords_1 %}
+{% tab 'Scala 2 Only' %}
+
+For instance, the following piece of code can be compiled with Scala 2.13 but not with Scala 3.
+~~~ scala
+object given { // In Scala 3, Error: given is now a keyword.
+ val enum = ??? // In Scala 3, Error: enum is now a keyword.
+
+ println(enum) // In Scala 3, Error: enum is now a keyword.
+}
+~~~
+{% endtab %}
+{% endtabs %}
+
+The [Scala 3 migration compilation](tooling-migration-mode.html) rewrites the code into:
+{% highlight diff %}
+-object given {
++object `given` {
+- val enum = ???
++ val `enum` = ???
+
+- println(enum)
++ println(`enum`)
+ }
+{% endhighlight %}
+
+## Procedure Syntax
+
+Procedure syntax has been deprecated for a while and it is dropped in Scala 3.
+
+{% tabs scala-2-procedure_1 %}
+{% tab 'Scala 2 Only' %}
+
+The following pieces of code are now illegal:
+~~~ scala
+object Bar {
+ def print() { // In Scala 3, Error: Procedure syntax no longer supported; `: Unit =` should be inserted here.
+ println("bar")
+ }
+}
+~~~
+{% endtab %}
+{% endtabs %}
+
+The [Scala 3 migration compilation](tooling-migration-mode.html) rewrites the code into.
+{% highlight diff %}
+ object Bar {
+- def print() {
++ def print(): Unit = {
+ println("bar")
+ }
+ }
+{% endhighlight %}
+
+## Parentheses Around Lambda Parameter
+
+When followed by its type, the parameter of a lambda is now required to be enclosed in parentheses.
+The following piece of code is invalid.
+
+{% tabs scala-2-lambda_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+val f = { x: Int => x * x } // In Scala 3, Error: parentheses are required around the parameter of a lambda.
+~~~
+{% endtab %}
+{% endtabs %}
+
+The [Scala 3 migration compilation](tooling-migration-mode.html) rewrites the code into:
+{% highlight diff %}
+-val f = { x: Int => x * x }
++val f = { (x: Int) => x * x }
+{% endhighlight %}
+
+## Open Brace Indentation For Passing An Argument
+
+In Scala 2 it is possible to pass an argument after a new line by enclosing it into braces.
+Although valid, this style of coding is not encouraged by the [Scala style guide](https://docs.scala-lang.org/style) and is no longer supported in Scala 3.
+
+{% tabs scala-2-brace_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+test("my test")
+{ // In Scala 3, Error: This opening brace will start a new statement.
+ assert(1 == 1)
+}
+~~~
+{% endtab %}
+{% endtabs %}
+
+The [Scala 3 migration compiler](tooling-migration-mode.html) indents the first line of the block.
+{% highlight diff %}
+ test("my test")
+-{
++ {
+ assert(1 == 1)
+ }
+{% endhighlight %}
+
+This migration rule applies to other patterns as well, such as refining a type after a new line.
+
+{% highlight diff %}
+ type Bar = Foo
+-{
++ {
+ def bar(): Int
+ }
+{% endhighlight %}
+
+A preferable solution is to write:
+{% highlight diff %}
+-test("my test")
+-{
++test("my test") {
+ assert(1 == 1)
+ }
+{% endhighlight %}
+
+## Wrong indentation
+
+The Scala 3 compiler now requires correct indentation.
+The following piece of code, that was compiled in Scala 2.13, does not compile anymore because of the indentation.
+
+{% tabs scala-2-indentation_1 %}
+{% tab 'Scala 2 Only' %}
+
+~~~ scala
+def bar: (Int, Int) = {
+ val foo = 1.0
+ val bar = foo // [E050] In Scala 3, type Error: value foo does not take parameters.
+ (1, 1)
+} // [E007] In Scala 3, type Mismatch Error: Found Unit, Required (Int, Int).
+~~~
+{% endtab %}
+{% endtabs %}
+
+The indentation must be fixed.
+{% highlight diff %}
+ def bar: (Int, Int) = {
+ val foo = 1.0
+ val bar = foo
+- (1, 1)
++ (1, 1)
+ }
+{% endhighlight %}
+
+These errors can be prevented by using a Scala formatting tool such as [scalafmt](https://scalameta.org/scalafmt/) or the [IntelliJ Scala formatter](https://www.jetbrains.com/help/idea/reformat-and-rearrange-code.html).
+Beware that these tools may change the entire code style of your project.
+
+## `_` As A Type Parameter
+
+The usage of the `_` identifier as a type parameter is permitted in Scala 2.13, even if it has never been mentioned in the Scala 2 specification.
+It is used in the API of [fastparse](https://index.scala-lang.org/lihaoyi/fastparse), in combination with a context bound, to declare an implicit parameter.
+
+{% tabs scala-2-identifier_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+def foo[_: Foo]: Unit = ???
+~~~
+{% endtab %}
+{% endtabs %}
+
+Here, the method `foo` takes a type parameter `_` and an implicit parameter of type `Foo[_]` where `_` refers to the type parameter, not the wildcard symbol.
+
+Martin Odersky described this pattern as a "clever exploit of a scalac compiler bug" ([source](https://www.reddit.com/r/scala/comments/fczcvo/mysterious_context_bounds_in_fastparse_2/fjecokn/)).
+
+The Scala 3 compiler does not permit this pattern anymore:
+
+{% highlight text %}
+-- [E040] Syntax Error: src/main/scala/anonymous-type-param.scala:4:10
+4 | def foo[_: Foo]: Unit = ()
+ | ^
+ | an identifier expected, but '_' found
+{% endhighlight %}
+
+The solution is to give the parameter a valid identifier name, for instance `T`.
+This will not break the binary compatibility.
+
+{% highlight diff %}
+-def foo[_: Foo]: Unit = ???
++def foo[T: Foo]: Unit = ???
+{% endhighlight %}
+
+## `+` And `-` As Type Parameters
+
+`+` and `-` are not valid identifiers for type parameters in Scala 3, since they are reserved for variance annotation.
+
+You cannot write `def foo[+]` or `def foo[-]` anymore.
+
+{% highlight text %}
+-- Error: src/main/scala/type-param-identifier.scala:2:10
+2 | def foo[+]: +
+ | ^
+ | no `+/-` variance annotation allowed here
+{% endhighlight %}
+
+The solution is to choose another valid identifier, for instance `T`.
+
+However, `+` and `-` still are valid type identifiers in general.
+You can write `type +`.
diff --git a/_overviews/scala3-migration/incompat-type-checker.md b/_overviews/scala3-migration/incompat-type-checker.md
new file mode 100644
index 0000000000..41afc5ebc7
--- /dev/null
+++ b/_overviews/scala3-migration/incompat-type-checker.md
@@ -0,0 +1,130 @@
+---
+title: Type Checker
+type: section
+description: This chapter details the unsoundness fixes in the type checker
+num: 21
+previous-page: incompat-other-changes
+next-page: incompat-type-inference
+---
+
+The Scala 2.13 type checker is unsound in some specific cases.
+This can lead to surprising runtime errors in places we would not expect.
+Scala 3 being based on stronger theoretical foundations, these unsoundness bugs in the type checker are now fixed.
+
+## Unsoundness Fixes in Variance checks
+
+In Scala 2, default parameters and inner-classes are not subject to variance checks.
+It is unsound and might cause runtime failures, as demonstrated by this [test](https://github.com/scala/scala3/blob/10526a7d0aa8910729b6036ee51942e05b71abf6/tests/neg/variances.scala) in the Scala 3 repository.
+
+The Scala 3 compiler does not permit this anymore.
+
+{% tabs scala-2-unsound_vc_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+class Foo[-A](x: List[A]) {
+ def f[B](y: List[B] = x): Unit = ???
+}
+
+class Outer[+A](x: A) {
+ class Inner(y: A)
+}
+~~~
+{% endtab %}
+{% endtabs %}
+
+So if you compile in Scala 3, you will get the following error.
+{% highlight text %}
+-- Error: src/main/scala/variance.scala:2:8
+2 | def f[B](y: List[B] = x): Unit = y
+ | ^^^^^^^^^^^^^^^^^
+ |contravariant type A occurs in covariant position in type [B] => List[A] of method f$default$1
+-- Error: src/main/scala/variance.scala:6:14
+6 | class Inner(y: A)
+ | ^^^^
+ |covariant type A occurs in contravariant position in type A of parameter y
+{% endhighlight %}
+
+Each problem of this kind needs a specific care.
+You can try the following options on a case-by-case basis:
+- Make type `A` invariant
+- Add a lower or an upper bound on a type parameter `B`
+- Add a new method overload
+
+In our example, we can opt for these two solutions:
+
+{% highlight diff %}
+class Foo[-A](x: List[A]) {
+- def f[B](y: List[B] = x): Unit = ???
++ def f[B](y: List[B]): Unit = ???
++ def f(): Unit = f(x)
+}
+
+class Outer[+A](x: A) {
+- class Inner(y: A)
++ class Inner[B >: A](y: B)
+}
+{% endhighlight %}
+
+Or, as a temporary solution, you can also use the `uncheckedVariance` annotation:
+
+{% highlight diff %}
+class Outer[+A](x: A) {
+- class Inner(y: A)
++ class Inner(y: A @uncheckedVariance)
+}
+{% endhighlight %}
+
+## Unsoundness Fixes in Pattern Matching
+
+Scala 3 fixes some unsoundness bugs in pattern matching, preventing some semantically wrong match expressions to type check.
+
+For instance, the match expression in `combineReq` can be compiled with Scala 2.13 but not with Scala 3.
+
+{% tabs scala-2-unsound_pm_1 %}
+{% tab 'Scala 2 Only' %}
+~~~ scala
+trait Request
+case class Fetch[A](ids: Set[A]) extends Request
+
+object Request {
+ def combineFetch[A](x: Fetch[A], y: Fetch[A]): Fetch[A] = Fetch(x.ids ++ y.ids)
+
+ def combineReq(x: Request, y: Request): Request = {
+ (x, y) match {
+ case (x @ Fetch(_), y @ Fetch(_)) => combineFetch(x, y)
+ }
+ }
+}
+~~~
+{% endtab %}
+{% endtabs %}
+
+In Scala 3, the error message is:
+
+{% highlight text %}
+-- [E007] Type Mismatch Error: src/main/scala/pattern-match.scala:9:59
+9 | case (x @ Fetch(_), y @ Fetch(_)) => combineFetch(x, y)
+ | ^
+ | Found: (y : Fetch[A$2])
+ | Required: Fetch[A$1]
+{% endhighlight %}
+
+
+Which is right, there is no proof that `x` and `y` have the same type parameter `A`.
+
+Coming from Scala 2, this is clearly an improvement to help us locate mistakes in our code.
+To solve this incompatibility it is better to find a solution that can be checked by the compiler.
+It is not always easy and sometimes it is even not possible, in which case the code is likely to fail at runtime.
+
+In this example, we can relax the constraint on `x` and `y` by stating that `A` is a common ancestor of both type arguments.
+This makes the compiler type-check the code successfully.
+{% tabs shared-unsound_pm_2 %}
+{% tab 'Scala 2 and 3' %}
+~~~ scala
+def combineFetch[A](x: Fetch[_ <: A], y: Fetch[_ <: A]): Fetch[A] = Fetch(x.ids ++ y.ids)
+~~~
+{% endtab %}
+{% endtabs %}
+
+Alternatively, a general but unsafe solution is to cast.
+
diff --git a/_overviews/scala3-migration/incompat-type-inference.md b/_overviews/scala3-migration/incompat-type-inference.md
new file mode 100644
index 0000000000..bb6fc3052a
--- /dev/null
+++ b/_overviews/scala3-migration/incompat-type-inference.md
@@ -0,0 +1,107 @@
+---
+title: Type Inference
+type: section
+description: This chapter details the incompatibilities caused by the new type inference algorithm
+num: 22
+previous-page: incompat-type-checker
+next-page: options-intro
+---
+
+The two incompatibilities described in this page are intentional changes in the type inference rules.
+
+Other incompatibilities could be caused by the replacement of the type inference algorithm.
+The new algorithm is better than the old one, but sometime it can fail where Scala 2.13 would succeed:
+
+> It is always good practice to write the result types of all public values and methods explicitly.
+> It prevents the public API of your library from changing with the Scala version, because of different inferred types.
+>
+> This can be done prior to the Scala 3 migration by using the [ExplicitResultTypes](https://scalacenter.github.io/scalafix/docs/rules/ExplicitResultTypes.html) rule in Scalafix.
+
+## Return Type of an Override Method
+
+In Scala 3 the return type of an override method is inferred by inheritance from the base method, whereas in Scala 2.13 it is inferred from the left hand side of the override method.
+
+{% tabs define_parent_child %}
+{% tab 'Scala 2 and 3' %}
+```scala
+class Foo
+
+class RichFoo(foo: Foo) extends Foo {
+ def show: String = ""
+}
+
+class Parent {
+ def foo: Foo = new Foo
+}
+
+class Child extends Parent {
+ override def foo = new RichFoo(super.foo)
+}
+```
+{% endtab %}
+{% endtabs %}
+
+In this example, `Child#foo` returns a `RichFoo` in Scala 2.13 but a `Foo` in Scala 3.
+It can lead to compiler errors as demonstrated below.
+
+{% tabs extend_parent_child %}
+{% tab 'Scala 3 Only' %}
+```scala
+(new Child).foo.show // Scala 3 error: value show is not a member of Foo
+```
+{% endtab %}
+{% endtabs %}
+
+In some rare cases involving implicit conversions and runtime casting it could even cause a runtime failure.
+
+The solution is to make the return type of the override method explicit so that it matches what is inferred in 2.13:
+
+{% highlight diff %}
+class Child extends Parent {
+- override def foo = new RichFoo(super.foo)
++ override def foo: RichFoo = new RichFoo(super.foo)
+}
+{% endhighlight %}
+
+## Reflective Type
+
+Scala 2 reflective calls are dropped and replaced by the broader [Programmatic Structural Types]({{ site.scala3ref }}/changed-features/structural-types.html).
+
+Scala 3 can imitate Scala 2 reflective calls by making `scala.reflect.Selectable.reflectiveSelectable` available wherever `scala.language.reflectiveCalls` is imported.
+
+{% tabs define_structural %}
+{% tab 'Scala 2 and 3' %}
+```scala
+import scala.language.reflectiveCalls
+
+val foo = new {
+ def bar: Unit = ???
+}
+```
+{% endtab %}
+{% endtabs %}
+
+However the Scala 3 compiler does not infer structural types by default.
+It infers the type `Object` for `foo` instead of `{ def bar: Unit }`.
+Therefore, the following structural selection fails to compile:
+
+{% tabs use_structural %}
+{% tab 'Scala 3 Only' %}
+```scala
+foo.bar // Error: value bar is not a member of Object
+```
+{% endtab %}
+{% endtabs %}
+
+The straightforward solution is to explicitly write down the structural type.
+
+{% highlight diff %}
+import scala.language.reflectiveCalls
+
+- val foo = new {
++ val foo: { def bar: Unit } = new {
+ def bar: Unit = ???
+}
+
+foo.bar
+{% endhighlight %}
diff --git a/_overviews/scala3-migration/incompatibility-table.md b/_overviews/scala3-migration/incompatibility-table.md
new file mode 100644
index 0000000000..9fc9f8bf18
--- /dev/null
+++ b/_overviews/scala3-migration/incompatibility-table.md
@@ -0,0 +1,126 @@
+---
+title: Incompatibility Table
+type: chapter
+description: This chapter list all the known incompatibilities between Scala 2.13 and Scala 3
+num: 16
+previous-page: tooling-syntax-rewriting
+next-page: incompat-syntactic
+---
+
+An incompatibility is a piece of code that can be compiled with Scala 2.13 but not with Scala 3.
+Migrating a codebase involves finding and fixing all the incompatibilities of the source code.
+On rare occasions we can also have a runtime incompatibility: a piece of code that behaves differently at runtime.
+
+In this page we propose a classification of the known incompatibilities.
+Each incompatibility is described by:
+ - Its short name with a link towards the detailed description and proposed solutions
+ - Whether the Scala 2.13 compiler emits a deprecation or a feature warning
+ - The existence of a [Scala 3 migration](tooling-migration-mode.html) rule for it
+ - The existence of a Scalafix rule that can fix it
+
+> #### Scala 2.13 deprecations and feature warnings
+> Run the 2.13 compilation with `-Xsource:3` to locate those incompatibilities in the code.
+
+> #### Scala 3 migration versus Scalafix rewrites
+> The Scala 3 migration mode comes out-of-the-box.
+> On the contrary, Scalafix is a tool that must be installed and configured manually.
+> However Scalafix has its own advantages:
+> - It runs on Scala 2.13.
+> - It is composed of individual rules that you can apply one at a time.
+> - It is easily extensible by adding custom rules.
+
+### Syntactic Changes
+
+Some of the old syntax is not supported anymore.
+
+|Incompatibility|Scala 2.13|Scala 3 Migration Rewrite|Scalafix Rule|
+|--- |--- |--- |--- |
+|[Restricted keywords](incompat-syntactic.html#restricted-keywords)||✅||
+|[Procedure syntax](incompat-syntactic.html#procedure-syntax)|Deprecation|✅|[✅](https://scalacenter.github.io/scalafix/docs/rules/ProcedureSyntax.html)|
+|[Parentheses around lambda parameter](incompat-syntactic.html#parentheses-around-lambda-parameter)||✅||
+|[Open brace indentation for passing an argument](incompat-syntactic.html#open-brace-indentation-for-passing-an-argument)||✅||
+|[Wrong indentation](incompat-syntactic.html#wrong-indentation)||||
+|[`_` as a type parameter](incompat-syntactic.html#_-as-a-type-parameter)||||
+|[`+` and `-` as type parameters](incompat-syntactic.html#-and---as-type-parameters)||||
+
+### Dropped Features
+
+Some features are dropped to simplify the language.
+
+|Incompatibility|Scala 2.13|Scala 3 Migration Rewrite|Scalafix Rule|
+|--- |--- |--- |--- |
+|[Symbol literals](incompat-dropped-features.html#symbol-literals)|Deprecation|✅||
+|[`do`-`while` construct](incompat-dropped-features.html#do-while-construct)||✅||
+|[Auto-application](incompat-dropped-features.html#auto-application)|Deprecation|✅|[✅](https://github.com/scala/scala-rewrites/blob/main/rewrites/src/main/scala/fix/scala213/ExplicitNonNullaryApply.scala)|
+|[Value eta-expansion](incompat-dropped-features.html#value-eta-expansion)|Deprecation|✅|[✅](https://github.com/scala/scala-rewrites/blob/main/rewrites/src/main/scala/fix/scala213/ExplicitNullaryEtaExpansion.scala)|
+|[`any2stringadd` conversion](incompat-dropped-features.html#any2stringadd-conversion)|Deprecation||[✅](https://github.com/scala/scala-rewrites/blob/main/rewrites/src/main/scala/fix/scala213/Any2StringAdd.scala)|
+|[Early initializer](incompat-dropped-features.html#early-initializer)|Deprecation|||
+|[Existential type](incompat-dropped-features.html#existential-type)|Feature warning|||
+
+### Contextual Abstractions
+
+The redesign of [contextual abstractions]({{ site.scala3ref }}/contextual) brings some well defined incompatibilities.
+
+|Incompatibility|Scala 2.13|Scala 3 Migration Rewrite|Scalafix Rule|Runtime Incompatibility|
+|--- |--- |--- |--- |--- |
+|[Type of implicit def](incompat-contextual-abstractions.html#type-of-implicit-definition)|||[✅](https://scalacenter.github.io/scalafix/docs/rules/ExplicitResultTypes.html)||
+|[Implicit views](incompat-contextual-abstractions.html#implicit-views)||||**Possible**|
+|[View bounds](incompat-contextual-abstractions.html#view-bounds)|Deprecation||||
+|[Ambiguous conversion on `A` and `=> A`](incompat-contextual-abstractions.html#ambiguous-conversion-on-a-and--a)|||||
+
+Furthermore we have changed the implicit resolution rules so that they are more useful and less surprising.
+The new rules are described [here]({{ site.scala3ref }}/changed-features/implicit-resolution.html).
+
+Because of these changes, the Scala 3 compiler could possibly fail at resolving some implicit parameters of existing Scala 2.13 code.
+
+### Other Changed Features
+
+Some other features are simplified or restricted to make the language easier, safer or more consistent.
+
+|Incompatibility|Scala 3 Migration Rewrite|
+|--- |--- |
+|[Inheritance shadowing](incompat-other-changes.html#inheritance-shadowing)|✅|
+|[Non-private constructor in private class](incompat-other-changes.html#non-private-constructor-in-private-class)|Migration Warning|
+|[Abstract override](incompat-other-changes.html#abstract-override)||
+|[Case class companion](incompat-other-changes.html#case-class-companion)||
+|[Explicit call to unapply](incompat-other-changes.html#explicit-call-to-unapply)||
+|[Invisible bean property](incompat-other-changes.html#invisible-bean-property)||
+|[`=>T` as type argument](incompat-other-changes.html#-t-as-type-argument)||
+|[Wildcard type argument](incompat-other-changes.html#wildcard-type-argument)||
+
+### Type Checker
+
+The Scala 2.13 type checker is unsound in some specific cases.
+This can lead to surprising runtime errors in places we would not expect.
+Scala 3 being based on stronger theoretical foundations, these unsoundness bugs in the type checker are now fixed.
+
+|Incompatibility|
+|--- |
+|[Variance checks](incompat-type-checker.html#unsoundness-fixes-in-variance-checks)|
+|[Pattern matching](incompat-type-checker.html#unsoundness-fixes-in-pattern-matching)|
+
+### Type Inference
+
+Some specific type inference rules have changed between Scala 2.13 and Scala 3.
+
+|Incompatibility|
+|--- |
+|[Return type of override method](incompat-type-inference.html#return-type-of-an-override-method)|
+|[Reflective type](incompat-type-inference.html#reflective-type)|
+
+Also we have improved the type inference algorithm by redesigning it entirely.
+This fundamental change leads to a few incompatibilities:
+- A different type can be inferred
+- A new type-checking error can appear
+
+> It is always good practice to write the result types of all public values and methods explicitly.
+> It prevents the public API of your library from changing with the Scala version, because of different inferred types.
+>
+> This can be done prior to the Scala 3 migration by using the [ExplicitResultTypes](https://scalacenter.github.io/scalafix/docs/rules/ExplicitResultTypes.html) rule in Scalafix.
+
+### Macros
+
+The Scala 3 compiler is not able to expand Scala 2.13 macros.
+Under such circumstances it is necessary to re-implement the Scala 2.13 macros using the new Scala 3 metaprogramming features.
+
+You can go back to the [Metaprogramming](compatibility-metaprogramming.html) page to learn about the new metaprogramming features.
diff --git a/_overviews/scala3-migration/options-intro.md b/_overviews/scala3-migration/options-intro.md
new file mode 100644
index 0000000000..9fc2d04d48
--- /dev/null
+++ b/_overviews/scala3-migration/options-intro.md
@@ -0,0 +1,21 @@
+---
+title: Compiler Options
+type: chapter
+description: This chapter shows the difference between Scala 2.13 and Scala 3 compiler options
+num: 23
+previous-page: incompat-type-inference
+next-page: options-lookup
+---
+
+The Scala 3 compiler has been rewritten from the ground up and consequently it does not offer the same options as the Scala 2.13 compiler.
+Some options are available under a different name, others have just not been implemented yet.
+
+When porting a Scala 2.13 project to Scala 3, you will need to adapt the list of compiler options.
+To do so you can refer to the [Lookup Table](options-lookup.html).
+
+> Passing an unavailable option to the Scala 3 compiler does not make it fail.
+> It just prints a warning and ignores the option.
+
+You can also discover the new Scala 3 compiler options, which have no equivalent in Scala 2.13, in the [New Compiler Options](options-new.html) page.
+
+For Scaladoc settings reference and their compatibility with Scala2 Scaladoc, read [Scaladoc settings compatibility between Scala2 and Scala3](scaladoc-settings-compatibility.html) page.
diff --git a/_overviews/scala3-migration/options-lookup.md b/_overviews/scala3-migration/options-lookup.md
new file mode 100644
index 0000000000..36db00ad8e
--- /dev/null
+++ b/_overviews/scala3-migration/options-lookup.md
@@ -0,0 +1,265 @@
+---
+title: Compiler Options Lookup Table
+type: section
+description: This section contains the compiler options lookup tables
+num: 24
+previous-page: options-intro
+next-page: options-new
+---
+
+This table lists the Scala 2.13 compiler options with their equivalent in Scala 3.
+Some options have cross-version support, such as `-Vprint`.
+Others have a close equivalent with a different name. A number of Scala 2 options
+have no equivalent in Scala 3, such as options for debugging Scala 2 macros.
+
+The compiler options are shown as displayed by the help output `scalac -help`, `scalac -X`, etc.
+A few aliases are shown here, but most older aliases, such as `-Xprint` for `-Vprint`,
+or `-Ytyper-debug` for `-Vtyper`, are listed by the latest name.
+
+The option groups `-V` and `-W` were introduced in Scala 2.13, for "verbose" options that
+request additional diagnostic output and "warnings" that request additional checks which
+may or may not indicate errors in code. `-Werror` elevates warnings to errors, and `-Wconf`
+allows precise control over warnings by either ignoring them or taking them as errors.
+The configuration string for `-Wconf` will likely require adjustment when migrating to Scala 3,
+since the configuration syntax and the error messages it matches are different.
+
+| Status | Meaning |
+|-|-|
+| | It is available in Scala 3. |
+| `` | It has been renamed to ``. |
+| | It is not yet available but could be added later. |
+
+> The current comparison is based on Scala 2.13.10 and 3.3.0.
+
+## Standard Settings
+
+| 2.13.x | 3.3.x |
+|-|-|
+| `-Dproperty=value` | |
+| `-J` | |
+| `-P::` ||
+| `-V` | |
+| `-W` | |
+| `-X` ||
+| `-Y` ||
+| `-bootclasspath` ||
+| `-classpath` ||
+| `-d` ||
+| `-dependencyfile` | |
+| `-deprecation` ||
+| `-encoding` ||
+| `-explaintypes` | `-explain-types` |
+| `-extdirs` ||
+| `-feature` ||
+| `-g` | |
+| `-help` ||
+| `-javabootclasspath` ||
+| `-javaextdirs` ||
+| `-language` ||
+| `-no-specialization` | |
+| `-nobootcp` | |
+| `-nowarn` ||
+| `-opt` | |
+| `-opt-inline-from` | |
+| `-opt-warnings` | |
+| `-optimize` | |
+| `-print` ||
+| `-release` ||
+| `-rootdir` | |
+| `-sourcepath` ||
+| `-target` | `-Xtarget` |
+| `-toolcp` | |
+| `-unchecked` ||
+| `-uniqid` ||
+| `-usejavacp` ||
+| `-usemanifestc` | |
+| `-verbose` ||
+| `-version` ||
+
+## Verbose Settings
+
+| 2.13.x | 3.3.x |
+|-|-|
+| `-Vbrowse:` | |
+| `-Vclasspath` | `-Ylog-classpath` |
+| `-Vdebug` | `-Ydebug` |
+| `-Vdebug-tasty` | |
+| `-Vdebug-type-error` | |
+| `-Vdoc` | |
+| `-Vfree-terms` | |
+| `-Vfree-types` | |
+| `-Vhot-statistics`| |
+| `-Vide`| |
+| `-Vimplicit-conversions`| |
+| `-Vimplicits`| |
+| `-Vimplicits-max-refined`| |
+| `-Vimplicits-verbose-tree`| |
+| `-Vinline ` | |
+| `-Vlog:` | `-Ylog:`|
+| `-Vmacro` | |
+| `-Vmacro-lite` | |
+| `-Vopt ` | |
+| `-Vpatmat` | |
+| `-Vphases` | |
+| `-Vpos`| |
+| `-Vprint:` | |
+| `-Vprint-args ` | |
+| `-Vprint-pos` | `-Yprint-pos` |
+| `-Vprint-types` | `-Xprint-types` |
+| `-Vquasiquote` | |
+| `-Vreflective-calls` | |
+| `-Vreify` | |
+| `-Vshow:` | |
+| `-Vshow-class ` | |
+| `-Vshow-member-pos
-
\ No newline at end of file
+
diff --git a/_ru/getting-started/install-scala.md b/_ru/getting-started/install-scala.md
new file mode 100644
index 0000000000..44154d2dfb
--- /dev/null
+++ b/_ru/getting-started/install-scala.md
@@ -0,0 +1,244 @@
+---
+layout: singlepage-overview
+title: Начало работы
+partof: getting-started
+language: ru
+includeTOC: true
+
+newcomer_resources:
+ - title: Вы пришли с Java?
+ description: Что нужно знать, чтобы ускорить работу со Scala после первоначального запуска.
+ icon: "fa fa-coffee"
+ link: /tutorials/scala-for-java-programmers.html
+ - title: Scala в браузере
+ description: >
+ Чтобы сразу начать экспериментировать со Scala, используйте "Scastie" в своем браузере.
+ icon: "fa fa-cloud"
+ link: https://scastie.scala-lang.org/pEBYc5VMT02wAGaDrfLnyw
+---
+
+Приведенные ниже инструкции охватывают как Scala 3, так и Scala 2.
+
+
+{% altDetails need-help-info-box 'Нужна помощь?' class=help-info %}
+*Если у вас возникли проблемы с настройкой Scala, смело обращайтесь за помощью в канал `#scala-users`
+[нашего Discord](https://discord.com/invite/scala).*
+{% endaltDetails %}
+
+
+## Ресурсы для новичков
+
+{% include inner-documentation-sections.html links=page.newcomer_resources %}
+
+## Установка Scala на компьютер
+
+Установка Scala означает установку различных инструментов командной строки,
+таких как компилятор Scala и инструменты сборки.
+Мы рекомендуем использовать инструмент установки "Coursier",
+который автоматически устанавливает все зависимости.
+Также возможно установить по отдельности каждый инструмент вручную.
+
+### Использование Scala Installer (рекомендованный путь)
+
+Установщик Scala — это инструмент [Coursier](https://get-coursier.io/docs/cli-overview),
+основная команда которого называется `cs`.
+Он гарантирует, что в системе установлены JVM и стандартные инструменты Scala.
+Установите его в своей системе, следуя следующим инструкциям.
+
+
+{% tabs install-cs-setup-tabs class=platform-os-options %}
+
+
+{% tab macOS for=install-cs-setup-tabs %}
+Запустите в терминале следующую команду, следуя инструкциям на экране:
+{% include code-snippet.html language='bash' codeSnippet=site.data.setup-scala.macOS-brew %}
+{% altDetails cs-setup-macos-nobrew "В качестве альтернативы, если вы не используете Homebrew:" %}
+ {% include code-snippet.html language='bash' codeSnippet=site.data.setup-scala.macOS-x86-64 %}
+{% endaltDetails %}
+{% endtab %}
+
+
+
+{% tab Linux for=install-cs-setup-tabs %}
+ Запустите в терминале следующую команду, следуя инструкциям на экране:
+ {% include code-snippet.html language='bash' codeSnippet=site.data.setup-scala.linux-x86-64 %}
+{% endtab %}
+
+
+
+{% tab Windows for=install-cs-setup-tabs %}
+ Загрузите и запустите [установщик Scala для Windows]({{site.data.setup-scala.windows-link}})
+ на базе Coursier и следуйте инструкциям на экране.
+{% endtab %}
+
+
+
+{% tab Иное for=install-cs-setup-tabs defaultTab %}
+
+ Следуйте документации Coursier о том,
+ [как установить и запустить `cs setup`](https://get-coursier.io/docs/cli-installation).
+{% endtab %}
+
+
+{% endtabs %}
+
+
+
+{% altDetails testing-your-setup 'Тестирование установки' %}
+Проверьте корректность установки с помощью команды `scala -version`, которая должна вывести:
+```bash
+$ scala -version
+Scala code runner version: 1.4.3
+Scala version (default): {{site.scala-3-version}}
+```
+Если сообщение не выдано, возможно, необходимо перезайти в терминал (или перезагрузиться),
+чтобы изменения вступили в силу.
+{% endaltDetails %}
+
+
+Наряду с JVM `cs setup` также устанавливает полезные инструменты командной строки:
+
+| Commands | Description |
+|---------------|--------------------------------------------------------------------------------------|
+| `scalac` | компилятор Scala |
+| `scala` | Scala REPL и средство запуска сценариев |
+| `scala-cli` | [Scala CLI](https://scala-cli.virtuslab.org), интерактивный инструментарий для Scala |
+| `sbt`, `sbtn` | Инструмент сборки [sbt](https://www.scala-sbt.org/) |
+| `amm` | [Ammonite](https://ammonite.io/) — улучшенный REPL |
+| `scalafmt` | [Scalafmt](https://scalameta.org/scalafmt/) - средство форматирования кода Scala |
+
+Дополнительная информация о cs [доступна по ссылке](https://get-coursier.io/docs/cli-overview).
+
+> `cs setup` по умолчанию устанавливает компилятор и исполняющую программу Scala 3
+> (команды `scalac` и `scala` соответственно). Независимо от того, собираетесь ли вы использовать Scala 2 или 3,
+> обычно это не проблема, потому что в большинстве проектов используется инструмент сборки,
+> который будет использовать правильную версию Scala независимо от того, какая версия установлена "глобально".
+> Тем не менее, вы всегда можете запустить конкретную версию Scala, используя
+> ```
+> $ cs launch scala:{{ site.scala-version }}
+> $ cs launch scalac:{{ site.scala-version }}
+> ```
+> Если предпочтительно, чтобы по умолчанию запускалась Scala 2, вы можете принудительно установить эту версию с помощью:
+> ```
+> $ cs install scala:{{ site.scala-version }} scalac:{{ site.scala-version }}
+> ```
+
+### ...или вручную
+
+Для компиляции, запуска, тестирования и упаковки проекта Scala нужны только два инструмента:
+Java 8 или 11 и sbt.
+Чтобы установить их вручную:
+
+1. если не установлена Java 8 или 11, загрузите Java из
+ [Oracle Java 8](https://www.oracle.com/java/technologies/javase-jdk8-downloads.html), [Oracle Java 11](https://www.oracle.com/java/technologies/javase-jdk11-downloads.html),
+ или [AdoptOpenJDK 8/11](https://adoptopenjdk.net/).
+ Подробную информацию о совместимости Scala/Java см. в разделе [Совместимость с JDK](/overviews/jdk-compatibility/overview.html).
+1. установить [sbt](https://www.scala-sbt.org/download.html)
+
+## Создание проекта "Hello World" с помощью sbt
+
+В следующих разделах объясняется как создавать проект Scala после того, как установлен sbt.
+
+Для создания проекта можно использовать командную строку или IDE.
+Мы рекомендуем командную строку, если вы с ней знакомы.
+
+### Использование командной строки
+
+sbt — это инструмент сборки для Scala. sbt компилирует, запускает и тестирует Scala код
+(он также может публиковать библиотеки и выполнять множество других задач).
+
+Чтобы создать новый проект Scala с помощью sbt:
+
+1. `cd` в пустую папку.
+1. Запустите команду `sbt new scala/scala3.g8`, чтобы создать проект на Scala 3,
+ или `sbt new scala/hello-world.g8` для создания проекта на Scala 2.
+ Она извлекает шаблон проекта из GitHub.
+ Эта команда также создает папку `target`, которую вы можете игнорировать.
+1. При появлении запроса назовите приложение `hello-world`.
+ Это создаст проект под названием "hello-world".
+1. Будет сгенерировано следующее:
+
+```
+- hello-world
+ - project (sbt использует эту папку для собственных файлов)
+ - build.properties
+ - build.sbt (файл определения сборки sbt)
+ - src
+ - main
+ - scala (здесь весь Scala code)
+ - Main.scala (точка входа в программу) <-- это все, что сейчас нужно
+```
+
+Дополнительную документацию по sbt можно найти в [Scala Book](/scala3/book/tools-sbt.html)
+(см. [здесь](/overviews/scala-book/scala-build-tool-sbt.html) для версии Scala 2)
+и в официальной [документации sbt](https://www.scala-sbt.org/1.x/docs/index.html).
+
+### С интегрированной средой разработки (IDE)
+
+Вы можете пропустить оставшуюся часть страницы и сразу перейти к [созданию проекта Scala с помощью IntelliJ и sbt](/ru/getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.html).
+
+
+## Открыть проект hello-world
+
+Давайте используем IDE, чтобы открыть проект. Самые популярные из них — IntelliJ и VSCode.
+Оба предлагают обширные возможности, но вы по-прежнему можете использовать [множество других редакторов](https://scalameta.org/metals/docs/editors/overview.html).
+
+
+### Использование IntelliJ
+
+1. Загрузите и установите [IntelliJ Community Edition](https://www.jetbrains.com/idea/download/)
+1. Установите Scala plugin, следуя [инструкциям по установке плагинов IntelliJ](https://www.jetbrains.com/help/idea/managing-plugins.html)
+1. Откройте файл `build.sbt`, затем выберете *Open as a project*
+
+### Использование VSCode с metals
+
+1. Загрузите [VSCode](https://code.visualstudio.com/Download)
+1. Установите расширение Metals из [Marketplace](https://marketplace.visualstudio.com/items?itemName=scalameta.metals)
+1. Затем откройте каталог, содержащий файл `build.sbt` (это должен быть каталог `hello-world`, если вы следовали предыдущим инструкциям). Когда будет предложено, выберите *Import build*.
+
+> [Metals](https://scalameta.org/metals) — это “языковой сервер Scala”, обеспечивающий поддержку написания кода Scala в VS Code и других редакторах,
+> таких как [Atom, Sublime Text и других](https://scalameta.org/metals/docs/editors/overview.html), использующих Language Server Protocol.
+>
+> Под капотом Metals взаимодействует со средством сборки с помощью
+> [Build Server Protocol (BSP)](https://build-server-protocol.github.io/).
+> Подробнее о том, как работает Metals, см. [“Написание Scala в VS Code, Vim, Emacs, Atom и Sublime Text с помощью Metals”](https://www.scala-lang.org/2019/04/16/metals.html).
+
+### Знакомство с исходным кодом
+
+Просмотрите эти два файла в своей IDE:
+
+- _build.sbt_
+- _src/main/scala/Main.scala_
+
+При запуске проекта на следующем шаге, конфигурация в _build.sbt_ будет использована для запуска кода в _src/main/scala/Main.scala_.
+
+## Запуск Hello World
+
+Код в _Main.scala_ можно запускать из IDE, если удобно.
+
+Но вы также можете запустить приложение из терминала, выполнив следующие действия:
+
+1. `cd` в `hello-world`.
+1. Запустить `sbt`. Эта команда открывает sbt-консоль.
+1. В консоле введите `~run`. `~` является необязательным, но заставляет sbt повторно запускаться при каждом сохранении файла,
+ обеспечивая быстрый цикл редактирования/запуска/отладки. sbt также создаст директорию `target`, которую пока можно игнорировать.
+
+После окончания экспериментирования с проектом, нажмите `[Enter]`, чтобы прервать команду `run`.
+Затем введите `exit` или нажмите `[Ctrl+D]`, чтобы выйти из sbt и вернуться в командную строку.
+
+## Следующие шаги
+
+После того как пройдете приведенные выше обучающие материалы, подумайте о том, чтобы проверить:
+
+* [The Scala Book](/scala3/book/introduction.html) (см. версию для Scala 2 [здесь](/overviews/scala-book/introduction.html)), которая содержит набор коротких уроков, знакомящих с основными функциями Scala.
+* [The Tour of Scala](/ru/tour/tour-of-scala.html) для краткого ознакомления с функциями Scala.
+* [Обучающие ресурсы](/online-courses.html), которые включают в себя интерактивные онлайн-учебники и курсы.
+* [Наш список некоторых популярных книг по Scala](/books.html).
+* [Руководство по миграции](/scala3/guides/migration/compatibility-intro.html) поможет перенести существующую кодовую базу Scala 2 на Scala 3.
+
+## Получение помощи
+
+Существует множество рассылок и real-time чатов на случай, если вы хотите быстро связаться с другими пользователями Scala.
+Посетите страницу [нашего сообщества](https://scala-lang.org/community/), чтобы ознакомиться со списком этих ресурсов и узнать, куда можно обратиться за помощью.
diff --git a/_ru/getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.md b/_ru/getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.md
new file mode 100644
index 0000000000..dd13a44443
--- /dev/null
+++ b/_ru/getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.md
@@ -0,0 +1,104 @@
+---
+title: Создание проекта Scala с IntelliJ и sbt
+layout: singlepage-overview
+partof: building-a-scala-project-with-intellij-and-sbt
+language: ru
+disqus: true
+previous-page: /ru/getting-started/intellij-track/getting-started-with-scala-in-intellij
+next-page: /ru/testing-scala-in-intellij-with-scalatest
+---
+
+В этом руководстве мы увидим, как создать проект Scala с помощью [sbt](https://www.scala-sbt.org/1.x/docs/index.html).
+sbt — популярный инструмент для компиляции, запуска и тестирования проектов Scala любой сложности.
+Использование инструмента сборки, такого как sbt (или Maven/Gradle), становится необходимым,
+если вы создаете проекты с зависимостями или несколькими файлами кода.
+Мы предполагаем, что вы прочитали [первое руководство](getting-started-with-scala-in-intellij.html).
+
+## Создание проекта
+В этом разделе мы покажем вам, как создать проект в IntelliJ.
+Однако, если вы знакомы с командной строкой, мы рекомендуем вам попробовать
+[Начало работы со Scala и sbt в командной строке]({{site.baseurl}}/ru/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.html)
+а затем вернуться к разделу "Написание Scala кода".
+
+1. Если вы не создавали проект из командной строки, откройте IntelliJ и выберите "Create New Project"
+ * На левой панели выберите Scala, а на правой панели - sbt
+ * Нажмите **Next**
+ * Назовите проект "SbtExampleProject"
+1. Если вы уже создали проект в командной строке, откройте IntelliJ, выберите *Import Project* и откройте `build.sbt` файл вашего проекта
+1. Убедитесь, что ваша **JDK version** - это 1.8, а **sbt version** не ниже 0.13.13
+1. Выберите **Use auto-import**, чтобы доступные зависимости загружались автоматически.
+1. Выберите **Finish**
+
+## Разбор структуры каталогов
+sbt создает множество каталогов, которые могут быть полезны, когда вы начнете создавать более сложные проекты.
+На данный момент вы можете игнорировать большинство из них, но вот объяснение, для чего все это:
+
+```
+- .idea (файлы IntelliJ)
+- project (плагины и дополнительные настройки sbt)
+- src (исходные файлы)
+ - main (код приложения)
+ - java (исходные файлы Java)
+ - scala (исходные файлы Scala) <-- это все, что вам сейчас нужно
+ - scala-2.12 (файлы, специфичные для Scala 2.12)
+ - test (модульные тесты)
+- target (сгенерированные файлы)
+- build.sbt (файл определения сборки для sbt)
+```
+
+
+## Написание Scala-кода
+1. На панели слева **Project**, разверните `SbtExampleProject` => `src` => `main`
+1. Щелкните правой кнопкой мыши на `scala` и выберете **New** => **Package**
+1. Назовите пакет `example` и нажмите **OK** (или просто нажмите клавишу **Enter** или **Return**).
+1. Щелкните правой кнопкой мыши на пакете `example` и выберите **New** => **Scala class**
+(если вы не видите эту опцию, щелкните правой кнопкой мыши на `SbtExampleProject`, кликните на **Add Frameworks Support**, выберете **Scala** и продолжите)
+1. Назовите класс `Main` и измените **Kind** на `Object`.
+1. Вставьте следующий код:
+
+```
+@main def run() =
+ val ages = Seq(42, 75, 29, 64)
+ println(s"The oldest person is ${ages.max}")
+```
+
+Примечание: IntelliJ имеет собственную реализацию компилятора Scala,
+и иногда ваш код верен, даже если IntelliJ указывает обратное.
+Вы всегда можете проверить, может ли sbt запустить ваш проект в командной строке.
+
+## Запуск проекта
+1. В меню **Run**, выберите **Edit configurations**
+1. Нажмите кнопку **+** и выберите **sbt Task**.
+1. Назовите задачу `Run the program`.
+1. В поле **Tasks**, введите `~run`. `~` заставляет sbt перекомпилировать
+и повторно запускать проект при каждом сохранении изменений в файле проекта.
+1. Нажмите **OK**.
+1. В меню **Run** нажмите **Run 'Run the program'**.
+1. В коде измените `75` на `61` и посмотрите на обновленные результаты в консоли.
+
+## Добавление зависимости
+Немного меняя тему, давайте посмотрим, как использовать опубликованные библиотеки
+для добавления дополнительных функций в наши приложения.
+1. Откройте `build.sbt` и добавьте следующую строку:
+
+```
+libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2"
+```
+Здесь `libraryDependencies` представляет набор зависимостей,
+и с помощью `+=` мы добавляем зависимость [scala-parser-combinators](https://github.com/scala/scala-parser-combinators)
+к набору зависимостей, которые sbt будет загружать при запуске.
+Теперь в любом файле Scala можно импортировать классы, объекты и т.д. из `scala-parser-combinators` с помощью обычного импорта.
+
+Вы можете найти больше опубликованных библиотек на [Scaladex](https://index.scala-lang.org/), каталоге библиотек Scala,
+где вы также можете скопировать указанную выше информацию о зависимостях для вставки в свой файл `build.sbt`.
+
+## Следующие шаги
+
+Перейдите к следующему руководству из серии _getting started with IntelliJ_ и узнайте, как [тестировать Scala в IntelliJ с помощью ScalaTest](testing-scala-in-intellij-with-scalatest.html).
+
+**или**
+
+* [The Scala Book](/scala3/book/introduction.html), содержащая набор коротких уроков, знакомящих с основными функциями Scala.
+* [Тур по Scala](/ru/tour/tour-of-scala.html) для краткого ознакомления с возможностями Scala.
+- Продолжайте изучать Scala в интерактивном режиме на
+ [Scala Exercises](https://www.scala-exercises.org/scala_tutorial).
diff --git a/_ru/getting-started/intellij-track/getting-started-with-scala-in-intellij.md b/_ru/getting-started/intellij-track/getting-started-with-scala-in-intellij.md
new file mode 100644
index 0000000000..65337bc058
--- /dev/null
+++ b/_ru/getting-started/intellij-track/getting-started-with-scala-in-intellij.md
@@ -0,0 +1,124 @@
+---
+title: Начало работы со Scala в IntelliJ
+layout: singlepage-overview
+partof: getting-started-with-scala-in-intellij
+language: ru
+disqus: true
+next-page: /ru/building-a-scala-project-with-intellij-and-sbt
+---
+
+В этом руководстве мы увидим, как создать минимальный проект Scala с помощью IntelliJ IDE со Scala плагином.
+В этом руководстве IntelliJ загрузит Scala за вас.
+
+## Установка
+
+1. Убедитесь, что у вас установлена Java 8 JDK (также известная как 1.8)
+ * Запустите `javac -version` в командной строке и убедитесь, что выдается
+ `javac 1.8.___`
+ * Если у вас нет версии 1.8 или выше, [установите JDK](https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
+1. Затем загрузите и установите [IntelliJ Community Edition](https://www.jetbrains.com/idea/download/)
+1. Затем, после запуска IntelliJ, вы можете загрузить и установить Scala плагин, следуя
+ [инструкции по установке плагинов IntelliJ](https://www.jetbrains.com/help/idea/installing-updating-and-uninstalling-repository-plugins.html) (найдите "Scala" в меню плагинов).
+
+Когда мы создадим проект, то установим последнюю версию Scala.
+Примечание: Если вы хотите открыть существующий проект Scala, вы можете нажать **Open**
+при запуске IntelliJ.
+
+## Создание проекта
+
+1. Откройте IntelliJ и нажмите **File** => **New** => **Project**
+1. На левой панели выберите Scala. На правой панели - IDEA.
+1. Назовите проект **HelloWorld**
+1. Если вы впервые создаете Scala проект с помощью IntelliJ, вам необходимо установить Scala SDK.
+ Справа от поля Scala SDK нажмите кнопку **Create**.
+1. Выберите последний номер версии (например, {{ site.scala-version }}) и нажмите **Download**.
+Это может занять несколько минут, но тот же пакет SDK могут использовать последующие проекты.
+1. Когда SDK будет установлен и вы вернетесь в окно "New Project", нажмите **Finish**.
+
+## Написание кода
+
+1. На левой панели **Project** щелкните правой кнопкой мыши на папке `src` и выберите
+**New** => **Scala class**. Если вы не видите **Scala class**, щелкните правой кнопкой мыши на **HelloWorld**
+и выберите **Add Framework Support...**, затем - **Scala** и продолжить.
+Если вы видите ошибку **Error: library is not specified**, вы можете либо нажать кнопку загрузки,
+либо выбрать путь к библиотеке вручную. Если вы видите только **Scala Worksheet** попробуйте развернуть папку `src`
+и её подпапку `main`, а затем правой кнопкой мыши на папке `scala`.
+1. Назовите класс `Hello` и измените **Kind** на `object`.
+1. Вставьте следующий код:
+
+{% tabs hello-world-entry-point class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=hello-world-entry-point %}
+
+```
+object Hello extends App {
+ println("Hello, World!")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=hello-world-entry-point %}
+
+```
+@main def hello(): Unit =
+ println("Hello, World!")
+```
+
+В Scala 3 вы можете удалить объект `Hello` и вместо него определить метод верхнего уровня `hello`
+с аннотацией `@main`.
+
+{% endtab %}
+
+{% endtabs %}
+
+## Запуск
+
+{% tabs hello-world-run class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=hello-world-run %}
+
+* Щелкните правой кнопкой мыши на `Hello` в своем коде и выберите **Run 'Hello'**.
+* Готово!
+
+{% endtab %}
+
+{% tab 'Scala 3' for=hello-world-run %}
+
+* Щелкните правой кнопкой мыши на `hello` в своем коде и выберите **Run 'hello'**.
+* Готово!
+
+{% endtab %}
+
+{% endtabs %}
+
+## Эксперименты со Скалой
+
+Хороший способ попробовать примеры кода — использовать Scala Worksheets.
+
+1. В левой панели проекта щелкните правой кнопкой мыши на
+`src` и выберите **New** => **Scala Worksheet**.
+2. Назовите новый Scala worksheet "Mathematician".
+3. Введите следующий код в worksheet:
+
+{% tabs square %}
+{% tab 'Scala 2 and 3' for=square %}
+```
+def square(x: Int): Int = x * x
+
+square(2)
+```
+{% endtab %}
+{% endtabs %}
+
+После запуска кода вы заметите, что результаты его выполнения выводятся на правой панели.
+Если вы не видите правую панель, щелкните правой кнопкой мыши на вашем Scala worksheet на панели "Проект"
+и выберите "Evaluate Worksheet".
+
+## Следующие шаги
+
+Теперь вы знаете, как создать простой Scala проект, который можно использовать для изучения языка.
+В следующем уроке мы представим важный инструмент сборки под названием sbt,
+который можно использовать для простых проектов и рабочих приложений.
+
+Далее: [Создание проекта Scala с IntelliJ и sbt](building-a-scala-project-with-intellij-and-sbt.html)
diff --git a/_ru/getting-started/intellij-track/testing-scala-in-intellij-with-scalatest.md b/_ru/getting-started/intellij-track/testing-scala-in-intellij-with-scalatest.md
new file mode 100644
index 0000000000..7a2ffef8fe
--- /dev/null
+++ b/_ru/getting-started/intellij-track/testing-scala-in-intellij-with-scalatest.md
@@ -0,0 +1,73 @@
+---
+title: Тестирование Scala в IntelliJ с помощью ScalaTest
+layout: singlepage-overview
+partof: testing-scala-in-intellij-with-scalatest
+language: ru
+disqus: true
+previous-page: /ru/building-a-scala-project-with-intellij-and-sbt
+---
+
+Для Scala существует множество библиотек и методологий тестирования,
+но в этом руководстве мы продемонстрируем один популярный вариант из фреймворка ScalaTest
+под названием [AnyFunSuite](https://www.scalatest.org/getting_started_with_fun_suite).
+
+Это предполагает, что вы знаете, [как создать проект в IntelliJ](building-a-scala-project-with-intellij-and-sbt.html).
+
+## Настройка
+1. Создайте sbt проект в IntelliJ.
+1. Добавьте зависимость ScalaTest:
+ 1. Добавьте зависимость ScalaTest в свой файл `build.sbt`:
+ ```
+ libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.19" % Test
+ ```
+ 1. Если вы получили уведомление "build.sbt was changed", выберите **auto-import**.
+ 1. Эти два действия заставят `sbt` подгрузить библиотеки ScalaTest.
+ 1. Дождитесь окончания синхронизации `sbt`; в противном случае, `AnyFunSuite` и `test()` не будет распознаны.
+1. На панели проекта слева разверните `src` => `main`.
+1. Щелкните правой кнопкой мыши на `scala` и выберите **New** => **Scala class**.
+1. Назовите новый класс `CubeCalculator`, измените **Kind** на `object`, или дважды щелкните на `object`.
+1. Вставьте следующий код:
+ ```
+ object CubeCalculator:
+ def cube(x: Int) =
+ x * x * x
+ ```
+
+## Создание теста
+1. На панели проекта слева разверните `src` => `test`.
+1. Щелкните правой кнопкой мыши на `scala` и выберите **New** => **Scala class**.
+1. Назовите новый класс `CubeCalculatorTest` и нажмите **Enter** или дважды щелкните на `class`.
+1. Вставьте следующий код:
+ ```
+ import org.scalatest.funsuite.AnyFunSuite
+
+ class CubeCalculatorTest extends AnyFunSuite:
+ test("CubeCalculator.cube") {
+ assert(CubeCalculator.cube(3) === 27)
+ }
+ ```
+1. В исходном коде щелкните правой кнопкой мыши на `CubeCalculatorTest` и выберите
+ **Run 'CubeCalculatorTest'**.
+
+## Разбор кода
+
+Давайте разберем код построчно:
+
+* `class CubeCalculatorTest` означает, что мы тестируем `CubeCalculator`
+* `extends AnyFunSuite` позволяет нам использовать функциональность класса AnyFunSuite из ScalaTest,
+ такую как функция `test`
+* `test` это функция из библиотеки FunSuite, которая собирает результаты проверок в теле функции.
+* `"CubeCalculator.cube"` - это имя для теста. Вы можете называть тест как угодно, но по соглашению используется имя — "ClassName.methodName".
+* `assert` принимает логическое условие и определяет, пройден тест или нет.
+* `CubeCalculator.cube(3) === 27` проверяет, действительно ли вывод функции `cube` равен 27.
+ `===` является частью ScalaTest и предоставляет понятные сообщения об ошибках.
+
+## Добавление еще одного теста
+1. Добавьте еще один оператор `assert` после первого, который проверяет 0 в кубе.
+1. Перезапустите тест `CubeCalculatorTest`, кликнув правой кнопкой мыши и выбрав
+ **Run 'CubeCalculatorTest'**.
+
+## Заключение
+Вы видели один из способов тестирования Scala кода.
+Узнать больше о AnyFunSuite от ScalaTest можно на [официальном сайте](https://www.scalatest.org/getting_started_with_fun_suite).
+Вы также можете использовать другие тестовые фреймворки, такие, как [ScalaCheck](https://www.scalacheck.org/) и [Specs2](https://etorreborre.github.io/specs2/).
diff --git a/_ru/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.md b/_ru/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.md
new file mode 100644
index 0000000000..f404e3daf8
--- /dev/null
+++ b/_ru/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.md
@@ -0,0 +1,111 @@
+---
+title: Начало работы со Scala и sbt в командной строке
+layout: singlepage-overview
+partof: getting-started-with-scala-and-sbt-on-the-command-line
+language: ru
+disqus: true
+next-page: /ru/testing-scala-with-sbt-on-the-command-line
+---
+
+В этом руководстве вы увидите, как создавать проекты Scala из шаблона.
+Это можно использовать как отправную точку для своих собственных проектов.
+Мы будем использовать [sbt](https://www.scala-sbt.org/1.x/docs/index.html), де-факто инструмент сборки для Scala.
+sbt компилирует, запускает и тестирует ваши проекты среди других связанных задач.
+Мы предполагаем, что вы знаете, как пользоваться терминалом.
+
+## Установка
+1. Убедитесь, что у вас установлена Java 8 JDK (также известная как 1.8)
+ * Запустите `javac -version` в командной строке и убедитесь, что выдается
+ `javac 1.8.___`
+ * Если у вас нет версии 1.8 или выше, [установите JDK](https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
+1. Установите sbt
+ * [Mac](https://www.scala-sbt.org/1.x/docs/Installing-sbt-on-Mac.html)
+ * [Windows](https://www.scala-sbt.org/1.x/docs/Installing-sbt-on-Windows.html)
+ * [Linux](https://www.scala-sbt.org/1.x/docs/Installing-sbt-on-Linux.html)
+
+## Создание проекта
+
+{% tabs sbt-welcome-1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=sbt-welcome-1 %}
+
+1. `cd` в пустую папку.
+1. Запустите следующую команду `sbt new scala/hello-world.g8`.
+ Она извлекает шаблон 'hello-world' из GitHub.
+ Она также создаст папку `target`, которую пока можно игнорировать.
+1. При появлении запроса назовите приложение `hello-world`. Это создаст проект под названием "hello-world".
+1. Давайте взглянем на то, что только что было сгенерировано:
+
+{% endtab %}
+{% tab 'Scala 3' for=sbt-welcome-1 %}
+
+1. `cd` в пустую папку.
+1. Запустите следующую команду `sbt new scala/scala3.g8`.
+ Она извлекает шаблон 'scala3' из GitHub.
+ Она также создаст папку `target`, которую пока можно игнорировать.
+1. При появлении запроса назовите приложение `hello-world`. Это создаст проект под названием "hello-world".
+1. Давайте взглянем на то, что только что было сгенерировано:
+
+{% endtab %}
+{% endtabs %}
+
+
+```
+- hello-world
+ - project (sbt использует эту папку для установки и настройки плагинов и зависимостей)
+ - build.properties
+ - src
+ - main
+ - scala (весь Scala код находится в этой папке)
+ - Main.scala (точка входа в программу) <-- это все, что вам сейчас нужно
+ - build.sbt (файл определения сборки для sbt)
+```
+
+После того как вы создадите свой проект, sbt создаст дополнительные каталоги `target` для сгенерированных файлов.
+Вы можете игнорировать их.
+
+## Запуск проекта
+1. `cd` в `hello-world`.
+1. Запустите `sbt`. Эта команда запустит sbt console.
+1. Запустите `~run`. `~` опциональна и заставляет sbt перекомпилировать
+ и повторно запускать проект при каждом сохранении изменений в файле проекта
+ для быстрого цикла редактирование/запуск/отладка.
+ sbt также сгенерит директорию `target`, которую можно игнорировать.
+
+## Доработка кода
+1. Откройте файл `src/main/scala/Main.scala` в вашем любимом текстовом редакторе.
+1. Измените "Hello, World!" на "Hello, New York!"
+1. Если вы не остановили команду sbt, то должны увидеть "Hello, New York!", напечатанным в консоли.
+1. Вы можете продолжить вносить изменения и видеть результаты доработки в консоли.
+
+## Добавление зависимости
+Немного меняя тему, давайте посмотрим, как использовать опубликованные библиотеки
+для добавления дополнительных функций в наши приложения.
+
+1. Откройте `build.sbt` и добавьте следующую строку:
+
+```
+libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2"
+```
+Здесь `libraryDependencies` представляет набор зависимостей,
+и с помощью `+=` мы добавляем зависимость [scala-parser-combinators](https://github.com/scala/scala-parser-combinators)
+к набору зависимостей, которые sbt будет загружать при запуске.
+Теперь в любом файле Scala можно импортировать классы, объекты и т.д. из `scala-parser-combinators` с помощью обычного импорта.
+
+Вы можете найти больше опубликованных библиотек на [Scaladex](https://index.scala-lang.org/), каталоге библиотек Scala,
+где вы также можете скопировать указанную выше информацию о зависимостях для вставки в свой файл `build.sbt`.
+
+> **Примечание для Java библиотек:** Для обычной библиотеки Java следует использовать только один знак процента (`%`)
+> между названием организации и именем артефакта. Двойной процент (`%%`) — это специализация Scala библиотек.
+> Подробнее об этом можно узнать в [документации sbt][sbt-docs-lib-dependencies].
+
+## Следующие шаги
+
+Перейдите к следующему учебнику из серии _getting started with sbt_ и узнайте, как [тестировать Scala c sbt и ScalaTest в командной строке](testing-scala-with-sbt-on-the-command-line.html).
+
+**или**
+
+- Продолжайте изучать Scala в интерактивном режиме на
+ [Scala Exercises](https://www.scala-exercises.org/scala_tutorial).
+- Узнайте о возможностях Scala с помощью небольших статей, ознакомившись с нашим [туром по Scala]({{ site.baseurl }}/ru/tour/tour-of-scala.html).
+
+[sbt-docs-lib-dependencies]: https://www.scala-sbt.org/1.x/docs/Library-Dependencies.html#Getting+the+right+Scala+version+with
diff --git a/_ru/getting-started/sbt-track/testing-scala-with-sbt-on-the-command-line.md b/_ru/getting-started/sbt-track/testing-scala-with-sbt-on-the-command-line.md
new file mode 100644
index 0000000000..a74aa92a19
--- /dev/null
+++ b/_ru/getting-started/sbt-track/testing-scala-with-sbt-on-the-command-line.md
@@ -0,0 +1,105 @@
+---
+title: Тестирование Scala c sbt и ScalaTest в командной строке
+layout: singlepage-overview
+partof: testing-scala-with-sbt-on-the-command-line
+language: ru
+disqus: true
+previous-page: /ru/getting-started-with-scala-and-sbt-on-the-command-line
+---
+
+Для Scala существует множество библиотек и методологий тестирования,
+но в этом руководстве мы продемонстрируем один популярный вариант из фреймворка ScalaTest
+под названием [AnyFunSuite](https://www.scalatest.org/getting_started_with_fun_suite).
+
+Это предполагает, что вы знаете, [как создать проект с sbt](getting-started-with-scala-and-sbt-on-the-command-line.html).
+
+## Настройка
+1. Используя командную строку создайте новую директорию.
+1. Перейдите (`cd`) в этот каталог и запустите `sbt new scala/scalatest-example.g8`.
+1. Назовите проект `ScalaTestTutorial`.
+1. Проект поставляется с зависимостью ScalaTest в файле `build.sbt`.
+1. Перейдите (`cd`) в этот каталог и запустите `sbt test`. Это запустит набор тестов
+`CubeCalculatorTest` с одним тестом под названием `CubeCalculator.cube`.
+
+```
+sbt test
+[info] Loading global plugins from /Users/username/.sbt/0.13/plugins
+[info] Loading project definition from /Users/username/workspace/sandbox/my-something-project/project
+[info] Set current project to scalatest-example (in build file:/Users/username/workspace/sandbox/my-something-project/)
+[info] CubeCalculatorTest:
+[info] - CubeCalculator.cube
+[info] Run completed in 267 milliseconds.
+[info] Total number of tests run: 1
+[info] Suites: completed 1, aborted 0
+[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
+[info] All tests passed.
+[success] Total time: 1 s, completed Feb 2, 2017 7:37:31 PM
+```
+
+## Разбор кода
+1. Откройте два файла в текстовом редакторе:
+ * `src/main/scala/CubeCalculator.scala`
+ * `src/test/scala/CubeCalculatorTest.scala`
+1. В файле `CubeCalculator.scala` увидите определение функции `cube`.
+1. В файле `CubeCalculatorTest.scala` тестируемый класс, названный так же как и объект.
+
+```
+ import org.scalatest.funsuite.AnyFunSuite
+
+ class CubeCalculatorTest extends AnyFunSuite:
+ test("CubeCalculator.cube") {
+ assert(CubeCalculator.cube(3) === 27)
+ }
+```
+
+Давайте разберем код построчно:
+
+* `class CubeCalculatorTest` означает, что мы тестируем `CubeCalculator`
+* `extends AnyFunSuite` позволяет нам использовать функциональность класса AnyFunSuite из ScalaTest,
+ такую как функция `test`
+* `test` это функция из библиотеки FunSuite, которая собирает результаты проверок в теле функции.
+* `"CubeCalculator.cube"` - это имя для теста. Вы можете называть тест как угодно, но по соглашению используется имя — "ClassName.methodName".
+* `assert` принимает логическое условие и определяет, пройден тест или нет.
+* `CubeCalculator.cube(3) === 27` проверяет, действительно ли вывод функции `cube` равен 27.
+ `===` является частью ScalaTest и предоставляет понятные сообщения об ошибках.
+
+## Добавление еще одного теста
+1. Добавьте еще один тестовый блок с собственным оператором assert, который проверяет 0 в кубе.
+
+ ```
+ import org.scalatest.funsuite.AnyFunSuite
+
+ class CubeCalculatorTest extends AnyFunSuite {
+ test("CubeCalculator.cube 3 should be 27") {
+ assert(CubeCalculator.cube(3) === 27)
+ }
+
+ test("CubeCalculator.cube 0 should be 0") {
+ assert(CubeCalculator.cube(0) === 0)
+ }
+ }
+ ```
+
+1. Запустите `sbt test` еще раз, чтобы увидеть результаты.
+
+ ```
+ sbt test
+ [info] Loading project definition from C:\projects\scalaPlayground\scalatestpractice\project
+ [info] Loading settings for project root from build.sbt ...
+ [info] Set current project to scalatest-example (in build file:/C:/projects/scalaPlayground/scalatestpractice/)
+ [info] Compiling 1 Scala source to C:\projects\scalaPlayground\scalatestpractice\target\scala-2.13\test-classes ...
+ [info] CubeCalculatorTest:
+ [info] - CubeCalculator.cube 3 should be 27
+ [info] - CubeCalculator.cube 0 should be 0
+ [info] Run completed in 257 milliseconds.
+ [info] Total number of tests run: 2
+ [info] Suites: completed 1, aborted 0
+ [info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0
+ [info] All tests passed.
+ [success] Total time: 3 s, completed Dec 4, 2019 10:34:04 PM
+ ```
+
+## Заключение
+Вы видели один из способов тестирования Scala кода.
+Узнать больше о AnyFunSuite от ScalaTest можно на [официальном сайте](https://www.scalatest.org/getting_started_with_fun_suite).
+Вы также можете использовать другие тестовые фреймворки, такие, как [ScalaCheck](https://www.scalacheck.org/) и [Specs2](https://etorreborre.github.io/specs2/).
diff --git a/_ru/index.md b/_ru/index.md
index b7678c8bfa..7ac8c2a455 100644
--- a/_ru/index.md
+++ b/_ru/index.md
@@ -1,42 +1,50 @@
---
-layout: inner-page-documentation
-title: Документация
+layout: landing-page
+title: Изучаем Scala
language: ru
partof: documentation
-discourse: true
-
-# Content masthead links
more-resources-label: Дополнительные Материалы
-sections:
- - title: "Для новичков"
+sections:
+ - title: "Первые шаги..."
links:
- - title: "Самое начало"
- description: "Установка Scala на ваш компьютер и написание пробного Scala кода!"
+ - title: "Приступая к работе"
+ description: "Установите Scala на свой компьютер и начните писать код на Scala!"
icon: "fa fa-rocket"
- link: /getting-started.html
+ link: /ru/getting-started/install-scala.html
- title: "Тур по Scala"
description: "Вступительный обзор по основным возможностям языка."
icon: "fa fa-flag"
link: /ru/tour/tour-of-scala.html
- - title: "для Java программистов"
- description: "Быстрое знакомство со Scala для тех кто уже знает Java."
- icon: "fa fa-coffee"
- link: /tutorials/scala-for-java-programmers.html
- more-resources:
+ - title: "Книга по Scala 3"
+ description: "Изучайте Scala используя серию коротких уроков."
+ icon: "fa fa-book-open"
+ link: /ru/scala3/book/introduction.html
+ - title: "Набор инструментов Scala"
+ description: "Отправка HTTP-запросов, запись файлов, запуск программ, обработка JSON..."
+ icon: "fa fa-toolbox"
+ link: /toolkit/introduction.html
- title: Онлайн Курсы, Упражнения и Блоги
- url: /learn.html
+ description: "Обучающие курсы по Scala от новичка до продвинутого уровня."
+ icon: "fa fa-cloud"
+ link: /online-courses.html
- title: Книги
- url: /books.html
+ description: "Напечатанные, а также электронные книги о Scala."
+ icon: "fa fa-book"
+ link: /books.html
+ - title: Уроки
+ description: "Пройдемся по серии коротких шагов по созданию Scala приложений."
+ icon: "fa fa-tasks"
+ link: /tutorials.html
- title: "Для опытных"
links:
- title: "API"
- description: "API документация для всех версий Scala."
- icon: "fa fa-file-text"
+ description: "Документация по API для каждой версии Scala."
+ icon: "fa fa-file-alt"
link: /api/all.html
- - title: "Обзоры"
- description: "Подробная документация, охватывающая возможности Scala."
+ - title: "Справочники"
+ description: "Подробные справочники по отдельным разделам языка."
icon: "fa fa-database"
link: /ru/overviews/index.html
- title: "Стилистика"
@@ -48,23 +56,49 @@ sections:
icon: "fa fa-list"
link: /ru/cheatsheets/index.html
- title: "Вопрос-Ответ"
- description: "Список по наиболее часто задаваемых вопросов с ответами по функционалу Scala"
+ description: "Список по наиболее часто задаваемым вопросам с ответами по функционалу Scala."
icon: "fa fa-question-circle"
link: /tutorials/FAQ/index.html
- - title: "Спецификация"
- description: "Официальная спецификация языка Scala"
+ - title: "Спецификация v2.x"
+ description: "Официальная спецификация языка Scala 2."
icon: "fa fa-book"
link: https://scala-lang.org/files/archive/spec/2.13/
+ - title: "Спецификация v3.x"
+ description: "Официальная спецификация языка Scala 3."
+ icon: "fa fa-book"
+ link: https://scala-lang.org/files/archive/spec/3.4/
+ - title: "Справочник по языку Scala 3"
+ description: "Справочник по языку Scala 3."
+ icon: "fa fa-book"
+ link: https://docs.scala-lang.org/scala3/reference
+
+ - title: "Исследуем Scala 3"
+ links:
+ - title: "Руководство по миграции"
+ description: "Руководство, которое поможет вам перейти от Scala 2 к Scala 3."
+ icon: "fa fa-suitcase"
+ link: /scala3/guides/migration/compatibility-intro.html
+ - title: "Новое в Scala 3"
+ description: "Обзор новой функциональности в Scala 3."
+ icon: "fa fa-star"
+ link: /ru/scala3/new-in-scala3.html
+ - title: "Новая функциональность Scaladoc для Scala 3"
+ description: "Ключевые особенности новой функциональности Scaladoc."
+ icon: "fa fa-star"
+ link: /ru/scala3/scaladoc.html
+ - title: "Выступления"
+ description: "Доступные онлайн выступления о Scala 3."
+ icon: "fa fa-play-circle"
+ link: /ru/scala3/talks.html
- title: "Развитие Scala"
links:
- - title: "SIPs"
- description: "Процесс улучшения Scala (Scala Improvement Process). Эволюция языка и компилятора."
+ - title: "Процесс улучшения Scala"
+ description: "Описание процесса развития языка и список всех предложений по улучшению Scala (SIP)."
icon: "fa fa-cogs"
link: /sips/index.html
- - title: "SPP"
- description: "Развитие платформы Scala. Развитие библиотек, движимое сообществом."
- icon: "fa fa-users"
- link: https://platform.scala-lang.org
-
+ - title: "Станьте участником развития Scala"
+ description: "От начала до конца: узнайте, как вы можете помочь открытой экосистеме Scala."
+ icon: "fa fa-code-branch"
+ link: /contribute/
---
diff --git a/_ru/online-courses.md b/_ru/online-courses.md
new file mode 100644
index 0000000000..2ec0c26bc9
--- /dev/null
+++ b/_ru/online-courses.md
@@ -0,0 +1,62 @@
+---
+title: Online ресурсы
+layout: singlepage-overview
+language: ru
+redirect-from:
+ - /learn.html
+---
+
+## Попробуй Scala в своем браузере!
+
+Существует несколько веб-сайтов, на которых вы можете интерактивно запускать код Scala в своем браузере!
+Взгляните на [Scastie](https://scastie.scala-lang.org/).
+
+## Онлайн-курсы от Scala Center
+
+[Scala Center](https://scala.epfl.ch) стремится создавать высококачественные и бесплатные онлайн-курсы
+для изучения Scala и функционального программирования.
+Уровни курса варьируются от начального до продвинутого.
+Более подробная информация доступна [на следующей странице]({% link scalacenter-courses.md %}).
+
+## Упражнения на языке Scala
+
+[Scala Exercises](https://www.scala-exercises.org/) — это серия уроков и упражнений, созданных [47 Degrees](https://www.47deg.com/).
+Это отличный способ получить краткое представление о Scala и одновременно проверить свои знания.
+
+[Tour of Scala](https://tourofscala.com) шаг за шагом знакомит вас со Scala, от новичка до эксперта.
+
+## Лекции доктора Mark C Lewis из Trinity University
+
+[Dr. Mark C Lewis](https://www.cs.trinity.edu/~mlewis/) из Университета Тринити, Сан-Антонио, Техас,
+преподает курсы программирования с использованием языка Scala.
+Видеокурсы доступны на YouTube бесплатно. Некоторые курсы ниже.
+
+- [Introduction to Programming and Problem Solving Using Scala](https://www.youtube.com/playlist?list=PLLMXbkbDbVt9MIJ9DV4ps-_trOzWtphYO)
+- [Object-Orientation, Abstraction, and Data Structures Using Scala](https://www.youtube.com/playlist?list=PLLMXbkbDbVt8JLumqKj-3BlHmEXPIfR42)
+
+Вы можете посетить его [YouTube канал](https://www.youtube.com/user/DrMarkCLewis/featured),
+чтобы найти больше видео.
+
+## Сообщество обучения Scala
+
+[Сообщество по изучению Scala в Discord](http://sca.la/learning-community) — растущее онлайн-сообщество,
+объединяющее учащихся с онлайн-ресурсами для совместного изучения Scala.
+
+## allaboutscala
+
+[allaboutscala](https://allaboutscala.com/) предоставляет подробные руководства для начинающих.
+
+## DevInsideYou
+
+[DevInsideYou](https://youtube.com/devinsideyou) — это YouTube канал с сотнями часов бесплатного контента Scala.
+
+## Rock the JVM
+
+[Rock the JVM](https://rockthejvm.com) — это учебная платформа с бесплатными и платными курсами
+по языку Scala, Akka, Cats Effect, ZIO, Apache Spark и другим инструментам экосистемы Scala.
+Он также содержит сотни [бесплатных видеоуроков](https://youtube.com/rockthejvm)
+и [статей](https://blog.rockthejvm.com) по различным темам, связанным со Scala.
+
+## Visual Scala Reference
+
+[Visual Scala Reference](https://superruzafa.github.io/visual-scala-reference/) — руководство по визуальному изучению концепций и функций Scala.
diff --git a/_ru/overviews/collections-2.13/arrays.md b/_ru/overviews/collections-2.13/arrays.md
index 7e71da1027..856c08002c 100644
--- a/_ru/overviews/collections-2.13/arrays.md
+++ b/_ru/overviews/collections-2.13/arrays.md
@@ -1,22 +1,16 @@
---
layout: multipage-overview
title: Массивы
-
-discourse: true
-
partof: collections-213
overview-name: Collections
-
num: 10
previous-page: concrete-mutable-collection-classes
next-page: strings
language: ru
-
---
[Массивы](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/Array.html) особый вид коллекций в Scala.
-С одной стороны, Scala массивы соответствуют массивам из Java. Например, Scala массив `Array[Int]` реализован в виде Java `int[]`, а `Array[Double]` как Java `double[]` и `Array[String]` как Java `String[]`
- С другой стороны, Scala массивы дают намного больше чем их Java аналоги. Во-первых Scala массивы могут быть обобщены (_generic_). То есть вы можете описать массив как `Array[T]`, где `T` дополнительный `параметр-тип` массива или же абстрактный тип.
+С одной стороны, Scala массивы соответствуют массивам из Java. Например, Scala массив `Array[Int]` реализован в виде Java `int[]`, а `Array[Double]` как Java `double[]` и `Array[String]` как Java `String[]`. С другой стороны, Scala массивы дают намного больше чем их Java аналоги. Во-первых, Scala массивы могут быть обобщены (_generic_). То есть вы можете описать массив как `Array[T]`, где `T` дополнительный `параметр-тип` массива или же абстрактный тип.
Во-вторых, Scala массивы совместимы со списками (`Seq`) Scala - вы можете передавать `Array[T]` на вход туда, где требуется `Seq[T]`. Ну и наконец, Scala массивы также поддерживают все операции, которые есть у списков. Вот пример:
scala> val a1 = Array(1, 2, 3)
@@ -28,7 +22,7 @@ language: ru
scala> a3.reverse
res0: Array[Int] = Array(9, 3)
-Учитывая то что Scala массивы соответствуют массивам из Java, каким же образом реализованы остальные дополнительные возможности массивов в Scala?
+Учитывая то, что Scala массивы соответствуют массивам из Java, каким же образом реализованы остальные дополнительные возможности массивов в Scala?
Реализация массивов в Scala постоянно использует неявные преобразования. В Scala массив не пытается _притворяться_ последовательностью. Он и не может, потому что тип данных лежащий в основе массива не является подтипом `Seq`. Вместо этого, используя "упаковывание", происходит неявное преобразование между массивами и экземплярами класса `scala.collection.mutable.ArraySeq`, который является подклассом `Seq`. Вот как это работает:
scala> val seq: collection.Seq[Int] = a1
@@ -55,7 +49,7 @@ language: ru
Вы видите, что вызов `reverse` на `seq`, который является `ArraySeq`, даст снова `ArraySeq`. Это логично, потому что массивы - это `Seqs`, и вызов `reverse` на любом `Seq` даст снова `Seq`. С другой стороны, вызов `reverse` на экземпляре класса `ArrayOps` даст значение `Array`, а не `Seq`.
-Пример `ArrayOps`, приведенный выше искусственный и используется лишь, чтоб показать разницу с `ArraySeq`. Обычно, вы никогда не создаете экземпляры класса `ArrayOps`. Вы просто вызываете методы `Seq` на массиве:
+Пример `ArrayOps`, приведенный выше искусственный и используется лишь, чтобы показать разницу с `ArraySeq`. Обычно, вы никогда не создаете экземпляры класса `ArrayOps`. Вы просто вызываете методы `Seq` на массиве:
scala> a1.reverse
res4: Array[Int] = Array(3, 2, 1)
@@ -67,7 +61,7 @@ language: ru
где `intArrayOps` - неявное преобразование, которое было вставлено ранее. В связи с этим возникает вопрос, как компилятор выбрал `intArrayOps` вместо другого неявного преобразования в `ArraySeq` в строке выше. В конце концов, оба преобразования преобразуют массив в тип, поддерживающий метод reverse. Ответ на этот вопрос заключается в том, что два неявных преобразования имеют приоритет. Преобразование `ArrayOps` имеет больший приоритет, чем преобразование `ArraySeq`. Первый определяется в объекте `Predef`, а второй - в классе `scala.LowPriorityImplicits`, который `Predef` наследует. Неявные преобразования в дочерних классах и дочерних объектах имеют более высокий приоритет над преобразованиями в базовых классах. Таким образом, если оба преобразования применимы, выбирается вариант в `Predef`. Очень похожая схема используется для строк.
-Итак, теперь вы знаете, как массивы могут быть совместимы с последовательностями и как они могут поддерживать все операции последовательностей. А как же обобщения? В Java нельзя написать `T[]`, где `T` является параметром типа. Как же представлен Scala `Array[T]`? На самом деле обобщенный массив типа `Array[T]` может быть любым из восьми примитивных типов массивов Java `byte[]`, `short[]`, `char[]`, `int[] `, `long[] `, `float[]`, `double ` или может быть массивом объектов. Единственным общим типом, включающим все эти типы, является `AnyRef` (или, равнозначно `java.lang.Object`), так что это тот тип в который компилятор Scala отобразит `Array[T]`. Во время исполнения, при обращении к элементу массива типа `Array[T]`, происходит последовательность проверок типов, которые определяют тип массива, за которыми следует подходящая операция на Java-массиве. Эти проверки типов замедляют работу массивов. Можно ожидать падения скорости доступа к обобщенным массивам в три-четыре раза, по сравнению с обычными массивами или массивами объектов. Это означает, что если вам нужна максимальная производительность, вам следует выбирать конкретные массивы, вместо обобщенных. Отображать обобщенный массив еще пол беды, нам нужен еще способ создания обобщенных массивов. Это куда более сложная задача, которая требует, от вас, небольшой помощи. Чтобы проиллюстрировать проблему, рассмотрим следующую попытку написания обобщенного метода, который создает массив.
+Итак, теперь вы знаете, как массивы могут быть совместимы с последовательностями и как они могут поддерживать все операции последовательностей. А как же обобщения? В Java нельзя написать `T[]`, где `T` является параметром типа. Как же представлен Scala `Array[T]`? На самом деле обобщенный массив типа `Array[T]` может быть любым из восьми примитивных типов массивов Java `byte[]`, `short[]`, `char[]`, `int[] `, `long[] `, `float[]`, `double ` или может быть массивом объектов. Единственным общим типом, включающим все эти типы, является `AnyRef` (или, равнозначно `java.lang.Object`), так что это тот тип, в который компилятор Scala отобразит `Array[T]`. Во время исполнения, при обращении к элементу массива типа `Array[T]`, происходит последовательность проверок типов, которые определяют тип массива, за которыми следует подходящая операция на Java-массиве. Эти проверки типов замедляют работу массивов. Можно ожидать падения скорости доступа к обобщенным массивам в три-четыре раза, по сравнению с обычными массивами или массивами объектов. Это означает, что если вам нужна максимальная производительность, вам следует выбирать конкретные массивы, вместо обобщенных. Отображать обобщенный массив еще полбеды, нам нужен еще способ создания обобщенных массивов. Это куда более сложная задача, которая требует от вас небольшой помощи. Чтобы проиллюстрировать проблему, рассмотрим следующую попытку написания обобщенного метода, который создает массив.
// это неправильно!
def evenElems[T](xs: Vector[T]): Array[T] = {
diff --git a/_ru/overviews/collections-2.13/concrete-immutable-collection-classes.md b/_ru/overviews/collections-2.13/concrete-immutable-collection-classes.md
index 6da8bcc3e1..e2f94e3455 100644
--- a/_ru/overviews/collections-2.13/concrete-immutable-collection-classes.md
+++ b/_ru/overviews/collections-2.13/concrete-immutable-collection-classes.md
@@ -1,18 +1,12 @@
---
layout: multipage-overview
title: Реализации Неизменяемых Коллекций
-
-discourse: true
-
partof: collections-213
overview-name: Collections
-
previous-page: maps
next-page: concrete-mutable-collection-classes
-
num: 8
language: ru
-
---
Scala предлагает множество конечных реализаций неизменяемых коллекций. Они отличаются реализуемыми трейтами (мапы (map), множества(set), последовательности(seq)), они могут быть бесконечными, и различаются производительностью операций. Вот некоторые из наиболее распространенных неизменяемых типов коллекций, используемых в Scala.
@@ -30,7 +24,7 @@ Scala предлагает множество конечных реализац
scala> val lazyList = 1 #:: 2 #:: 3 #:: LazyList.empty
lazyList: scala.collection.immutable.LazyList[Int] = LazyList(?)
-На первом месте в этом ленивом списке - 1, а на втором - 2 и 3. Но ни один из элементов здесь не выводится, потому что список еще не вычислен! Ленивые списки задуманны обрабатываться лениво, поэтому метод `toString`, не выводит всех элементов, не заставляя производить дополнительные вычисления.
+На первом месте в этом ленивом списке - 1, а на втором - 2 и 3. Но ни один из элементов здесь не выводится, потому что список еще не вычислен! Ленивые списки задуманы обрабатываться лениво, поэтому метод `toString` не выводит всех элементов, не заставляя производить дополнительные вычисления.
Ниже приводится более сложный пример. Вычисления ленивого списка, содержащего последовательность Фибоначчи, которая начинается с заданных двух чисел. Последовательность Фибоначчи - это последовательность, в которой каждый элемент представляет собой сумму двух предыдущих элементов в серии.
@@ -78,7 +72,7 @@ res27: scala.collection.immutable.ArraySeq[Int] = ArraySeq(1, 2, 3)
Как видно из последней строки выше, вызов `updated` не влияет на исходный ArraySeq `arr`.
-ArraySeqs хранят свои элементы в приватном [Массиве](arrays.html). Таким образом достигается компактное представление и обеспечивается быстрый индексированный доступ к элементам, но обновление или добавление одного элемента занимает линейное время, так как требует создания другого массива и копирования всех элементов исходного массива.
+ArraySeqs хранят свои элементы в приватном [Массиве]({% link _ru/overviews/collections-2.13/arrays.md %}). Таким образом достигается компактное представление и обеспечивается быстрый индексированный доступ к элементам, но обновление или добавление одного элемента занимает линейное время, так как требует создания другого массива и копирования всех элементов исходного массива.
## Вектора (Vectors)
@@ -86,7 +80,7 @@ ArraySeqs хранят свои элементы в приватном [Масс
[Вектор](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Vector.html) - тип коллекции, который обеспечивает хорошую производительность для всех своих операций. Вектора позволяют получить доступ к любому элементу последовательности за "практически" постоянное время. Это значит что константа больше, чем при получении переднего (`head`) элемента списка или при чтения элемента из ArraySeq, но, тем не менее, это константа. Избегайте использование векторов в алгоритмах базирующихся на активной работе с передними (`head`) элементами. Вектора могут получать доступ к элементам и изменять их в произвольных местах, что делает разработку более простой и удобной.
-Вектора создаются и модифицируются также как и другие последовательности.
+Вектора создаются и модифицируются так же, как и другие последовательности.
scala> val vec = scala.collection.immutable.Vector.empty
vec: scala.collection.immutable.Vector[Nothing] = Vector()
@@ -97,10 +91,10 @@ ArraySeqs хранят свои элементы в приватном [Масс
scala> vec3(0)
res1: Int = 100
-Вектора представленны деревьями с высоким уровнем ветвления (уровень ветвления дерева или графа - это количество дочерних элементов у каждого узла). Каждый узел дерева содержит до 32х элементов вектора или содержит до 32х других узлов. Вектора с размером до 32х элементов могут быть представленны одним узлом. Вектора `32 * 32 = 1024` элементы могут быть представлены одним витком.
+Вектора представлены деревьями с высоким уровнем ветвления (уровень ветвления дерева или графа - это количество дочерних элементов у каждого узла). Каждый узел дерева содержит до 32х элементов вектора или содержит до 32х других узлов. Вектора с размером до 32х элементов могут быть представлены одним узлом. Вектора `32 * 32 = 1024` элементы могут быть представлены одним витком.
Для векторов с 215 элементами достаточно двух переходов от корня дерева до конечного элемента узла, трех переходов для векторов с 220 элементами, четырех переходов для 225 элементами и пяти переходов для 230 элементами. Таким образом, для всех векторов разумных размеров выбор элемента включает до 5 простых выборок массивов. Именно это мы подразумевали, когда писали, что доступ к элементам осуществляется с "практически постоянным временем".
-Также как и доступ к элементу, операция обновления в векторах занимает "практически" постоянное время. Добавление элемента в середину вектора может быть выполнено через копирование узла содержащего этот элемент и каждого ссылающегося на него узла, начиная от корня дерева. Это означает, что процесс обновления элемента создает от одного до пяти узлов, каждый из которых содержит до 32 элементов или поддеревьев. Это, конечно, дороже, чем просто обновление элемента в изменяемом массиве, но все же намного дешевле, чем копирование вообще всего вектора.
+Так же как и доступ к элементу, операция обновления в векторах занимает "практически" постоянное время. Добавление элемента в середину вектора может быть выполнено через копирование узла содержащего этот элемент и каждого ссылающегося на него узла, начиная от корня дерева. Это означает, что процесс обновления элемента создает от одного до пяти узлов, каждый из которых содержит до 32 элементов или поддеревьев. Это, конечно, дороже, чем просто обновление элемента в изменяемом массиве, но все же намного дешевле, чем копирование вообще всего вектора.
Поскольку вектора обладают хорошим балансом между быстрой случайной выборкой и быстрым случайным обновлением элементов, они используются в качестве реализации неизменяемых индексированных последовательностей:
@@ -157,7 +151,7 @@ ArraySeqs хранят свои элементы в приватном [Масс
Хэш деревья - это стандартный способ эффективного создания неизменяемых множеств и ассоциативных массивов (мап). [Compressed Hash-Array Mapped Prefix-trees](https://github.com/msteindorfer/oopsla15-artifact/) - это специальные хэш деревья для JVM, которые улучшают локальность и обеспечивают компактную и элегантную реализацию деревьев. Они базируются на классе [immutable.HashMap](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/HashMap.html). Их представление очень похоже на реализацию векторов, которые также являются деревьями, где каждый узел имеет либо 32 элемента либо 32 поддерева. Но в данном случае ключ выбирается на основе хэш-кода. Например, чтобы найти ключ на мапе, сначала берут хэш-код ключа. Затем самые младшие 5 бит хэш-кода используются для выбора первого поддерева, за которым следуют следующие 5 бит и так далее. Выбор прекращается, когда для всех битов будут найдены ключи.
-Хэш деревья пытаются предоставить разумный баланс между достаточно быстрым поиском и достаточно эффективными операциями вставки (`+`) и удаления (`-`) элементов. Именно поэтому они лежат в основе стандартных реализаций Scala неизменяемых множеств и ассоциативных массивов (мап). На самом деле, в Scala есть дополнительная оптимизацию для неизменяемых множеств и мап, которые содержат менее пяти элементов. Множества и мапы от одного до четырех элементов хранятся как обычные объекты, которые содержат только элементы (или пары ключ/значение в случае мапы) как поля. Пустое неизменяемое множество и пустая неизменяемая мапа - это всегда объект-сингэлтон - нет необходимости размножать сущности для них, потому что пустое неизменяемое множество или мапа всегда будут оставаться пустыми.
+Хэш деревья пытаются предоставить разумный баланс между достаточно быстрым поиском и достаточно эффективными операциями вставки (`+`) и удаления (`-`) элементов. Именно поэтому они лежат в основе стандартных реализаций Scala неизменяемых множеств и ассоциативных массивов (мап). На самом деле, в Scala есть дополнительная оптимизация для неизменяемых множеств и мап, которые содержат менее пяти элементов. Множества и мапы от одного до четырех элементов хранятся как обычные объекты, которые содержат только элементы (или пары ключ/значение в случае мапы) как поля. Пустое неизменяемое множество и пустая неизменяемая мапа - это всегда объект-сингэлтон - нет необходимости размножать сущности для них, потому что пустое неизменяемое множество или мапа всегда будут оставаться пустыми.
## Красно-Черные Деревья (Red-Black Trees)
diff --git a/_ru/overviews/collections-2.13/concrete-mutable-collection-classes.md b/_ru/overviews/collections-2.13/concrete-mutable-collection-classes.md
index 7152037ce9..1506db43ce 100644
--- a/_ru/overviews/collections-2.13/concrete-mutable-collection-classes.md
+++ b/_ru/overviews/collections-2.13/concrete-mutable-collection-classes.md
@@ -1,25 +1,19 @@
---
layout: multipage-overview
title: Реализации Изменяемых Коллекций
-
-discourse: true
-
partof: collections-213
overview-name: Collections
-
num: 9
previous-page: concrete-immutable-collection-classes
next-page: arrays
-
language: ru
-
---
Вы уже успели увидеть наиболее часто используемые неизменяемые типы коллекции, которые есть в стандартной библиотеке Scala. Настало время посмотреть на изменяемые (mutable) типы коллекции.
## Array Buffers
-[ArrayBuffer](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/ArrayBuffer.html) - буферизированный массив в своем буфере хранит массив и его размер. Большинство операций с буферизированным массивом выполняются с той же скоростью, что и с массивом, так как операции просто обращаются и изменяют исходный массив. Кроме того он может эффективно добавлять данные к своему концу. Присоединение элемента к такому массиву занимает амортизированное константное время. Поэтому буферизированные массивы будут полезны, если вы строите большую коллекцию данных регулярно добавляя новые элементы в конец.
+[ArrayBuffer](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/ArrayBuffer.html) - буферизированный массив в своем буфере хранит массив и его размер. Большинство операций с буферизированным массивом выполняются с той же скоростью, что и с массивом, так как операции просто обращаются и изменяют исходный массив. Кроме того, он может эффективно добавлять данные к своему концу. Присоединение элемента к такому массиву занимает амортизированное константное время. Поэтому буферизированные массивы будут полезны, если вы строите большую коллекцию данных регулярно добавляя новые элементы в конец.
scala> val buf = scala.collection.mutable.ArrayBuffer.empty[Int]
buf: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
@@ -45,7 +39,7 @@ language: ru
## StringBuilders
-Так же, как буферизированный массив полезен для создания массивов, а буферизированный список полезен для построения списков, [StringBuilder](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/StringBuilder.html) полезен для создания строк. StringBuilders настолько широко используются, что они уже импортированы по умолчанию в стандартную область видимости. Можете создать их с помощью `new StringBuilder`, как в следующем примере:
+Так же как буферизированный массив полезен для создания массивов, а буферизированный список полезен для построения списков, [StringBuilder](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/StringBuilder.html) полезен для создания строк. StringBuilders настолько широко используются, что они уже импортированы по умолчанию в стандартную область видимости. Можете создать их с помощью `new StringBuilder`, как в следующем примере:
scala> val buf = new StringBuilder
buf: StringBuilder =
@@ -108,7 +102,7 @@ Scala предоставляет не только неизменяемые, н
Последовательные массивы - это изменяемые массивы со свойствами последовательности фиксированного размера, которые хранят свои элементы внутри `Array[Object]`. Они реализованы в Scala классом [ArraySeq](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/ArraySeq.html).
-Вам стоит использовать `ArraySeq`, если вам нужен массив из-за его показателей производительности, но вы дополнительно хотите использовать обобщеные экземпляры последовательности, в которых вы не знаете тип элементов и у которого нет `ClassTag` который будет предоставлен непосредственно во время исполнения. Эти аспекты рассматриваются в разделе [arrays]({{ site.baseurl }}/overviews/collections/arrays.html).
+Вам стоит использовать `ArraySeq`, если вам нужен массив из-за его показателей производительности, но вы дополнительно хотите использовать обобщеные экземпляры последовательности, в которых вы не знаете тип элементов и у которого нет `ClassTag` который будет предоставлен непосредственно во время исполнения. Эти аспекты рассматриваются в разделе [arrays]({% link _ru/overviews/collections-2.13/arrays.md %}).
## Hash Tables (Хэш Таблицы)
@@ -146,11 +140,11 @@ Scala предоставляет не только неизменяемые, н
| `m.replace(k, old, new)` |Заменяет значение, связанное с ключом `k` на `new`, если ранее оно было равно `old`. |
| `m.replace (k, v)` | Заменяет значение, связанное с ключом `k` на `v`, если ранее значение вообще существовало.|
-`concurrent.Map` это трейт в библиотеке коллекций Scala. В настоящее время он реализуется двумя способами. Первый - через Java мапу `java.util.concurrent.ConcurrentMap`, который может быть автоматически преобразован в Scala мапу с помощью [стандартного механизма преобразования Java/Scala коллекций]({{ site.baseurl }}/overviews/collections/conversions-between-java-and-scala-collections.html). Вторая реализация через [TrieMap](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/concurrent/TrieMap.html), которая представляет из себя не блокируемую хэш-таблицу привязанную к дереву.
+`concurrent.Map` это трейт в библиотеке коллекций Scala. В настоящее время он реализуется двумя способами. Первый - через Java мапу `java.util.concurrent.ConcurrentMap`, который может быть автоматически преобразован в Scala мапу с помощью [стандартного механизма преобразования Java/Scala коллекций]({% link _ru/overviews/collections-2.13/conversions-between-java-and-scala-collections.md %}). Вторая реализация через [TrieMap](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/concurrent/TrieMap.html), которая представляет из себя не блокируемую хэш-таблицу привязанную к дереву.
## Mutable Bitsets (Изменяемый Битовый Набор)
-Изменяемый набор типа [mutable.BitSet](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/BitSet.html) практически такойже как и неизменяемый набор, за исключением того, что он при изменении сам меняется. Изменяемые битовые наборы немного эффективнее при обновлении, чем неизменяемые, так как им не нужно копировать `Long`, которые не изменились.
+Изменяемый набор типа [mutable.BitSet](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/BitSet.html) практически такой же, как и неизменяемый набор, за исключением того, что он при изменении сам меняется. Изменяемые битовые наборы немного эффективнее при обновлении, чем неизменяемые, так как им не нужно копировать `Long`, которые не изменились.
scala> val bits = scala.collection.mutable.BitSet.empty
bits: scala.collection.mutable.BitSet = BitSet()
diff --git a/_ru/overviews/collections-2.13/conversions-between-java-and-scala-collections.md b/_ru/overviews/collections-2.13/conversions-between-java-and-scala-collections.md
index 2471e0121f..0320c0c59d 100644
--- a/_ru/overviews/collections-2.13/conversions-between-java-and-scala-collections.md
+++ b/_ru/overviews/collections-2.13/conversions-between-java-and-scala-collections.md
@@ -1,17 +1,11 @@
---
layout: multipage-overview
title: Преобразования между Java и Scala коллекциями
-
-discourse: true
-
partof: collections-213
overview-name: Collections
-
num: 17
previous-page: creating-collections-from-scratch
-
language: ru
-
---
Как и в Scala, в Java есть богатая библиотека коллекций. Между ними много общего. Например, обе библиотеки предоставляют итераторы, итерируемые сущности, множества, мапы и списки. Но есть и серьезные различия. В частности, библиотека Scala фокусируют больше внимания на неизменяемых коллекциях, предоставляя больше возможностей для преобразования исходной коллекции в новую.
diff --git a/_ru/overviews/collections-2.13/creating-collections-from-scratch.md b/_ru/overviews/collections-2.13/creating-collections-from-scratch.md
index e705778625..5956c8e4a2 100644
--- a/_ru/overviews/collections-2.13/creating-collections-from-scratch.md
+++ b/_ru/overviews/collections-2.13/creating-collections-from-scratch.md
@@ -1,18 +1,12 @@
---
layout: multipage-overview
title: Создание коллекций с нуля
-
-discourse: true
-
partof: collections-213
overview-name: Collections
-
num: 16
previous-page: iterators
next-page: conversions-between-java-and-scala-collections
-
language: ru
-
---
У вас есть синтаксис `List(1, 2, 3)` для создания списка из трех целых чисел и `Map('A' -> 1, 'C' -> 2)` для создания мапы с двумя элементами. На самом деле, это универсальная функциональность коллекций Scala. Можно получить любую коллекцию написав ее название и указав следом список элементов в круглых скобках. В результате получится новая коллекция с заданными элементами. Вот еще несколько примеров:
@@ -55,11 +49,11 @@ language: ru
| `C.empty` | Пустая коллекция. |
| `C(x, y, z)` | Коллекция состоящая из элементов `x, y, z`. |
| `C.concat(xs, ys, zs)` | Коллекция, полученная путем объединения элементов `xs, ys, zs`. |
-| `C.fill(n){e}` | Коллекция длины `n`, где каждый элемент вычисляется выражением`e`. |
+| `C.fill(n){e}` | Коллекция длины `n`, где каждый элемент вычисляется выражением `e`. |
| `C.fill(m, n){e}` | Коллекция коллекций размерности `m×n`, где каждый элемент вычисляется выражением `e`. (существует и в более высоких измерениях). |
| `C.tabulate(n){f}` | Коллекция длины `n`, где элемент каждого индекса i вычисляется с помощью `f(i)`. |
| `C.tabulate(m, n){f}` | Коллекция коллекций измерений `m×n`, где элемент каждого индекса `(i, j)` вычисляется с помощью `f(i, j)`. (существует также в более высоких измерениях). |
| `C.range(start, end)` | Коллекция из целых чисел от `start` до `end-1`. |
| `C.range(start, end, step)`| Коллекция целых чисел, начиная со `start` и продвигаясь на шаг `step` увеличиваясь до конечного значения `end` (не включая его самого) . |
| `C.iterate(x, n)(f)` | Коллекция длины `n` с элементами `x`, `f(x)`, `f(f(x))`, ... |
-| `C.unfold(init)(f)` | Коллекция, использующая функцию `f` для вычисления следующего элемента и состояния, начиная с начального состояния `init`.|
\ No newline at end of file
+| `C.unfold(init)(f)` | Коллекция, использующая функцию `f` для вычисления следующего элемента и состояния, начиная с начального состояния `init`.|
diff --git a/_ru/overviews/collections-2.13/equality.md b/_ru/overviews/collections-2.13/equality.md
index b63d7165f7..e05ee5ee73 100644
--- a/_ru/overviews/collections-2.13/equality.md
+++ b/_ru/overviews/collections-2.13/equality.md
@@ -1,21 +1,15 @@
---
layout: multipage-overview
title: Равенство
-
-discourse: true
-
partof: collections-213
overview-name: Collections
-
num: 13
previous-page: performance-characteristics
next-page: views
-
language: ru
-
---
-Коллекций придерживаются единого подхода к определению равенства и получению хэшей. Идея состоит, во-первых, в том, чтобы разделить коллекции на группы: множества, мапы и последовательности. Коллекции в разных группах всегда различаются. Например, `Set(1,2,3)` неравнозначен списку `List(1,2,3)`, хотя они содержат одни и те же элементы. С другой стороны, в рамках одной и той же группы коллекции равны тогда и только тогда, когда они имеют одинаковые элементы (для последовательностей: одни и те же элементы в одном порядке). Например `List(1, 2, 3) == Vector(1, 2, 3)`, и `HashSet(1, 2) == TreeSet(2, 1)`.
+Коллекции придерживаются единого подхода к определению равенства и получению хэшей. Идея состоит, во-первых, в том, чтобы разделить коллекции на группы: множества, мапы и последовательности. Коллекции в разных группах всегда различаются. Например, `Set(1,2,3)` неравнозначен списку `List(1,2,3)`, хотя они содержат одни и те же элементы. С другой стороны, в рамках одной и той же группы коллекции равны тогда и только тогда, когда они имеют одинаковые элементы (для последовательностей: одни и те же элементы в одном порядке). Например `List(1, 2, 3) == Vector(1, 2, 3)`, и `HashSet(1, 2) == TreeSet(2, 1)`.
Для проверки на равенство не важно, является ли коллекция изменяемой или неизменяемой. Для изменяемой коллекции достаточно просто рассмотреть ее текущие элементы на момент проведения проверки на равенство. Это означает, что коллекция в разные моменты может быть эквивалентна разным коллекциям, в зависимости от того, какие элементы в неё добавляются или удаляются. В этом кроится потенциальная опасность при использовании изменяемой коллекции в качестве ключа для хэшмапы. Пример:
@@ -34,4 +28,4 @@ language: ru
java.util.NoSuchElementException: key not found:
ArrayBuffer(2, 2, 3)
-В этом примере запрос в последней строке, скорее всего, не сработает, так как хэш-код массива `buf` изменился во второй с конца строке. Таким образом, в поиске элемента на основе хэша, будет запрашиваться совсем другой элемент, чем тот что был первоначально сохранен в `map`.
\ No newline at end of file
+В этом примере запрос в последней строке, скорее всего, не сработает, так как хэш-код массива `buf` изменился во второй с конца строке. Таким образом, в поиске элемента на основе хэша, будет запрашиваться совсем другой элемент, чем тот что был первоначально сохранен в `map`.
diff --git a/_ru/overviews/collections-2.13/introduction.md b/_ru/overviews/collections-2.13/introduction.md
index c965ef979e..e97c142eb8 100644
--- a/_ru/overviews/collections-2.13/introduction.md
+++ b/_ru/overviews/collections-2.13/introduction.md
@@ -1,17 +1,11 @@
---
layout: multipage-overview
title: Введение
-
-discourse: true
-
partof: collections-213
overview-name: Collections
-
num: 1
next-page: overview
-
language: ru
-
---
**Martin Odersky и Lex Spoon**
diff --git a/_ru/overviews/collections-2.13/iterators.md b/_ru/overviews/collections-2.13/iterators.md
index ee7c02c50d..3d43d76a8f 100644
--- a/_ru/overviews/collections-2.13/iterators.md
+++ b/_ru/overviews/collections-2.13/iterators.md
@@ -1,18 +1,12 @@
---
layout: multipage-overview
title: Итераторы
-
-discourse: true
-
partof: collections-213
overview-name: Collections
-
num: 15
previous-page: views
next-page: creating-collections-from-scratch
-
language: ru
-
---
Итератор (Iterator) - это не коллекция, а скорее способ поочередного доступа к элементам коллекции. Есть две основные операции у итератора - это `next` и `hasNext`. Вызов метода `it.next()` на итераторе `it` вернет следующий элемент и изменит его состояние. Повторный вызов `next` на том же итераторе выведит следующий элемент идущий после ранее возвращённого. Если больше нет элементов для возврата, вызов команды `next` кинет исключение `NoSuchElementException`. Вы можете узнать, есть ли еще элементы для возврата с помощью метода `hasNext` у [Итератора](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterator.html).
@@ -62,8 +56,8 @@ language: ru
Обратите внимание еще раз, что сам итератор`it` был изменен вызовом `dropWhile`: теперь он указывает на второе слово `number` в списке.
Фактически, `it` и результат `res4` возвращаемый после`dropWhile` возвращают одну и туже последовательность элементов.
-Чтоб избежать такое поведение, как вариант можно использовать `duplicate` (дублировать используемый итератор), вызывая методы на разных итераторах.
-Каждый из _двух_ итераторов будет обрабатывать точно такие же элементы, как и тот из которого состоит итераторатор `it`:
+Чтобы избежать такое поведение, как вариант можно использовать `duplicate` (дублировать используемый итератор), вызывая методы на разных итераторах.
+Каждый из _двух_ итераторов будет обрабатывать точно такие же элементы, как и тот, из которого состоит итераторатор `it`:
scala> val (words, ns) = Iterator("a", "number", "of", "words").duplicate
words: Iterator[String] =
@@ -79,7 +73,7 @@ language: ru
Может создаться впечатление что итератор подвергается двойному обходу над элементами, но это не так, результат достигается за счет внутреннего буферизации.
Как обычно, базовый итератор `it` не пригоден для прямого использования и должен быть исключен из дальнейших операций.
-Обобщая вышесказанное, итераторы ведут себя как коллекции _если после вызова метода на них сам итератор больше не вызывается_. В библиотеке коллекции Scala это достигается явным образом с помощью абстракции [IterableOnce](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/IterableOnce.html), который является общим суперкласом для [Iterable](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterable.html) и [Iterator](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterator.html). У `IterableOnce[A]` только два метода: `iterator: Iterator[A]` и `knownSize: Int`.
+Обобщая вышесказанное, итераторы ведут себя как коллекции, _если после вызова метода на них сам итератор больше не вызывается_. В библиотеке коллекции Scala это достигается явным образом с помощью абстракции [IterableOnce](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/IterableOnce.html), который является общим суперкласом для [Iterable](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterable.html) и [Iterator](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterator.html). У `IterableOnce[A]` только два метода: `iterator: Iterator[A]` и `knownSize: Int`.
Если объект `IterableOnce` является `Iterator`, то его операция `iterator` всегда возвращает себя, в своем текущем состоянии, но если он `Iterable`, то операция `iterator` всегда возвращает новый `Iterator`. Типовой вариант использования `IterableOnce` - в качестве типа аргумента для методов, которые могут принимать или итератор или коллекцию в качестве аргумента. Примером может служить метод соединения `concat` в классе `Iterable`. Он принимает `IterableOnce` параметр, поэтому вы можете соединять элементы, поступающие или из итератора или коллекции.
@@ -174,7 +168,7 @@ language: ru
Поэтому выражение `(1 to 10).iterator.map(println)` не выведет ничего на экран.
Метод `map` в данном случае не применяет функцию в аргументе к значениям в диапазоне, вместо этого будет возвращен новый `Iterator`, который будет выполнять операции тогда когда будет запрошен их результат. Добавление `.toList` в конец этого выражения фактически вызовет вывод элементов на печать.
-Как следствие такие методы как `map` или `filter` не обязательно применят функцию в аргументе ко всем входным элементам. Выражение `(1 to 10).iterator.map(println).take(5).toList` выводит только значения от `1` до `5`, поскольку это те значения, которые запрашиваются у `Iterator`, возвращаемого из `map`.
+Как следствие, такие методы как `map` или `filter` не обязательно применят функцию в аргументе ко всем входным элементам. Выражение `(1 to 10).iterator.map(println).take(5).toList` выводит только значения от `1` до `5`, поскольку это те значения, которые запрашиваются у `Iterator`, возвращаемого из `map`.
Это одна из причин, того почему важно использовать только чистые функции в качестве аргументов для `map`, `filter`, `fold` и подобных методов. Помните, что чистая функция не имеет побочных эффектов, поэтому `println` обычно не используется в `map`. Здесь `println` используется лишь для демонстрации "ленивости", которую с чистыми функциями не заметно.
diff --git a/_ru/overviews/collections-2.13/maps.md b/_ru/overviews/collections-2.13/maps.md
index 18cfc11245..a3d93834fd 100644
--- a/_ru/overviews/collections-2.13/maps.md
+++ b/_ru/overviews/collections-2.13/maps.md
@@ -1,18 +1,12 @@
---
layout: multipage-overview
title: Мапы
-
-discourse: true
-
partof: collections-213
overview-name: Collections
-
num: 7
previous-page: sets
next-page: concrete-immutable-collection-classes
-
language: ru
-
---
[Map](https://www.scala-lang.org/api/current/scala/collection/Map.html) это [Iterable](https://www.scala-lang.org/api/current/scala/collection/Iterable.html) состоящее из пар ключ значение (также называемых _связкой_ или _ассоциативным массивом_).
diff --git a/_ru/overviews/collections-2.13/overview.md b/_ru/overviews/collections-2.13/overview.md
index b0fe21b1cd..c9205aeded 100644
--- a/_ru/overviews/collections-2.13/overview.md
+++ b/_ru/overviews/collections-2.13/overview.md
@@ -1,18 +1,12 @@
---
layout: multipage-overview
title: Изменяемые и Неизменяемые Коллекции
-
-discourse: true
-
partof: collections-213
overview-name: Collections
-
num: 2
previous-page: introduction
next-page: trait-iterable
-
language: ru
-
---
В коллекциях Scala постоянно проводят различие между неизменяемыми и изменяемыми коллекциями. _Изменяемые_ (mutable) коллекции могут быть изменены или дополнены. Это означает, что вы можете изменять, добавлять или удалять её элементы. _Неизменяемые_ (Immutable) коллекции, напротив, никогда не меняются. У них есть операции, имитирующие добавления, удаления или обновления, но эти операции каждый раз будут возвращать новую коллекцию и оставлять старую коллекцию без изменений.
@@ -29,7 +23,7 @@ language: ru
является _базовой_ для обоих коллекций [collection.immutable.IndexedSeq\[T\]](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/IndexedSeq.html)
и
[collection.mutable.IndexedSeq\[T\]](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/IndexedSeq.html)
-Как правило, базовые коллекции пакета `scala.collection` поддерживают операции преобразования, затрагивающие всю коллекцию, неизменяемые коллекции пакета `scala.collection.immutable` обычно добавляют операции добавления или удаления отдельных элементов, а изменяемые коллекции пакета `scala.collection.mutable` обычно добавляют к базовому интерфейсу, операции модификации элементов основанные на побочных эфектах.
+Как правило, базовые коллекции пакета `scala.collection` поддерживают операции преобразования, затрагивающие всю коллекцию, неизменяемые коллекции пакета `scala.collection.immutable` обычно добавляют операции добавления или удаления отдельных элементов, а изменяемые коллекции пакета `scala.collection.mutable` обычно добавляют к базовому интерфейсу операции модификации элементов, основанные на побочных эффектах.
Еще одним отличием базовой коллекции от неизменяемой является то, что пользователи неизменяемой коллекции имеют гарантию, что никто не сможет изменить коллекцию, а пользователи базовой коллекции лишь обещают не менять ее самостоятельно. Даже если тип такой коллекции не предоставляет никаких операций для модификации коллекции, все равно возможно, что эта коллекция, может быть изменена какими-либо сторонними пользователями.
@@ -47,7 +41,7 @@ language: ru
scala.collection.immutable.List // Полное объявление
scala.List // объявление через псевдоним
- List // тк scala._ всегда автоматически импортируется
+ List // т.к. scala._ всегда автоматически импортируется
// можно просто указать имя коллекции
Другие псевдонимы для типов
diff --git a/_ru/overviews/collections-2.13/performance-characteristics.md b/_ru/overviews/collections-2.13/performance-characteristics.md
index 526a74a2b2..281280075b 100644
--- a/_ru/overviews/collections-2.13/performance-characteristics.md
+++ b/_ru/overviews/collections-2.13/performance-characteristics.md
@@ -1,21 +1,15 @@
---
layout: multipage-overview
title: Показатели производительности
-
-discourse: true
-
partof: collections-213
overview-name: Collections
-
num: 12
previous-page: strings
next-page: equality
-
language: ru
-
---
-Из предыдущих объяснений стало ясно, что разные типы коллекций имеют разные показатели производительности. Что зачастую является основной причиной, выбора одной коллекции вместо другой. Показатели для наиболее распространенных операций собраны в таблицах ниже.
+Из предыдущих объяснений стало ясно, что разные типы коллекций имеют разные показатели производительности. Что зачастую является основной причиной выбора одной коллекции вместо другой. Показатели для наиболее распространенных операций собраны в таблицах ниже.
Показатели производительности на последовательностях:
diff --git a/_ru/overviews/collections-2.13/seqs.md b/_ru/overviews/collections-2.13/seqs.md
index e85e6f1eb3..49ef6d32b6 100644
--- a/_ru/overviews/collections-2.13/seqs.md
+++ b/_ru/overviews/collections-2.13/seqs.md
@@ -1,18 +1,12 @@
---
layout: multipage-overview
title: Последовательности. Трейт Seq, IndexedSeq и LinearSeq
-
-discourse: true
-
partof: collections-213
overview-name: Collections
-
num: 5
previous-page: trait-iterable
next-page: sets
-
language: ru
-
---
Трейт [Seq](https://www.scala-lang.org/api/current/scala/collection/Seq.html) представляет из себя последовательность. Последовательность - это своего рода итерируемая сущность, у которой есть длина (`length`) и элементы с фиксированным индексом, начинающийся от `0`.
@@ -76,10 +70,10 @@ language: ru
| `xs intersect ys` |Операция пересечения на множестве между последовательностей `xs` и `ys`, сохраняющее порядок элементов в `xs`.|
| `xs diff ys` |Операция расхождения на множестве между последовательностей `xs` и `ys`, сохраняющее порядок элементов в `xs`.|
| `xs.distinct` |Подпоследовательность `xs`, которая не содержит дублирующих друг друга элементов.|
-| `xs distinctBy f` |Подпоследовательность `xs`, которая не содержит дублирующего элемента после применения функции преобразования `f`. Например, `List("foo", "bar", "quux").distinctBy(_.length) == List("foo", "bar")`|
+| `xs distinctBy f` |Подпоследовательность `xs`, которая не содержит дублирующего элемента после применения функции преобразования `f`. Например, `List("foo", "bar", "quux").distinctBy(_.length) == List("foo", "quux")`|
У трейта [Seq](https://www.scala-lang.org/api/current/scala/collection/Seq.html) есть два дочерних трейта [LinearSeq](https://www.scala-lang.org/api/current/scala/collection/LinearSeq.html), и [IndexedSeq](https://www.scala-lang.org/api/current/scala/collection/IndexedSeq.html).
-Они не добавляют никаких новых операций, но у каждого из них разные характеристики производительности: у LinearSeq эффективные операции `head` и `tail`, в то время как у IndexedSeq эффективные операции `apply`, `length` и (если мутабельная) `update`. Часто используемые варианты LinearSeq - это `scala.collection.immutable.List` и `scala.collection.immutable.LazyList`. А наиболее часто используемые IndexedSeq - это `scala.Array` и `scala.collection.mutable.ArrayBuffer`. Класс `Vector` представляет собой компромисс между IndexedSeq и LinearSeq. У него эффективные, как обращение по индексу, так и последовательный обход элементов. Поэтому вектора хорошая основа для смешанных моделей доступа, где используются как индексированный, так и последовательный доступ. Позже мы расскажем больше о [векторах](concrete-immutable-collection-classes.html).
+Они не добавляют никаких новых операций, но у каждого из них разные характеристики производительности: у LinearSeq эффективные операции `head` и `tail`, в то время как у IndexedSeq эффективные операции `apply`, `length` и (если мутабельная) `update`. Часто используемые варианты LinearSeq - это `scala.collection.immutable.List` и `scala.collection.immutable.LazyList`. А наиболее часто используемые IndexedSeq - это `scala.Array` и `scala.collection.mutable.ArrayBuffer`. Класс `Vector` представляет собой компромисс между IndexedSeq и LinearSeq. У него эффективные как обращение по индексу, так и последовательный обход элементов. Поэтому вектора хорошая основа для смешанных моделей доступа, где используются как индексированный, так и последовательный доступ. Позже мы расскажем больше о [векторах]({% link _ru/overviews/collections-2.13/concrete-immutable-collection-classes.md %}).
В мутабельном варианте `IndexedSeq` добавляет операции преобразования ее элементов в самой коллекции (в отличие от таких операций как `map` и `sort`, доступных на базовом трейте `Seq`, для которых результат - это новая коллекция).
diff --git a/_ru/overviews/collections-2.13/sets.md b/_ru/overviews/collections-2.13/sets.md
index f905b07bfe..d57e891797 100644
--- a/_ru/overviews/collections-2.13/sets.md
+++ b/_ru/overviews/collections-2.13/sets.md
@@ -1,18 +1,12 @@
---
layout: multipage-overview
title: Множества
-
-discourse: true
-
partof: collections-213
overview-name: Collections
-
num: 6
previous-page: seqs
next-page: maps
-
language: ru
-
---
Множества (`Set`) - это итерируемые сущности, которые не содержат дублирующих друг друга элементов. Операции с множествами описаны в таблицах ниже. Описания включают операции для базовых, неизменяемых и изменяемых множеств. Все их операции поделены на следующие категории:
@@ -111,14 +105,14 @@ language: ru
У изменяемых множеств также есть операции `add` и `remove` как эквиваленты для `+=` и `-=`. Разница лишь в том, что команды `add` и `remove` возвращают логический результат, показывающий, повлияла ли операция на само множество или нет.
-Текущая реализация изменяемого множества по умолчанию использует хэш-таблицу для хранения элементов множества. Реализация неизменяемого множества по умолчанию использует представление, которое адаптируется к количеству элементов множества. Пустое множество представлено объектом сингэлтоном. Множества размеров до четырех представлены одним объектом, в котором все элементы хранятся в виде полей. За пределами этого размера, неизменяемые множества реализованны в виде [Сжатого Отображенния Префиксного Дерева на Ассоциативном Массиве](concrete-immutable-collection-classes.html).
+Текущая реализация изменяемого множества по умолчанию использует хэш-таблицу для хранения элементов множества. Реализация неизменяемого множества по умолчанию использует представление, которое адаптируется к количеству элементов множества. Пустое множество представлено объектом сингэлтоном. Множества размеров до четырех представлены одним объектом, в котором все элементы хранятся в виде полей. За пределами этого размера, неизменяемые множества реализованны в виде [Сжатого Отображенния Префиксного Дерева на Ассоциативном Массиве]({% link _ru/overviews/collections-2.13/concrete-immutable-collection-classes.md %}).
Результатом такой схемы представления является то, что неизменяемые множества малых размеров (скажем, до 4), более компактны и более эффективны, чем изменяемые. Поэтому, если вы ожидаете, что размер множества будет небольшим, постарайтесь сделать его неизменяемым.
Два дочерних трейта множеств `SortedSet` и `BitSet`.
### Отсортированное Множество (SortedSet) ###
-[SortedSet](https://www.scala-lang.org/api/current/scala/collection/SortedSet.html) это множество, которое отдает свои элементы (используя `iterator` или `foreach`) в заданном порядке (который можно свободно задать в момент создания множества). Стандартное представление [SortedSet](https://www.scala-lang.org/api/current/scala/collection/SortedSet.html) - это упорядоченное двоичное дерево, которое поддерживает свойство того, что все элементы левого поддерева меньше, чем все элементы правого поддерева. Таким образом, простой упорядоченный обход может вернуть все элементы дерева в возрастающем порядке. Scala класс [immutable.TreeSet](https://www.scala-lang.org/api/current/scala/collection/immutable/TreeSet.html) базируется на _красно-черном_ дереве, в котором сохраняется тоже свойство но при этом само дерево является _сбалансированным_ --, то есть все пути от корня дерева до листа имеют длину, которая может отличаться друг от друга максимум на еденицу.
+[SortedSet](https://www.scala-lang.org/api/current/scala/collection/SortedSet.html) это множество, которое отдает свои элементы (используя `iterator` или `foreach`) в заданном порядке (который можно свободно задать в момент создания множества). Стандартное представление [SortedSet](https://www.scala-lang.org/api/current/scala/collection/SortedSet.html) - это упорядоченное двоичное дерево, которое поддерживает свойство того, что все элементы левого поддерева меньше, чем все элементы правого поддерева. Таким образом, простой упорядоченный обход может вернуть все элементы дерева в возрастающем порядке. Scala класс [immutable.TreeSet](https://www.scala-lang.org/api/current/scala/collection/immutable/TreeSet.html) базируется на _красно-черном_ дереве, в котором сохраняется тоже свойство но при этом само дерево является _сбалансированным_ --, то есть все пути от корня дерева до листа имеют длину, которая может отличаться друг от друга максимум на единицу.
При создании пустого [TreeSet](https://www.scala-lang.org/api/current/scala/collection/immutable/TreeSet.html), можно сначала указать требуемый порядок:
@@ -135,7 +129,7 @@ language: ru
scala> TreeSet.empty[String]
res2: scala.collection.immutable.TreeSet[String] = TreeSet()
-Если вы создаете новое множество из существующего упорядоченного множества (например, путем объединения или фильтрации), оно будет иметь туже схему упорядочения элементов, что и исходное множество. Например
+Если вы создаете новое множество из существующего упорядоченного множества (например, путем объединения или фильтрации), оно будет иметь ту же схему упорядочения элементов, что и исходное множество. Например
scala> res2 + "one" + "two" + "three" + "four"
res3: scala.collection.immutable.TreeSet[String] = TreeSet(four, one, three, two)
@@ -152,4 +146,4 @@ language: ru
Битовые Наборы - это множество неотрицательных целочисленных элементов, которые упаковываются в пакеты. Внутреннее представление [BitSet](https://www.scala-lang.org/api/current/scala/collection/BitSet.html) использует массив `Long`ов. Первый `Long` охватывает элементы от 0 до 63, второй от 64 до 127 и так далее (Неизменяемые наборы элементов в диапазоне от 0 до 127 оптимизированны таким образом что хранят биты непосредственно в одном или двух полях типа `Long` без использования массива). Для каждого `Long` 64 бита каждого из них устанавливается значение 1, если соответствующий элемент содержится в наборе, и сбрасывается в 0 в противном случае. Отсюда следует, что размер битового набора зависит от размера самого большого числа, которое в нем хранится. Если `N` является самым большим размером числа, то размер набора будет составлять `N/64` от размера `Long`, или `N/8` байта плюс небольшое количество дополнительных байт для информации о состоянии.
-Поэтому битовые наборы компактнее, чем другие множества, когда речь идет о хранении мелких элементов. Еще одним преимуществом битовых наборов является то, что такие операции, как проверка на наличие элемента `contains`, добавление либо удаление элементов с `+=` и `-=` черезвычайно эффективны.
\ No newline at end of file
+Поэтому битовые наборы компактнее, чем другие множества, когда речь идет о хранении мелких элементов. Еще одним преимуществом битовых наборов является то, что такие операции, как проверка на наличие элемента `contains`, добавление либо удаление элементов с `+=` и `-=` черезвычайно эффективны.
diff --git a/_ru/overviews/collections-2.13/strings.md b/_ru/overviews/collections-2.13/strings.md
index 1527860415..141b537e76 100644
--- a/_ru/overviews/collections-2.13/strings.md
+++ b/_ru/overviews/collections-2.13/strings.md
@@ -1,21 +1,15 @@
---
layout: multipage-overview
title: Строки
-
-discourse: true
-
partof: collections-213
overview-name: Collections
-
num: 11
previous-page: arrays
next-page: performance-characteristics
-
language: ru
-
---
-Как и массивы, строки не являются непосредственно последовательностями, но могут быть преобразованы в них, а также поддерживают все операции которые есть у последовательностей. Ниже приведены некоторые примеры операций, которые можно вызывать на строках.
+Как и массивы, строки не являются непосредственно последовательностями, но могут быть преобразованы в них, а также поддерживают все операции, которые есть у последовательностей. Ниже приведены некоторые примеры операций, которые можно вызывать на строках.
scala> val str = "hello"
str: java.lang.String = hello
diff --git a/_ru/overviews/collections-2.13/trait-iterable.md b/_ru/overviews/collections-2.13/trait-iterable.md
index 25cfd6ed37..3af59d11d6 100644
--- a/_ru/overviews/collections-2.13/trait-iterable.md
+++ b/_ru/overviews/collections-2.13/trait-iterable.md
@@ -1,18 +1,12 @@
---
layout: multipage-overview
title: Трейт Iterable
-
-discourse: true
-
partof: collections-213
overview-name: Collections
-
num: 4
previous-page: overview
next-page: seqs
-
language: ru
-
---
На самом верху иерархии коллекций находится трейт `Iterable`. Все методы в этого трейта описаны как абстрактные, `iterator` - это метод, который выдает элементы коллекции один за другим.
@@ -35,9 +29,9 @@ language: ru
* **Свертки** `foldLeft`, `foldRight`, `reduceLeft`, `reduceRight` которые применяют двуместную операцию к последовательным элементам.
* **Определённых сверток** `sum`, `product`, `min`, `max`, которые работают над коллекциями конкретных типов (числовыми или сопоставимыми).
* **Строковая** операции `mkString`, `addString`, `className`, которые дают альтернативные способы преобразования коллекции в строку.
-* **Отображения** - это такая коллекция, которая лениво вычисляется. Позже мы расмотрим отображения [подробнее](views.html).
+* **Отображения** - это такая коллекция, которая лениво вычисляется. Позже мы расмотрим отображения [подробнее]({% link _ru/overviews/collections-2.13/views.md %}).
-В `Iterable` есть два метода, которые возвращают итераторы: `grouped` и `sliding`. Правда эти итераторы возвращают не отдельные элементы, а целые подпоследовательности элементов исходной коллекции. Максимальный размер таких подпоследовательностей задается аргументом. Метод `grouped` возвращает свои элементы "нарезанные" на фиксированные части, тогда как `sliding` возвращает результат "прохода окна" (заданной длинны) над элементами. Разница между ними станет очевидной, если взглянуть на следующий результат в консоли:
+В `Iterable` есть два метода, которые возвращают итераторы: `grouped` и `sliding`. Правда, эти итераторы возвращают не отдельные элементы, а целые подпоследовательности элементов исходной коллекции. Максимальный размер таких подпоследовательностей задается аргументом. Метод `grouped` возвращает свои элементы "нарезанные" на фиксированные части, тогда как `sliding` возвращает результат "прохода окна" (заданной длинны) над элементами. Разница между ними станет очевидной, если взглянуть на следующий результат в консоли:
scala> val xs = List(1, 2, 3, 4, 5)
xs: List[Int] = List(1, 2, 3, 4, 5)
diff --git a/_ru/overviews/collections-2.13/views.md b/_ru/overviews/collections-2.13/views.md
index 8a095c96a1..135cbb0b50 100644
--- a/_ru/overviews/collections-2.13/views.md
+++ b/_ru/overviews/collections-2.13/views.md
@@ -1,18 +1,12 @@
---
layout: multipage-overview
title: Отображения
-
-discourse: true
-
partof: collections-213
overview-name: Collections
-
num: 14
previous-page: equality
next-page: iterators
-
language: ru
-
---
У коллекций довольно много вариантов создания новых коллекций. Ну например используя операции `map`, `filter` или `++`. Мы называем такие операции *трансформерами*, потому что они берут хотя бы одну коллекцию и трансформируют её в новую коллекцию.
@@ -21,11 +15,11 @@ language: ru
В качестве примера не строгого трансформера рассмотрим следующую реализацию операции создания ленивой мапы:
- def lazyMap[T, U](coll: Iterable[T], f: T => U) = new Iterable[U] {
- def iterator = coll.iterator map f
+ def lazyMap[T, U](iter: Iterable[T], f: T => U) = new Iterable[U] {
+ def iterator = iter.iterator map f
}
-Обратите внимание, что `lazyMap` создает новую `Iterable` , не обходя все элементы коллекции `coll`. Функция `f` применяется к элементам новой коллекции `iterator` по мере запроса ее элементов.
+Обратите внимание, что `lazyMap` создает новую `Iterable` , не обходя все элементы коллекции `iter`. Функция `f` применяется к элементам новой коллекции `iterator` по мере запроса ее элементов.
Коллекции Scala по умолчанию используют строгий способ во всех своих трансфмерах, за исключением `LazyList`, который реализует свои трансформеры не строгими (ленивыми). Однако существует практичный способ превратить любую коллекцию в ленивую и _наоборот_, основанный на отображении коллекции. _Отображение_ представляет собой особый вид коллекции, которое реализует все трансформеры лениво.
@@ -40,7 +34,7 @@ language: ru
res5: scala.collection.immutable.Vector[Int] =
Vector(4, 6, 8, 10, 12, 14, 16, 18, 20, 22)
-В последней строчке выражение `v map (_ + 1)` создает новый вектор, который при втором вызове в `map (_ * 2)` превращается в третий вектор. Как правило построение промежуточного результата от первого вызова мапы расточительно. В приведенном выше примере было бы быстрее составить единую мапу, состоящую из двух функций `(_ + 1)` и `(_ * 2)`. Если у вас обе функции доступны в одном и том же выражении, вы можете объеденить их вручную. Но довольно часто последовательные преобразования структуры данных выполняются в различных модулях программы. Слияние этих преобразований отрицательно скажется на модульности. Более универсальным способом избежать промежуточных результатов - это превратить вектор сначало в отображение, затем примененить все преобразования к отображению и, наконец, преобразовать отображение в вектор:
+В последней строчке выражение `v map (_ + 1)` создает новый вектор, который при втором вызове в `map (_ * 2)` превращается в третий вектор. Как правило, построение промежуточного результата от первого вызова мапы расточительно. В приведенном выше примере было бы быстрее составить единую мапу, состоящую из двух функций `(_ + 1)` и `(_ * 2)`. Если у вас обе функции доступны в одном и том же выражении, вы можете объединить их вручную. Но довольно часто последовательные преобразования структуры данных выполняются в различных модулях программы. Слияние этих преобразований отрицательно скажется на модульности. Более универсальным способом избежать промежуточных результатов - это превратить вектор сначало в отображение, затем применить все преобразования к отображению и, наконец, преобразовать отображение в вектор:
scala> (v.view map (_ + 1) map (_ * 2)).to(Vector)
res12: scala.collection.immutable.Vector[Int] =
@@ -51,7 +45,7 @@ language: ru
scala> val vv = v.view
vv: scala.collection.IndexedSeqView[Int] = IndexedSeqView()
-Применение `v.view` дает нам `IndexedSeqView[Int]`, тоесть лениво вычисляемым `IndexedSeq[Int]`. Также как и `LazyList`,
+Применение `v.view` дает нам `IndexedSeqView[Int]`, тоесть лениво вычисляемым `IndexedSeq[Int]`. Так же как и `LazyList`,
метод `toString` на отображении не принуждает выводить элементы, вот почему содержимое `vv` выводится как `View(?)`.
Применение первого `map` к отображению дает:
diff --git a/_ru/overviews/collections/introduction.md b/_ru/overviews/collections/introduction.md
index 4f503f94d6..5b996a9254 100644
--- a/_ru/overviews/collections/introduction.md
+++ b/_ru/overviews/collections/introduction.md
@@ -1,14 +1,9 @@
---
layout: multipage-overview
title: Введение
-
-discourse: false
-
partof: collections
overview-name: Collections
-
num: 1
-
language: ru
---
diff --git a/_ru/overviews/parallel-collections/architecture.md b/_ru/overviews/parallel-collections/architecture.md
index 5ee10d99b9..1e8fbbf37c 100644
--- a/_ru/overviews/parallel-collections/architecture.md
+++ b/_ru/overviews/parallel-collections/architecture.md
@@ -1,9 +1,6 @@
---
layout: multipage-overview
title: Архитектура библиотеки параллельных коллекций
-
-discourse: false
-
partof: parallel-collections
overview-name: Parallel Collections
@@ -51,7 +48,7 @@ _Примечание:_ Если есть два `Combiner`а, `c1` и `c2` гд
Параллельные коллекции Scala во многом созданы под влиянием дизайна библиотеки (последовательных) коллекций Scala. На рисунке ниже показано, что их дизайн фактически отражает соответствующие трейты фреймворка обычных коллекций.
-[]({{ site.baseurl }}/resources/images/parallel-collections-hierarchy.png)
+[]({{ site.baseurl }}/resources/images/parallel-collections-hierarchy.png)
Иерархия библиотеки Scala: коллекции и параллельные коллекции
diff --git a/_ru/overviews/parallel-collections/concrete-parallel-collections.md b/_ru/overviews/parallel-collections/concrete-parallel-collections.md
index ab41a576c7..1bda571a82 100644
--- a/_ru/overviews/parallel-collections/concrete-parallel-collections.md
+++ b/_ru/overviews/parallel-collections/concrete-parallel-collections.md
@@ -1,12 +1,8 @@
---
layout: multipage-overview
title: Конкретные классы параллельных коллекций
-
-discourse: false
-
partof: parallel-collections
overview-name: Parallel Collections
-
language: ru
num: 2
---
@@ -47,10 +43,10 @@ num: 2
[ParRange](https://www.scala-lang.org/api/{{ site.scala-212-version }}/scala/collection/parallel/immutable/ParRange.html) представляет собой упорядоченную последовательность элементов, отстоящих друг от друга на одинаковые промежутки. Параллельный диапазон создается подобно последовательному [Range](https://www.scala-lang.org/api/{{ site.scala-212-version }}/scala/collection/immutable/Range.html):
- scala> 1 to 3 par
+ scala> (1 to 3).par
res0: scala.collection.parallel.immutable.ParRange = ParRange(1, 2, 3)
- scala> 15 to 5 by -2 par
+ scala> (15 to 5 by -2).par
res1: scala.collection.parallel.immutable.ParRange = ParRange(15, 13, 11, 9, 7, 5)
Подобно тому, как последовательные диапазоны не имеют строителей, параллельные диапазоны не имеют [компоновщиков]({{ site.baseurl }}/ru/overviews/parallel-collections/architecture.html). При создании отображения (mapping) элементов параллельного диапазона получается параллельный вектор. Последовательные и параллельные диапазоны могут эффективно преобразовываться друг в друга вызовами методов `seq` и `par`.
@@ -76,7 +72,7 @@ num: 2
scala> val phs = scala.collection.parallel.immutable.ParHashSet(1 until 1000: _*)
phs: scala.collection.parallel.immutable.ParHashSet[Int] = ParSet(645, 892, 69, 809, 629, 365, 138, 760, 101, 479,...
- scala> phs map { x => x * x } sum
+ scala> phs.map(x => x * x).sum
res0: Int = 332833500
[Компоновщики]({{ site.baseurl }}/overviews/parallel-collections/architecture.html) параллельных хэш-деревьев действуют аналогично компоновщикам хэш-таблиц, а именно предварительно распределяют элементы по блокам, а после этого параллельно составляют результирующее хэш-дерево, назначая обработку различных блоков разным процессорам, каждый из которых независимо собирает свое поддерево.
@@ -92,19 +88,19 @@ num: 2
scala> while (numbers.nonEmpty) {
| numbers foreach { case (num, sqrt) =>
- | val nsqrt = 0.5 * (sqrt + num / sqrt)
- | numbers(num) = nsqrt
- | if (math.abs(nsqrt - sqrt) < 0.01) {
- | println(num, nsqrt)
- | numbers.remove(num)
- | }
- | }
- | }
- (1.0,1.0)
+ | val nsqrt = 0.5 * (sqrt + num / sqrt)
+ | numbers(num) = nsqrt
+ | if (math.abs(nsqrt - sqrt) < 0.01) {
+ | println(num, nsqrt)
+ | numbers.remove(num)
+ | }
+ | }
+ | }
+ (1.0,1.0)
(2.0,1.4142156862745097)
(7.0,2.64576704419029)
(4.0,2.0000000929222947)
- ...
+ ...
[Компоновщики]({{ site.baseurl }}/ru/overviews/parallel-collections/architecture.html) реализованы как `TrieMap`-- так как эта структура является многопоточной, при вызове метода трансформации создается только один компоновщик, разделяемый всеми процессорами.
@@ -114,53 +110,52 @@ num: 2
Характеристики производительности последовательных типов (sequence types):
-| | head | tail | apply | update| prepend | append | insert |
-| -------- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
-| `ParArray` | C | L | C | C | L | L | L |
-| `ParVector` | eC | eC | eC | eC | eC | eC | - |
-| `ParRange` | C | C | C | - | - | - | - |
+| | head | tail | apply | update | prepend | append | insert |
+| ----------- | ---- | ---- | ----- | ------ | ------- | ------ | ------ |
+| `ParArray` | C | L | C | C | L | L | L |
+| `ParVector` | eC | eC | eC | eC | eC | eC | - |
+| `ParRange` | C | C | C | - | - | - | - |
Характеристики производительности множеств (set) и ассоциативных массивов (map):
-| | lookup | add | remove |
-| -------- | ---- | ---- | ---- |
-| **неизменяемые** | | | |
-| `ParHashSet`/`ParHashMap`| eC | eC | eC |
-| **изменяемые** | | | |
-| `ParHashSet`/`ParHashMap`| C | C | C |
-| `ParTrieMap` | eC | eC | eC |
-
+| | lookup | add | remove |
+| ------------------------- | ------ | --- | ------ |
+| **неизменяемые** | | | |
+| `ParHashSet`/`ParHashMap` | eC | eC | eC |
+| **изменяемые** | | | |
+| `ParHashSet`/`ParHashMap` | C | C | C |
+| `ParTrieMap` | eC | eC | eC |
### Расшифровка
Обозначения в двух представленных выше таблицах означают следующее:
-| | |
-| --- | ---- |
-| **C** | Операция (быстрая) выполняется за постоянное время. |
-| **eC** | Операция выполняется за фактически постоянное время, но только при соблюдении некоторых предположений, например о максимальной длине вектора или распределении хэш-кодов.|
+| | |
+| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| **C** | Операция (быстрая) выполняется за постоянное время. |
+| **eC** | Операция выполняется за фактически постоянное время, но только при соблюдении некоторых предположений, например о максимальной длине вектора или распределении хэш-кодов. |
| **aC** | Операция выполняется за амортизированное постоянное время. Некоторые вызовы операции могут выполняться медленнее, но при подсчете времени выполнения большого количества операций выходит, что в среднем на операцию требуется постоянное время. |
-| **Log** | Операция занимает время, пропорциональное логарифму размера коллекции. |
-| **L** | Операция линейна, то есть занимает время, пропорциональное размеру коллекции. |
-| **-** | Операция не поддерживается. |
+| **Log** | Операция занимает время, пропорциональное логарифму размера коллекции. |
+| **L** | Операция линейна, то есть занимает время, пропорциональное размеру коллекции. |
+| **-** | Операция не поддерживается. |
Первая таблица трактует последовательные типы-- изменяемые и неизменяемые-- в контексте выполнения следующих операций:
-| | |
-| --- | ---- |
-| **head** | Получение первого элемента последовательности. |
-| **tail** | Получение новой последовательности, состоящей из всех элементов исходной, кроме первого. |
-| **apply** | Индексирование. |
-| **update** | Функциональное обновление (с помощью `updated`) для неизменяемых последовательностей, обновление с побочными действиями (с помощью `update`) для изменяемых. |
-| **prepend**| Добавление элемента в начало последовательности. Для неизменяемых последовательностей создается новая последовательность, для изменяемых-- модифицируется существующая. |
-| **append** | Добавление элемента в конец последовательности. Для неизменяемых последовательностей создается новая последовательность, для изменяемых-- модифицируется существующая. |
-| **insert** | Вставка элемента в выбранную позицию последовательности. Поддерживается только изменяемыми последовательностями. |
+| | |
+| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **head** | Получение первого элемента последовательности. |
+| **tail** | Получение новой последовательности, состоящей из всех элементов исходной, кроме первого. |
+| **apply** | Индексирование. |
+| **update** | Функциональное обновление (с помощью `updated`) для неизменяемых последовательностей, обновление с побочными действиями (с помощью `update`) для изменяемых. |
+| **prepend** | Добавление элемента в начало последовательности. Для неизменяемых последовательностей создается новая последовательность, для изменяемых-- модифицируется существующая. |
+| **append** | Добавление элемента в конец последовательности. Для неизменяемых последовательностей создается новая последовательность, для изменяемых-- модифицируется существующая. |
+| **insert** | Вставка элемента в выбранную позицию последовательности. Поддерживается только изменяемыми последовательностями. |
Вторая таблица рассматривает изменяемые и неизменяемые множества и ассоциативные массивы в контексте следующих операций:
-| | |
-| --- | ---- |
+| | |
+| ---------- | ---------------------------------------------------------------------------------------------- |
| **lookup** | Проверка принадлежности элемента множеству, или получение значения, ассоциированного с ключом. |
-| **add** | Добавление нового элемента во множество или новой пары ключ/значение в ассоциативный массив. |
-| **remove** | Удаление элемента из множества или ключа из ассоциативного массива. |
-| **min** | Минимальный элемент множества или минимальный ключ ассоциативного массива. |
+| **add** | Добавление нового элемента во множество или новой пары ключ/значение в ассоциативный массив. |
+| **remove** | Удаление элемента из множества или ключа из ассоциативного массива. |
+| **min** | Минимальный элемент множества или минимальный ключ ассоциативного массива. |
diff --git a/_ru/overviews/parallel-collections/configuration.md b/_ru/overviews/parallel-collections/configuration.md
index 5dbd2b1e38..253c4c30d5 100644
--- a/_ru/overviews/parallel-collections/configuration.md
+++ b/_ru/overviews/parallel-collections/configuration.md
@@ -1,12 +1,8 @@
---
layout: multipage-overview
title: Конфигурирование параллельных коллекций
-
-discourse: false
-
partof: parallel-collections
overview-name: Parallel Collections
-
language: ru
num: 7
---
diff --git a/_ru/overviews/parallel-collections/conversions.md b/_ru/overviews/parallel-collections/conversions.md
index 114f2d8986..f001762841 100644
--- a/_ru/overviews/parallel-collections/conversions.md
+++ b/_ru/overviews/parallel-collections/conversions.md
@@ -1,12 +1,8 @@
---
layout: multipage-overview
title: Преобразования параллельных коллекций
-
-discourse: false
-
partof: parallel-collections
overview-name: Parallel Collections
-
language: ru
num: 3
---
diff --git a/_ru/overviews/parallel-collections/ctries.md b/_ru/overviews/parallel-collections/ctries.md
index 9e52d407bf..640ac7e8b9 100644
--- a/_ru/overviews/parallel-collections/ctries.md
+++ b/_ru/overviews/parallel-collections/ctries.md
@@ -1,12 +1,8 @@
---
layout: multipage-overview
title: Многопоточные префиксные деревья
-
-discourse: false
-
partof: parallel-collections
overview-name: Parallel Collections
-
language: ru
num: 4
---
diff --git a/_ru/overviews/parallel-collections/custom-parallel-collections.md b/_ru/overviews/parallel-collections/custom-parallel-collections.md
index 6fd6fa9f58..4dbcdf7e96 100644
--- a/_ru/overviews/parallel-collections/custom-parallel-collections.md
+++ b/_ru/overviews/parallel-collections/custom-parallel-collections.md
@@ -1,12 +1,8 @@
---
layout: multipage-overview
title: Создание пользовательской параллельной коллекции
-
-discourse: false
-
partof: parallel-collections
overview-name: Parallel Collections
-
language: ru
num: 6
---
diff --git a/_ru/overviews/parallel-collections/overview.md b/_ru/overviews/parallel-collections/overview.md
index 2d68d91d8d..e2b4bbcd7d 100644
--- a/_ru/overviews/parallel-collections/overview.md
+++ b/_ru/overviews/parallel-collections/overview.md
@@ -1,12 +1,8 @@
---
layout: multipage-overview
title: Обзор
-
-discourse: false
-
partof: parallel-collections
overview-name: Parallel Collections
-
num: 1
language: ru
---
diff --git a/_ru/overviews/parallel-collections/performance.md b/_ru/overviews/parallel-collections/performance.md
index b86e90bc2c..64e533e359 100644
--- a/_ru/overviews/parallel-collections/performance.md
+++ b/_ru/overviews/parallel-collections/performance.md
@@ -1,12 +1,8 @@
---
layout: multipage-overview
title: Измерение производительности
-
-discourse: false
-
partof: parallel-collections
overview-name: Parallel Collections
-
num: 8
language: ru
---
diff --git a/_ru/scala3/book/ca-context-bounds.md b/_ru/scala3/book/ca-context-bounds.md
new file mode 100644
index 0000000000..91c18c5101
--- /dev/null
+++ b/_ru/scala3/book/ca-context-bounds.md
@@ -0,0 +1,141 @@
+---
+layout: multipage-overview
+title: Контекстные границы
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этой главе представлены контекстные границы в Scala 3.
+language: ru
+num: 62
+previous-page: ca-context-parameters
+next-page: ca-given-imports
+---
+
+Во многих ситуациях имя [контекстного параметра]({% link _overviews/scala3-book/ca-context-parameters.md %}#context-parameters)
+не нужно указывать явно, поскольку оно используется компилятором только в синтезированных аргументах для других параметров контекста.
+В этом случае вам не нужно определять имя параметра, а можно просто указать тип.
+
+## Предыстория
+
+Например, рассмотрим метод `maxElement`, возвращающий максимальное значение в коллекции:
+
+{% tabs context-bounds-max-named-param class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+
+```scala
+def maxElement[A](as: List[A])(implicit ord: Ord[A]): A =
+ as.reduceLeft(max(_, _)(ord))
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+def maxElement[A](as: List[A])(using ord: Ord[A]): A =
+ as.reduceLeft(max(_, _)(using ord))
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+Метод `maxElement` принимает _контекстный параметр_ типа `Ord[A]` только для того,
+чтобы передать его в качестве аргумента методу `max`.
+
+Для полноты приведем определения `max` и `Ord`
+(обратите внимание, что на практике мы будем использовать существующий метод `max` для `List`,
+но мы создали этот пример для иллюстрации):
+
+{% tabs context-bounds-max-ord class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+
+```scala
+/** Определяет, как сравнивать значения типа `A` */
+trait Ord[A] {
+ def greaterThan(a1: A, a2: A): Boolean
+}
+
+/** Возвращает максимальное из двух значений */
+def max[A](a1: A, a2: A)(implicit ord: Ord[A]): A =
+ if (ord.greaterThan(a1, a2)) a1 else a2
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+/** Определяет, как сравнивать значения типа `A` */
+trait Ord[A]:
+ def greaterThan(a1: A, a2: A): Boolean
+
+/** Возвращает максимальное из двух значений */
+def max[A](a1: A, a2: A)(using ord: Ord[A]): A =
+ if ord.greaterThan(a1, a2) then a1 else a2
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+Обратите внимание, что метод `max` принимает контекстный параметр типа `Ord[A]`, как и метод `maxElement`.
+
+## Пропуск контекстных аргументов
+
+Так как `ord` - это контекстный параметр в методе `max`,
+компилятор может предоставить его для нас в реализации `maxElement` при вызове `max`:
+
+{% tabs context-bounds-context class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+
+```scala
+def maxElement[A](as: List[A])(implicit ord: Ord[A]): A =
+ as.reduceLeft(max(_, _))
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+def maxElement[A](as: List[A])(using Ord[A]): A =
+ as.reduceLeft(max(_, _))
+```
+
+Обратите внимание: поскольку нам не нужно явно передавать его методу `max`,
+мы можем не указывать его имя в определении метода `maxElement`.
+Это _анонимный параметр контекста_.
+
+{% endtab %}
+
+{% endtabs %}
+
+## Границы контекста
+
+Учитывая написанное выше, _привязка к контексту_ — это сокращенный синтаксис
+для выражения шаблона "параметр контекста, применяемый к параметру типа".
+
+Используя привязку к контексту, метод `maxElement` можно записать следующим образом:
+
+{% tabs context-bounds-max-rewritten %}
+
+{% tab 'Scala 2 и 3' %}
+
+```scala
+def maxElement[A: Ord](as: List[A]): A =
+ as.reduceLeft(max(_, _))
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+Привязка типа `: Ord` к параметру типа `A` метода или класса указывает на параметр контекста с типом `Ord[A]`.
+Под капотом компилятор преобразует этот синтаксис в тот, который показан в разделе "Предыстория".
+
+Дополнительные сведения о границах контекста см. в разделе ["Что такое границы контекста?"]({% link _overviews/FAQ/index.md %}#what-are-context-bounds) раздел FAQ по Scala.
diff --git a/_ru/scala3/book/ca-context-parameters.md b/_ru/scala3/book/ca-context-parameters.md
new file mode 100644
index 0000000000..dc66f2fc98
--- /dev/null
+++ b/_ru/scala3/book/ca-context-parameters.md
@@ -0,0 +1,196 @@
+---
+layout: multipage-overview
+title: Параметры контекста
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице показано, как объявлять параметры контекста и как компилятор выводит их на стороне вызова.
+language: ru
+num: 61
+previous-page: ca-extension-methods
+next-page: ca-context-bounds
+---
+
+Scala предлагает две важные функции для контекстной абстракции:
+
+- **Параметры контекста** позволяют указать параметры, которые на стороне вызова могут быть опущены программистом
+ и должны автоматически предоставляться контекстом.
+- **Экземпляры given** (в Scala 3) или **неявные определения** (в Scala 2) — это термины,
+ которые компилятор Scala может использовать для заполнения отсутствующих аргументов.
+
+## Параметры контекста
+
+При проектировании системы зачастую необходимо предоставлять контекстную информацию,
+такую как конфигурация или настройки, различным компонентам вашей системы.
+Одним из распространенных способов добиться этого является передача конфигурации
+в качестве дополнительного аргумента методам.
+
+В следующем примере мы определяем кейс класс `Config` для моделирования некоторой конфигурации веб-сайта
+и передаем ее в различных методах.
+
+{% tabs example %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+case class Config(port: Int, baseUrl: String)
+
+def renderWebsite(path: String, config: Config): String =
+ "" + renderWidget(List("cart"), config) + ""
+
+def renderWidget(items: List[String], config: Config): String = ???
+
+val config = Config(8080, "docs.scala-lang.org")
+renderWebsite("/home", config)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Предположим, что конфигурация не меняется на протяжении большей части нашей кодовой базы.
+Передача `config` каждому вызову метода (например `renderWidget`) становится очень утомительной
+и делает нашу программу более трудной для чтения, поскольку нам нужно игнорировать аргумент `config`.
+
+### Установка параметров как контекстных
+
+Мы можем пометить некоторые параметры наших методов как _контекстные_.
+
+{% tabs 'contextual-parameters' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+def renderWebsite(path: String)(implicit config: Config): String =
+ "" + renderWidget(List("cart")) + ""
+ // ^
+ // аргумент config больше не требуется
+
+def renderWidget(items: List[String])(implicit config: Config): String = ???
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+def renderWebsite(path: String)(using config: Config): String =
+ "" + renderWidget(List("cart")) + ""
+ // ^
+ // аргумент config больше не требуется
+
+def renderWidget(items: List[String])(using config: Config): String = ???
+```
+
+{% endtab %}
+{% endtabs %}
+
+Начав секцию параметров с ключевого слова `using` в Scala 3 или `implicit` в Scala 2, мы сообщаем компилятору,
+что на стороне вызова он должен автоматически найти аргумент с необходимым типом.
+Таким образом, компилятор Scala выполняет **вывод термов**.
+
+При вызове `renderWidget(List("cart"))` компилятор Scala увидит, что в области видимости есть терм типа `Config`
+(в нашем случае - `config`) и автоматически предоставит его для `renderWidget`.
+Таким образом, программа эквивалентна приведенной выше.
+
+На самом деле, поскольку в реализации `renderWebsite` больше не нужно ссылаться на `config`,
+мы можем даже опустить его имя в подписи в Scala 3:
+
+{% tabs 'anonymous' %}
+{% tab 'Только в Scala 3' %}
+
+```scala
+// нет необходимости придумывать имя параметра
+// vvvvvvvvvvvvv
+def renderWebsite(path: String)(using Config): String =
+ "" + renderWidget(List("cart")) + ""
+```
+
+{% endtab %}
+{% endtabs %}
+
+В Scala 2 именовать неявные параметры по-прежнему необходимо.
+
+### Явное указание контекстных параметров
+
+Мы увидели, как _абстрагироваться_ от контекстных параметров
+и что компилятор Scala может автоматически предоставлять нам аргументы.
+Но как мы можем указать, какую конфигурацию использовать для нашего вызова `renderWebsite`?
+
+{% tabs 'explicit' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+Мы явно указываем значение аргумента, как если бы это был обычный аргумент:
+
+```scala
+renderWebsite("/home")(config)
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+Подобно тому, как мы указали наш раздел параметров с помощью `using`,
+мы также можем явно указать контекстные параметры с помощью `using`:
+
+```scala
+renderWebsite("/home")(using config)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Явное предоставление контекстных параметров может быть полезно,
+когда у нас в области видимости есть несколько разных значений,
+подходящих по типу, и мы хотим убедиться в корректности передачи параметра методу.
+
+Для всех остальных случаев, как мы увидим в следующем разделе,
+есть еще один способ ввести контекстуальные значения в область видимости.
+
+## Экземпляры given (определения implicit в Scala 2)
+
+Мы видели, что можем явно передавать аргументы в качестве контекстных параметров.
+Однако, если для определенного типа существует _единственное каноническое значение_,
+есть другой предпочтительный способ сделать его доступным для компилятора Scala:
+пометив его как `given` в Scala 3 или `implicit` в Scala 2.
+
+{% tabs 'instances' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+implicit val config: Config = Config(8080, "docs.scala-lang.org")
+// ^^^^^^
+// это значение, которое выведет компилятор Scala
+// в качестве аргумента контекстного параметра типа Config
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+val config = Config(8080, "docs.scala-lang.org")
+
+// это тип, который мы хотим предоставить для канонического значения
+// vvvvvv
+given Config = config
+// ^^^^^^
+// это значение, которое выведет компилятор Scala
+// в качестве аргумента контекстного параметра типа Config
+```
+
+{% endtab %}
+{% endtabs %}
+
+В приведенном выше примере мы указываем, что всякий раз,
+когда в текущей области видимости опущен контекстный параметр типа `Config`,
+компилятор должен вывести `config` в качестве аргумента.
+
+Определив каноническое значение для типа `Config`,
+мы можем вызвать `renderWebsite` следующим образом:
+
+```scala
+renderWebsite("/home")
+// ^
+// снова без аргумента
+```
+
+Подробное руководство о том, где Scala ищет канонические значения, можно найти в [FAQ]({% link _overviews/FAQ/index.md %}#where-does-scala-look-for-implicits).
+
+[reference]: {{ site.scala3ref }}/overview.html
+[blog-post]: /2020/11/06/explicit-term-inference-in-scala-3.html
diff --git a/_ru/scala3/book/ca-contextual-abstractions-intro.md b/_ru/scala3/book/ca-contextual-abstractions-intro.md
new file mode 100644
index 0000000000..eef3910c30
--- /dev/null
+++ b/_ru/scala3/book/ca-contextual-abstractions-intro.md
@@ -0,0 +1,96 @@
+---
+layout: multipage-overview
+title: Контекстные абстракции
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: В этой главе представлено введение в концепцию контекстных абстракций Scala 3.
+language: ru
+num: 59
+previous-page: types-others
+next-page: ca-extension-methods
+---
+
+## Предпосылка
+
+Контекстные абстракции — это способ абстрагироваться от контекста.
+Они представляют собой единую парадигму с большим разнообразием вариантов использования, среди которых:
+
+- реализация тайп классов (_type classes_)
+- установление контекста
+- внедрение зависимости (_dependency injection_)
+- выражение возможностей
+- вычисление новых типов и доказательство взаимосвязей между ними
+
+В этом отношении Scala оказала влияние на другие языки. Например, трейты в Rust или protocol extensions Swift.
+Предложения по дизайну также представлены для Kotlin в качестве разрешения зависимостей во время компиляции,
+для C# в качестве Shapes и Extensions или для F# в качестве Traits.
+Контекстные абстракции также являются общей особенностью средств доказательства теорем, таких как Coq или Agda.
+
+Несмотря на то, что в этих проектах используется разная терминология,
+все они являются вариантами основной идеи вывода терминов (term inference):
+учитывая тип, компилятор синтезирует "канонический" термин, который имеет этот тип.
+
+## Редизайн в Scala 3
+
+В Scala 2 контекстные абстракции поддерживаются пометкой `implicit` определений (методов и значений) или параметров
+(см. [Параметры контекста]({% link _overviews/scala3-book/ca-context-parameters.md %})).
+
+Scala 3 включает в себя переработку контекстных абстракций.
+Хотя эти концепции постепенно "открывались" в Scala 2, теперь они хорошо известны и понятны, и редизайн использует эти знания.
+
+Дизайн Scala 3 фокусируется на **намерении**, а не на **механизме**.
+Вместо того, чтобы предлагать одну очень мощную функцию имплицитов,
+Scala 3 предлагает несколько функций, ориентированных на варианты использования:
+
+- **Расширение классов задним числом**.
+ В Scala 2 методы расширения должны были кодироваться с использованием [неявных преобразований][implicit-conversions] или [неявных классов]({% link _overviews/core/implicit-classes.md %}).
+ Напротив, в Scala 3 [методы расширения][extension-methods] теперь встроены непосредственно в язык, что приводит к улучшению сообщений об ошибках и улучшению вывода типов.
+
+- **Абстрагирование контекстной информации**.
+ [Предложения Using][givens] позволяют программистам абстрагироваться от информации,
+ которая доступна в контексте вызова и должна передаваться неявно.
+ В качестве улучшения по сравнению со Scala 2 подразумевается, что предложения using могут быть указаны по типу,
+ освобождая сигнатуры функций от имен переменных, на которые никогда не ссылаются явно.
+
+- **Предоставление экземпляров тайп-классов**.
+ [Given экземпляры][givens] позволяют программистам определять _каноническое значение_ определенного типа.
+ Это делает программирование с [тайп-классами][type-classes] более простым без утечек деталей реализации.
+
+- **Неявное преобразование одного типа в другой**.
+ Неявное преобразование было [переработано с нуля][implicit-conversions] как экземпляры тайп-класса `Conversion`.
+
+- **Контекстные абстракции высшего порядка**.
+ _Совершенно новая_ функция [контекстных функций][contextual-functions] делает контекстные абстракции объектами первого класса.
+ Они являются важным инструментом для авторов библиотек и позволяют выражать лаконичный DSL.
+
+- **Полезная обратная связь от компилятора**.
+ Если компилятор не может разрешить неявный параметр, теперь он предлагает [предложения по импорту](https://www.scala-lang.org/blog/2020/05/05/scala-3-import-suggestions.html), которые могут решить проблему.
+
+## Преимущества
+
+Эти изменения в Scala 3 обеспечивают лучшее разделение вывода терминов от остального языка:
+
+- существует единственный способ определить данные
+- существует единственный способ ввести неявные параметры и аргументы
+- существует отдельный способ [импорта givens][given-imports], который не позволяет им прятаться в море обычного импорта
+- существует единственный способ определить [неявное преобразование][implicit-conversions], которое четко обозначено как таковое и не требует специального синтаксиса
+
+К преимуществам этих изменений относятся:
+
+- новый дизайн позволяет избежать взаимодействия функций и делает язык более согласованным
+- implicits становятся более легкими для изучения и более сложными для злоупотреблений
+- значительно улучшается ясность 95% программ Scala, использующих implicits
+- есть потенциал, чтобы сделать вывод термов однозначным способом, который также доступен и удобен.
+
+В этой главе в следующих разделах представлены многие из этих новых функций.
+
+[givens]: {% link _overviews/scala3-book/ca-context-parameters.md %}
+[given-imports]: {% link _overviews/scala3-book/ca-given-imports.md %}
+[implicit-conversions]: {% link _overviews/scala3-book/ca-implicit-conversions.md %}
+[extension-methods]: {% link _overviews/scala3-book/ca-extension-methods.md %}
+[context-bounds]: {% link _overviews/scala3-book/ca-context-bounds.md %}
+[type-classes]: {% link _overviews/scala3-book/ca-type-classes.md %}
+[equality]: {% link _overviews/scala3-book/ca-multiversal-equality.md %}
+[contextual-functions]: {{ site.scala3ref }}/contextual/context-functions.html
diff --git a/_ru/scala3/book/ca-extension-methods.md b/_ru/scala3/book/ca-extension-methods.md
new file mode 100644
index 0000000000..6f530b141f
--- /dev/null
+++ b/_ru/scala3/book/ca-extension-methods.md
@@ -0,0 +1,145 @@
+---
+layout: multipage-overview
+title: Методы расширения
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этой главе представлена работа методов расширения в Scala 3.
+language: ru
+num: 60
+previous-page: ca-contextual-abstractions-intro
+next-page: ca-context-parameters
+versionSpecific: true
+---
+
+В Scala 2 аналогичного результата можно добиться с помощью [неявных классов]({% link _overviews/core/implicit-classes.md %}).
+
+---
+
+Методы расширения позволяют добавлять методы к типу после того, как он был определен,
+т.е. они позволяют добавлять новые методы в закрытые классы.
+Например, представьте, что кто-то создал класс `Circle`:
+
+{% tabs ext1 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+case class Circle(x: Double, y: Double, radius: Double)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Теперь представим, что необходим метод `circumference`, но нет возможности изменить исходный код `Circle`.
+До того как концепция вывода терминов была введена в языки программирования,
+единственное, что можно было сделать, это написать метод в отдельном классе или объекте, подобном этому:
+
+{% tabs ext2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+object CircleHelpers {
+ def circumference(c: Circle): Double = c.radius * math.Pi * 2
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+object CircleHelpers:
+ def circumference(c: Circle): Double = c.radius * math.Pi * 2
+```
+
+{% endtab %}
+{% endtabs %}
+
+Затем этот метод можно было использовать следующим образом:
+
+{% tabs ext3 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val aCircle = Circle(2, 3, 5)
+
+// без использования метода расширения
+CircleHelpers.circumference(aCircle)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Но методы расширения позволяют создать метод `circumference` для работы с экземплярами `Circle`:
+
+{% tabs ext4 %}
+{% tab 'Только в Scala 3' %}
+
+```scala
+extension (c: Circle)
+ def circumference: Double = c.radius * math.Pi * 2
+```
+
+{% endtab %}
+{% endtabs %}
+
+В этом коде:
+
+- `Circle` — это тип, к которому будет добавлен метод расширения `circumference`
+- Синтаксис `c: Circle` позволяет ссылаться на переменную `c` в методах расширения
+
+Затем в коде метод `circumference` можно использовать так же, как если бы он был изначально определен в классе `Circle`:
+
+{% tabs ext5 %}
+{% tab 'Только в Scala 3' %}
+
+```scala
+aCircle.circumference
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Импорт методов расширения
+
+Представим, что `circumference` определен в пакете `lib` - его можно импортировать с помощью
+
+{% tabs ext6 %}
+{% tab 'Только в Scala 3' %}
+
+```scala
+import lib.circumference
+
+aCircle.circumference
+```
+
+{% endtab %}
+{% endtabs %}
+
+Если импорт отсутствует, то компилятор выводит подробное сообщение об ошибке, подсказывая возможный импорт, например так:
+
+```text
+value circumference is not a member of Circle, but could be made available as an extension method.
+
+The following import might fix the problem:
+
+ import lib.circumference
+```
+
+## Обсуждение
+
+Ключевое слово `extension` объявляет о намерении определить один или несколько методов расширения для типа, заключенного в круглые скобки.
+Чтобы определить для типа несколько методов расширения, используется следующий синтаксис:
+
+{% tabs ext7 %}
+{% tab 'Только в Scala 3' %}
+
+```scala
+extension (c: Circle)
+ def circumference: Double = c.radius * math.Pi * 2
+ def diameter: Double = c.radius * 2
+ def area: Double = math.Pi * c.radius * c.radius
+```
+
+{% endtab %}
+{% endtabs %}
diff --git a/_ru/scala3/book/ca-given-imports.md b/_ru/scala3/book/ca-given-imports.md
new file mode 100644
index 0000000000..41439a27be
--- /dev/null
+++ b/_ru/scala3/book/ca-given-imports.md
@@ -0,0 +1,54 @@
+---
+layout: multipage-overview
+title: Given импорты
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице показано, как работают операторы импорта 'given' в Scala 3.
+language: ru
+num: 63
+previous-page: ca-context-bounds
+next-page: ca-type-classes
+versionSpecific: true
+---
+
+Для большей ясности, откуда берутся данные в текущей области видимости,
+для импорта экземпляров `given` используется специальная форма оператора `import`.
+Базовая форма показана в этом примере:
+
+```scala
+object A:
+ class TC
+ given tc: TC = ???
+ def f(using TC) = ???
+
+object B:
+ import A.* // импорт всех не-given элементов
+ import A.given // импорт экземпляров given
+```
+
+В этом коде предложение `import A.*` объекта `B` импортирует все элементы `A`, _кроме_ `given` экземпляра `tc`.
+И наоборот, второй импорт, `import A.given`, импортирует _только_ экземпляр `given`.
+Два предложения импорта также могут быть объединены в одно:
+
+```scala
+object B:
+ import A.{given, *}
+```
+
+## Обсуждение
+
+Селектор с подстановочным знаком `*` помещает в область видимости все определения, кроме given-ов или расширений,
+тогда как селектор `given` помещает в область видимости _все_ given-ы, включая те, которые являются результатом расширений.
+
+Эти правила имеют два основных преимущества:
+
+- понятнее, откуда берутся данные в текущей области видимости.
+ В частности, невозможно скрыть импортированные given-ы в длинном списке других импортов.
+- есть возможность импортировать все given, не импортируя ничего другого.
+ Это важно, потому что given-ы могут быть анонимными, поэтому обычное использование именованного импорта нецелесообразно.
+
+Дополнительные примеры синтаксиса "import given" показаны в главе ["Пакеты и импорт"][imports].
+
+[imports]: {% link _overviews/scala3-book/packaging-imports.md %}
diff --git a/_ru/scala3/book/ca-implicit-conversions.md b/_ru/scala3/book/ca-implicit-conversions.md
new file mode 100644
index 0000000000..f4703dc075
--- /dev/null
+++ b/_ru/scala3/book/ca-implicit-conversions.md
@@ -0,0 +1,236 @@
+---
+layout: multipage-overview
+title: Неявное преобразование типов
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице демонстрируется, как реализовать неявное преобразование типов в Scala 3.
+language: ru
+num: 66
+previous-page: ca-multiversal-equality
+next-page: ca-summary
+---
+
+Неявные преобразования — это мощная функция Scala, позволяющая пользователям предоставлять аргумент одного типа,
+как если бы он был другого типа, чтобы избежать шаблонного преобразования.
+
+> Обратите внимание, что в Scala 2 неявные преобразования также использовались для предоставления дополнительных членов
+> запечатанным классам (см. [Неявные классы]({% link _overviews/core/implicit-classes.md %})).
+> В Scala 3 мы рекомендуем использовать эту функциональность, определяя методы расширения вместо неявных преобразований
+> (хотя стандартная библиотека по-прежнему полагается на неявные преобразования по историческим причинам).
+
+## Пример
+
+Рассмотрим, например, метод `findUserById`, принимающий параметр типа `Long`:
+
+{% tabs implicit-conversions-1 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+def findUserById(id: Long): Option[User]
+```
+
+{% endtab %}
+{% endtabs %}
+
+Для краткости опустим определение типа `User` - это не имеет значения для нашего примера.
+
+В Scala есть возможность вызвать метод `findUserById` с аргументом типа `Int` вместо ожидаемого типа `Long`,
+потому что аргумент будет неявно преобразован в тип `Long`:
+
+{% tabs implicit-conversions-2 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val id: Int = 42
+findUserById(id) // OK
+```
+
+{% endtab %}
+{% endtabs %}
+
+Этот код не упадет с ошибкой компиляции “type mismatch: expected `Long`, found `Int`”,
+потому что есть неявное преобразование, которое преобразует аргумент `id` в значение типа `Long`.
+
+## Детальное объяснение
+
+В этом разделе описывается, как определять и использовать неявные преобразования.
+
+### Определение неявного преобразования
+
+{% tabs implicit-conversions-3 class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+
+В Scala 2 неявное преобразование из типа `S` в тип `T` определяется [неявным классом]({% link _overviews/core/implicit-classes.md %}) `T`,
+который принимает один параметр конструктора типа `S`, [неявное значение]({% link _overviews/scala3-book/ca-context-parameters.md %})
+типа функции `S => T` или неявный метод, преобразуемый в значение этого типа.
+
+Например, следующий код определяет неявное преобразование из `Int` в `Long`:
+
+```scala
+import scala.language.implicitConversions
+
+implicit def int2long(x: Int): Long = x.toLong
+```
+
+Это неявный метод, преобразуемый в значение типа `Int => Long`.
+
+См. раздел "Остерегайтесь силы неявных преобразований" ниже для объяснения пункта `import scala.language.implicitConversions` в начале.
+{% endtab %}
+
+{% tab 'Scala 3' %}
+В Scala 3 неявное преобразование типа `S` в тип `T` определяется [`given` экземпляром]({% link _overviews/scala3-book/ca-context-parameters.md %})
+типа `scala.Conversion[S, T]`.
+Для совместимости со Scala 2 его также можно определить неявным методом (подробнее читайте во вкладке Scala 2).
+
+Например, этот код определяет неявное преобразование из `Int` в `Long`:
+
+```scala
+given int2long: Conversion[Int, Long] with
+ def apply(x: Int): Long = x.toLong
+```
+
+Как и другие given определения, неявные преобразования могут быть анонимными:
+
+```scala
+given Conversion[Int, Long] with
+ def apply(x: Int): Long = x.toLong
+```
+
+Используя псевдоним, это можно выразить более кратко:
+
+```scala
+given Conversion[Int, Long] = (x: Int) => x.toLong
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+### Использование неявного преобразования
+
+Неявные преобразования применяются в двух случаях:
+
+1. Если выражение `e` имеет тип `S` и `S` не соответствует ожидаемому типу выражения `T`.
+2. В выборе `e.m` с `e` типа `S`, где `S` не определяет `m`
+ (для поддержки [методов расширения][extension methods] в стиле Scala-2).
+
+В первом случае ищется конверсия `c`, применимая к `e` и тип результата которой соответствует `T`.
+
+В примере выше, когда мы передаем аргумент `id` типа `Int` в метод `findUserById`,
+вставляется неявное преобразование `int2long(id)`.
+
+Во втором случае ищется преобразование `c`, применимое к `e` и результат которого содержит элемент с именем `m`.
+
+Примером является сравнение двух строк `"foo" < "bar"`.
+В этом случае `String` не имеет члена `<`, поэтому вставляется неявное преобразование `Predef.augmentString("foo") < "bar"`
+(`scala.Predef` автоматически импортируется во все программы Scala.).
+
+### Как неявные преобразования становятся доступными?
+
+Когда компилятор ищет подходящие преобразования:
+
+- во-первых, он смотрит в текущую лексическую область
+ - неявные преобразования, определенные в текущей области или во внешних областях
+ - импортированные неявные преобразования
+ - неявные преобразования, импортированные с помощью импорта подстановочных знаков (только в Scala 2)
+- затем он просматривает [сопутствующие объекты][companion objects], _связанные_ с типом аргумента `S` или ожидаемым типом `T`.
+ Сопутствующие объекты, связанные с типом `X`:
+ - сам объект-компаньон `X`
+ - сопутствующие объекты, связанные с любым из унаследованных типов `X`
+ - сопутствующие объекты, связанные с любым аргументом типа в `X`
+ - если `X` - это внутренний класс, внешние объекты, в которые он встроен
+
+Например, рассмотрим неявное преобразование `fromStringToUser`, определенное в объекте `Conversions`:
+
+{% tabs implicit-conversions-4 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+import scala.language.implicitConversions
+
+object Conversions {
+ implicit def fromStringToUser(name: String): User = (name: String) => User(name)
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+object Conversions:
+ given fromStringToUser: Conversion[String, User] = (name: String) => User(name)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Следующие операции импорта эквивалентно передают преобразование в область действия:
+
+{% tabs implicit-conversions-5 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+import Conversions.fromStringToUser
+// или
+import Conversions._
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+import Conversions.fromStringToUser
+// или
+import Conversions.given
+// или
+import Conversions.{given Conversion[String, User]}
+```
+
+Обратите внимание, что в Scala 3 импорт с подстановочными знаками (т.е. `import Conversions.*`)
+не импортирует given определения.
+
+{% endtab %}
+{% endtabs %}
+
+Во вводном примере преобразование из `Int` в `Long` не требует импорта, поскольку оно определено в объекте `Int`,
+который является сопутствующим объектом типа `Int`.
+
+Дополнительная литература:
+[Где Scala ищет неявные значения? (в Stackoverflow)](https://stackoverflow.com/a/5598107).
+
+### Остерегайтесь силы неявных преобразований
+
+{% tabs implicit-conversions-6 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+Поскольку неявные преобразования могут иметь подводные камни, если используются без разбора,
+компилятор предупреждает при компиляции определения неявного преобразования.
+
+Чтобы отключить предупреждения, выполните одно из следующих действий:
+
+- Импорт `scala.language.implicitConversions` в область определения неявного преобразования
+- Вызвать компилятор с командой `-language:implicitConversions`
+
+Предупреждение не выдается, когда компилятор применяет преобразование.
+{% endtab %}
+{% tab 'Scala 3' %}
+Поскольку неявные преобразования могут иметь подводные камни, если они используются без разбора,
+компилятор выдает предупреждение в двух случаях:
+
+- при компиляции определения неявного преобразования в стиле Scala 2.
+- на стороне вызова, где given экземпляр `scala.Conversion` вставляется как конверсия.
+
+Чтобы отключить предупреждения, выполните одно из следующих действий:
+
+- Импортировать `scala.language.implicitConversions` в область:
+ - определения неявного преобразования в стиле Scala 2
+ - стороны вызова, где given экземпляр `scala.Conversion` вставляется как конверсия.
+- Вызвать компилятор с командой `-language:implicitConversions`
+ {% endtab %}
+ {% endtabs %}
+
+[extension methods]: {% link _overviews/scala3-book/ca-extension-methods.md %}
+[companion objects]: {% link _overviews/scala3-book/domain-modeling-tools.md %}#companion-objects
diff --git a/_ru/scala3/book/ca-multiversal-equality.md b/_ru/scala3/book/ca-multiversal-equality.md
new file mode 100644
index 0000000000..19960bc97a
--- /dev/null
+++ b/_ru/scala3/book/ca-multiversal-equality.md
@@ -0,0 +1,207 @@
+---
+layout: multipage-overview
+title: Многостороннее равенство
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице демонстрируется, как реализовать многостороннее равенство в Scala 3.
+language: ru
+num: 65
+previous-page: ca-type-classes
+next-page: ca-implicit-conversions
+versionSpecific: true
+---
+
+Раньше в Scala было _универсальное равенство_ (_universal equality_):
+два значения любых типов можно было сравнивать друг с другом с помощью `==` и `!=`.
+Это произошло из-за того факта, что `==` и `!=` реализованы в терминах метода `equals` Java,
+который также может сравнивать значения любых двух ссылочных типов.
+
+Универсальное равенство удобно, но оно также опасно, поскольку подрывает безопасность типов.
+Например, предположим, что после некоторого рефакторинга осталась ошибочная программа,
+в которой значение `y` имеет тип `S` вместо правильного типа `T`:
+
+```scala
+val x = ... // типа T
+val y = ... // типа S, но должно быть типа T
+x == y // результат проверки типов всегда будет false
+```
+
+Если `y` сравнивается с другими значениями типа `T`, программа все равно будет проверять тип,
+так как значения всех типов можно сравнивать друг с другом.
+Но это, вероятно, даст неожиданные результаты и завершится ошибкой во время выполнения.
+
+Типобезопасный язык программирования может работать лучше, а многостороннее равенство —
+это дополнительный способ сделать универсальное равенство более безопасным.
+Он использует класс двоичного типа `CanEqual`, чтобы указать, что значения двух заданных типов можно сравнивать друг с другом.
+
+## Разрешение сравнения экземпляров класса
+
+По умолчанию в Scala 3 все ещё можно сравнивать на равенство следующим образом:
+
+```scala
+case class Cat(name: String)
+case class Dog(name: String)
+val d = Dog("Fido")
+val c = Cat("Morris")
+
+d == c // false, но он компилируется
+```
+
+Но в Scala 3 такие сравнения можно отключить.
+При (а) импорте `scala.language.strictEquality` или (б) использовании флага компилятора `-language:strictEquality`
+это сравнение больше не компилируется:
+
+```scala
+import scala.language.strictEquality
+
+val rover = Dog("Rover")
+val fido = Dog("Fido")
+println(rover == fido) // ошибка компиляции
+
+// сообщение об ошибке компиляции:
+// Values of types Dog and Dog cannot be compared with == or !=
+```
+
+## Включение сравнений
+
+Есть два способа включить сравнение с помощью класса типов `CanEqual`.
+Для простых случаев класс может _выводиться_ (_derive_) от класса `CanEqual`:
+
+```scala
+// Способ 1
+case class Dog(name: String) derives CanEqual
+```
+
+Как вы вскоре увидите, когда нужна большая гибкость, вы также можете использовать следующий синтаксис:
+
+```scala
+// Способ 2
+case class Dog(name: String)
+given CanEqual[Dog, Dog] = CanEqual.derived
+```
+
+Любой из этих двух подходов позволяет сравнивать экземпляры `Dog` друг с другом.
+
+## Более реалистичный пример
+
+В более реалистичном примере представим, что есть книжный интернет-магазин
+и мы хотим разрешить или запретить сравнение бумажных, печатных и аудиокниг.
+В Scala 3 для начала необходимо включить многостороннее равенство:
+
+```scala
+// [1] добавить этот импорт или command line flag: -language:strictEquality
+import scala.language.strictEquality
+```
+
+Затем создать объекты домена:
+
+```scala
+// [2] создание иерархии классов
+trait Book:
+ def author: String
+ def title: String
+ def year: Int
+
+case class PrintedBook(
+ author: String,
+ title: String,
+ year: Int,
+ pages: Int
+) extends Book
+
+case class AudioBook(
+ author: String,
+ title: String,
+ year: Int,
+ lengthInMinutes: Int
+) extends Book
+```
+
+Наконец, используем `CanEqual`, чтобы определить, какие сравнения необходимо разрешить:
+
+```scala
+// [3] создайте экземпляры класса типов, чтобы определить разрешенные сравнения.
+// разрешено `PrintedBook == PrintedBook`
+// разрешено `AudioBook == AudioBook`
+given CanEqual[PrintedBook, PrintedBook] = CanEqual.derived
+given CanEqual[AudioBook, AudioBook] = CanEqual.derived
+
+// [4a] сравнение двух печатных книг разрешено
+val p1 = PrintedBook("1984", "George Orwell", 1961, 328)
+val p2 = PrintedBook("1984", "George Orwell", 1961, 328)
+println(p1 == p2) // true
+
+// [4b] нельзя сравнивать печатную книгу и аудиокнигу
+val pBook = PrintedBook("1984", "George Orwell", 1961, 328)
+val aBook = AudioBook("1984", "George Orwell", 2006, 682)
+println(pBook == aBook) // ошибка компиляции
+```
+
+Последняя строка кода приводит к следующему сообщению компилятора об ошибке:
+
+```
+Values of types PrintedBook and AudioBook cannot be compared with == or !=
+```
+
+Вот как многостороннее равенство отлавливает недопустимые сравнения типов во время компиляции.
+
+### Включение “PrintedBook == AudioBook”
+
+Если есть необходимость разрешить сравнение "печатной книги" (`PrintedBook`) с аудио-книгой (`AudioBook`),
+то достаточно создать следующие два дополнительных сравнения равенства:
+
+```scala
+// разрешить `PrintedBook == AudioBook` и `AudioBook == PrintedBook`
+given CanEqual[PrintedBook, AudioBook] = CanEqual.derived
+given CanEqual[AudioBook, PrintedBook] = CanEqual.derived
+```
+
+Теперь можно сравнивать печатную книгу с аудио-книгой без ошибки компилятора:
+
+```scala
+println(pBook == aBook) // false
+println(aBook == pBook) // false
+```
+
+#### Внедрите "equals", чтобы они действительно работали
+
+Хотя эти сравнения теперь разрешены, они всегда будут ложными,
+потому что их методы `equals` не знают, как проводить подобные сравнения.
+Чтобы доработать сравнение, можно переопределить методы `equals` для каждого класса.
+Например, если переопределить метод `equals` для `AudioBook`:
+
+```scala
+case class AudioBook(
+ author: String,
+ title: String,
+ year: Int,
+ lengthInMinutes: Int
+) extends Book:
+ // переопределить, чтобы разрешить сравнение AudioBook с PrintedBook
+ override def equals(that: Any): Boolean = that match
+ case a: AudioBook =>
+ this.author == a.author
+ && this.title == a.title
+ && this.year == a.year
+ && this.lengthInMinutes == a.lengthInMinutes
+ case p: PrintedBook =>
+ this.author == p.author && this.title == p.title
+ case _ =>
+ false
+```
+
+Теперь можно сравнить `AudioBook` с `PrintedBook`:
+
+```scala
+println(aBook == pBook) // true (работает из-за переопределенного `equals` в `AudioBook`)
+println(pBook == aBook) // false
+```
+
+Книга `PrintedBook` не имеет метода `equals`, поэтому второе сравнение возвращает `false`.
+Чтобы включить это сравнение, достаточно переопределить метод `equals` в `PrintedBook`.
+
+Вы можете найти дополнительную информацию о [многостороннем равенстве][ref-equal] в справочной документации.
+
+[ref-equal]: {{ site.scala3ref }}/contextual/multiversal-equality.html
diff --git a/_ru/scala3/book/ca-summary.md b/_ru/scala3/book/ca-summary.md
new file mode 100644
index 0000000000..f3b68b7211
--- /dev/null
+++ b/_ru/scala3/book/ca-summary.md
@@ -0,0 +1,38 @@
+---
+layout: multipage-overview
+title: Обзор
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице представлен краткий обзор уроков по контекстуальным абстракциям.
+language: ru
+num: 67
+previous-page: ca-implicit-conversions
+next-page: concurrency
+---
+
+В этой главе представлено введение в большинство тем контекстных абстракций, в том числе:
+
+- [Методы расширения](ca-extension-methods.html)
+- [Экземпляры given и параметры контекста](ca-context-parameters.html)
+- [Контекстные границы](ca-context-bounds.html)
+- [Импорт given](ca-given-imports.html)
+- [Классы типов](ca-type-classes.html)
+- [Многостороннее равенство](ca-multiversal-equality.html)
+- [Неявные преобразования](ca-implicit-conversions.html)
+
+Все эти функции являются вариантами основной идеи **вывода термов**:
+учитывая тип, компилятор синтезирует “канонический” терм, который имеет этот тип.
+
+Несколько более сложных тем здесь не рассматриваются, в том числе:
+
+- Условные given экземпляры
+- Вывод класса типов
+- Контекстные функции
+- Контекстные параметры по имени
+- Связь с имплицитами Scala 2
+
+Эти темы подробно обсуждаются в [справочной документации][ref].
+
+[ref]: {{ site.scala3ref }}/contextual
diff --git a/_ru/scala3/book/ca-type-classes.md b/_ru/scala3/book/ca-type-classes.md
new file mode 100644
index 0000000000..5da4f9468f
--- /dev/null
+++ b/_ru/scala3/book/ca-type-classes.md
@@ -0,0 +1,230 @@
+---
+layout: multipage-overview
+title: Классы типов
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этой главе демонстрируется создание и использование классов типов.
+language: ru
+num: 64
+previous-page: ca-given-imports
+next-page: ca-multiversal-equality
+---
+
+Класс типов (_type class_) — это абстрактный параметризованный тип,
+который позволяет добавлять новое поведение к любому закрытому типу данных без использования подтипов.
+Если вы пришли с Java, то можно думать о классах типов как о чем-то вроде [`java.util.Comparator[T]`][comparator].
+
+> В статье ["Type Classes as Objects and Implicits"][typeclasses-paper] (2010 г.) обсуждаются основные идеи,
+> лежащие в основе классов типов в Scala.
+> Несмотря на то, что в статье используется более старая версия Scala, идеи актуальны и по сей день.
+
+Этот стиль программирования полезен во многих случаях, например:
+
+- выражение того, как тип, которым вы не владеете, например, из стандартной или сторонней библиотеки, соответствует такому поведению
+- добавление поведения к нескольким типам без введения отношений подтипов между этими типами (например, когда один расширяет другой)
+
+Классы типов — это трейты с одним или несколькими параметрами,
+реализации которых предоставляются в виде экземпляров `given` в Scala 3 или `implicit` значений в Scala 2.
+
+## Пример
+
+Например, `Show` - хорошо известный класс типов в Haskell, и в следующем коде показан один из способов его реализации в Scala.
+Если предположить, что классы Scala не содержат метода `toString`, то можно определить класс типов `Show`,
+чтобы добавить это поведение к любому типу, который вы хотите преобразовать в пользовательскую строку.
+
+### Класс типов
+
+Первым шагом в создании класса типов является объявление параметризованного trait, содержащего один или несколько абстрактных методов.
+Поскольку `Showable` содержит только один метод с именем `show`, он записывается так:
+
+{% tabs 'definition' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+// класс типов
+trait Showable[A] {
+ def show(a: A): String
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+// класс типов
+trait Showable[A]:
+ extension (a: A) def show: String
+```
+
+{% endtab %}
+{% endtabs %}
+
+Обратите внимание, что этот подход близок к обычному объектно-ориентированному подходу,
+когда обычно trait `Show` определяется следующим образом:
+
+{% tabs 'trait' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+// a trait
+trait Show {
+ def show: String
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+// a trait
+trait Show:
+ def show: String
+```
+
+{% endtab %}
+{% endtabs %}
+
+Следует отметить несколько важных моментов:
+
+1. Классы типов, например, `Showable` принимают параметр типа `A`, чтобы указать, для какого типа мы предоставляем реализацию `show`;
+ в отличие от классических трейтов, наподобие `Show`.
+2. Чтобы добавить функциональность `show` к определенному типу `A`, классический трейт требует наследования `A extends Show`,
+ в то время как для классов типов нам требуется реализация `Showable[A]`.
+3. В Scala 3, чтобы разрешить один и тот же синтаксис вызова метода в обоих случаях `Showable`,
+ который имитирует синтаксис `Show`, мы определяем `Showable.show` как метод расширения.
+
+### Реализация конкретных экземпляров
+
+Следующий шаг — определить, какие классы `Showable` должны работать в вашем приложении, а затем реализовать для них это поведение.
+Например, для реализации `Showable` следующего класса `Person`:
+
+{% tabs 'person' %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+case class Person(firstName: String, lastName: String)
+```
+
+{% endtab %}
+{% endtabs %}
+
+необходимо определить одно _каноническое значение_ типа `Showable[Person]`, т.е. экземпляр `Showable` для типа `Person`,
+как показано в следующем примере кода:
+
+{% tabs 'instance' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+implicit val showablePerson: Showable[Person] = new Showable[Person] {
+ def show(p: Person): String =
+ s"${p.firstName} ${p.lastName}"
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+given Showable[Person] with
+ extension (p: Person) def show: String =
+ s"${p.firstName} ${p.lastName}"
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Использование класса типов
+
+Теперь вы можете использовать этот класс типов следующим образом:
+
+{% tabs 'usage' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+val person = Person("John", "Doe")
+println(showablePerson.show(person))
+```
+
+Обратите внимание, что на практике классы типов обычно используются со значениями, тип которых неизвестен,
+в отличие от type `Person`, как показано в следующем разделе.
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+val person = Person("John", "Doe")
+println(person.show)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Опять же, если бы в Scala не было метода `toString`, доступного для каждого класса, вы могли бы использовать эту технику,
+чтобы добавить поведение `Showable` к любому классу, который вы хотите преобразовать в `String`.
+
+### Написание методов, использующих класс типов
+
+Как и в случае с наследованием, вы можете определить методы, которые используют `Showable` в качестве параметра типа:
+
+{% tabs 'method' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+def showAll[A](as: List[A])(implicit showable: Showable[A]): Unit =
+ as.foreach(a => println(showable.show(a)))
+
+showAll(List(Person("Jane"), Person("Mary")))
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+def showAll[A: Showable](as: List[A]): Unit =
+ as.foreach(a => println(a.show))
+
+showAll(List(Person("Jane"), Person("Mary")))
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Класс типов с несколькими методами
+
+Обратите внимание: если вы хотите создать класс типов с несколькими методами, исходный синтаксис выглядит следующим образом:
+
+{% tabs 'multiple-methods' class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait HasLegs[A] {
+ def walk(a: A): Unit
+ def run(a: A): Unit
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+trait HasLegs[A]:
+ extension (a: A)
+ def walk(): Unit
+ def run(): Unit
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Пример из реального мира
+
+В качестве примера из реального мира, как классы типов используются в Scala 3,
+см. обсуждение `CanEqual` в [разделе Multiversal Equality][multiversal].
+
+[typeclasses-paper]: https://infoscience.epfl.ch/record/150280/files/TypeClasses.pdf
+
+[typeclasses-chapter]: {% link _overviews/scala3-book/ca-type-classes.md %}
+[comparator]: https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html
+[multiversal]: {% link _overviews/scala3-book/ca-multiversal-equality.md %}
diff --git a/_ru/scala3/book/collections-classes.md b/_ru/scala3/book/collections-classes.md
new file mode 100644
index 0000000000..80fcf30248
--- /dev/null
+++ b/_ru/scala3/book/collections-classes.md
@@ -0,0 +1,971 @@
+---
+layout: multipage-overview
+title: Типы коллекций
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице представлены общие типы коллекций Scala 3 и некоторые из их методов.
+language: ru
+num: 38
+previous-page: collections-intro
+next-page: collections-methods
+---
+
+
+На этой странице показаны общие коллекции Scala 3 и сопутствующие им методы.
+Scala поставляется с большим количеством типов коллекций, на изучение которых может уйти время,
+поэтому желательно начать с нескольких из них, а затем использовать остальные по мере необходимости.
+Точно так же у каждого типа коллекции есть десятки методов, облегчающих разработку,
+поэтому лучше начать изучение лишь с небольшого количества.
+
+В этом разделе представлены наиболее распространенные типы и методы коллекций,
+которые вам понадобятся для начала работы.
+
+В конце этого раздела представлены дополнительные ссылки, для более глубокого изучения коллекций.
+
+## Три основные категории коллекций
+
+Для коллекций Scala можно выделить три основные категории:
+
+- **Последовательности** (**Sequences**/**Seq**) представляют собой последовательный набор элементов
+ и могут быть _индексированными_ (как массив) или _линейными_ (как связанный список)
+- **Мапы** (**Maps**) содержат набор пар ключ/значение, например Java `Map`, Python dictionary или Ruby `Hash`
+- **Множества** (**Sets**) — это неупорядоченный набор уникальных элементов
+
+Все они являются базовыми типами и имеют подтипы подходящие под конкретные задачи,
+таких как параллелизм (concurrency), кэширование (caching) и потоковая передача (streaming).
+В дополнение к этим трем основным категориям существуют и другие полезные типы коллекций,
+включая диапазоны (ranges), стеки (stacks) и очереди (queues).
+
+
+### Иерархия коллекций
+
+В качестве краткого обзора следующие три рисунка показывают иерархию классов и трейтов в коллекциях Scala.
+
+На первом рисунке показаны типы коллекций в пакете _scala.collection_.
+Все это высокоуровневые абстрактные классы или трейты, которые обычно имеют _неизменяемые_ и _изменяемые_ реализации.
+
+![General collection hierarchy][collections1]
+
+На этом рисунке показаны все коллекции в пакете _scala.collection.immutable_:
+
+![Immutable collection hierarchy][collections2]
+
+А на этом рисунке показаны все коллекции в пакете _scala.collection.mutable_:
+
+![Mutable collection hierarchy][collections3]
+
+В следующих разделах представлены некоторые из распространенных типов.
+
+## Общие коллекции
+
+Основные коллекции, используемые чаще всего:
+
+| Тип коллекции | Неизменяемая | Изменяемая | Описание |
+|----------------|--------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `List` | ✓ | | Линейная неизменяемая последовательность (связный список) |
+| `Vector` | ✓ | | Индексированная неизменяемая последовательность |
+| `LazyList` | ✓ | | Ленивый неизменяемый связанный список, элементы которого вычисляются только тогда, когда они необходимы; подходит для больших или бесконечных последовательностей. |
+| `ArrayBuffer` | | ✓ | Подходящий тип для изменяемой индексированной последовательности |
+| `ListBuffer` | | ✓ | Используется, когда вам нужен изменяемый список; обычно преобразуется в `List` |
+| `Map` | ✓ | ✓ | Итерируемая коллекция, состоящая из пар ключей и значений |
+| `Set` | ✓ | ✓ | Итерируемая коллекция без повторяющихся элементов |
+
+Как показано, `Map` и `Set` бывают как изменяемыми, так и неизменяемыми.
+
+Основы каждого типа демонстрируются в следующих разделах.
+
+> В Scala _буфер_ (_buffer_), такой как `ArrayBuffer` или `ListBuffer`, представляет собой последовательность,
+> которая может увеличиваться и уменьшаться.
+
+### Примечание о неизменяемых коллекциях
+
+В последующих разделах всякий раз, когда используется слово _immutable_, можно с уверенностью сказать,
+что тип предназначен для использования в стиле _функционального программирования_ (ФП).
+С помощью таких типов коллекция не меняется,
+а при вызове функциональных методов возвращается новый результат - новая коллекция.
+
+## Выбор последовательности
+
+При выборе _последовательности_ (последовательной коллекции элементов) нужно руководствоваться двумя основными вопросами:
+
+- должна ли последовательность индексироваться (как массив), обеспечивая быстрый доступ к любому элементу,
+ или она должна быть реализована как линейный связанный список?
+- необходима изменяемая или неизменяемая коллекция?
+
+Рекомендуемые универсальные последовательности:
+
+| Тип\Категория | Неизменяемая | Изменяемая |
+|-----------------------------|--------------|---------------|
+| индексируемая | `Vector` | `ArrayBuffer` |
+| линейная (связанный список) | `List` | `ListBuffer` |
+
+Например, если нужна неизменяемая индексированная коллекция, в общем случае следует использовать `Vector`.
+И наоборот, если нужна изменяемая индексированная коллекция, используйте `ArrayBuffer`.
+
+> `List` и `Vector` часто используются при написании кода в функциональном стиле.
+> `ArrayBuffer` обычно используется при написании кода в императивном стиле.
+> `ListBuffer` используется тогда, когда стили смешиваются, например, при создании списка.
+
+Следующие несколько разделов кратко демонстрируют типы `List`, `Vector` и `ArrayBuffer`.
+
+
+## `List`
+
+[List](https://www.scala-lang.org/api/current/scala/collection/immutable/List.html)
+представляет собой линейную неизменяемую последовательность.
+Каждый раз, когда в список добавляются или удаляются элементы, по сути создается новый список из существующего.
+
+### Создание списка
+
+`List` можно создать различными способами:
+
+{% tabs list-creation %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val ints = List(1, 2, 3)
+val names = List("Joel", "Chris", "Ed")
+
+// другой путь создания списка List
+val namesAgain = "Joel" :: "Chris" :: "Ed" :: Nil
+```
+{% endtab %}
+
+{% endtabs %}
+
+При желании тип списка можно объявить, хотя обычно в этом нет необходимости:
+
+{% tabs list-type %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val ints: List[Int] = List(1, 2, 3)
+val names: List[String] = List("Joel", "Chris", "Ed")
+```
+{% endtab %}
+
+{% endtabs %}
+
+Одно исключение — когда в коллекции смешанные типы; в этом случае тип желательно указывать явно:
+
+{% tabs list-mixed-types class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+val things: List[Any] = List(1, "two", 3.0)
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val things: List[String | Int | Double] = List(1, "two", 3.0) // с типами объединения
+val thingsAny: List[Any] = List(1, "two", 3.0) // с Any
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Добавление элементов в список
+
+Поскольку `List` неизменяем, в него нельзя добавлять новые элементы.
+Вместо этого создается новый список с добавленными к существующему списку элементами.
+Например, учитывая этот `List`:
+
+{% tabs adding-elements-init %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val a = List(1, 2, 3)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Для _добавления_ (_prepend_) к началу списка одного элемента используется метод `::`, для добавления нескольких — `:::`, как показано здесь:
+
+{% tabs adding-elements-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val b = 0 :: a // List(0, 1, 2, 3)
+val c = List(-1, 0) ::: a // List(-1, 0, 1, 2, 3)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Также можно _добавить_ (_append_) элементы в конец `List`, но, поскольку `List` является односвязным,
+следует добавлять к нему элементы только в начало;
+добавление элементов в конец списка — относительно медленная операция,
+особенно при работе с большими последовательностями.
+
+> Совет: если необходимо добавлять к неизменяемой последовательности элементы в начало и конец, используйте `Vector`.
+
+Поскольку `List` является связанным списком,
+крайне нежелательно пытаться получить доступ к элементам больших списков по значению их индекса.
+Например, если есть `List` с миллионом элементов, доступ к такому элементу, как `myList(999_999)`,
+займет относительно много времени, потому что этот запрос должен пройти почти через все элементы.
+Если есть большая коллекция и необходимо получать доступ к элементам по их индексу, то
+вместо `List` используйте `Vector` или `ArrayBuffer`.
+
+### Как запомнить названия методов
+
+В методах Scala символ `:` представляет сторону, на которой находится последовательность,
+поэтому, когда используется метод `+:`, список нужно указывать справа:
+
+{% tabs list-prepending %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+0 +: a
+```
+{% endtab %}
+
+{% endtabs %}
+
+Аналогично, если используется `:+`, список должен быть слева:
+
+{% tabs list-appending %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+a :+ 4
+```
+{% endtab %}
+
+{% endtabs %}
+
+Хорошей особенностью таких символических имен у методов является то, что они стандартизированы.
+
+Те же имена методов используются с другими неизменяемыми последовательностями, такими как `Seq` и `Vector`.
+Также можно использовать несимволические имена методов для добавления элементов в начало (`a.prepended(4)`)
+или конец (`a.appended(4)`).
+
+### Как пройтись по списку
+
+Представим, что есть `List` имён:
+
+{% tabs list-loop-init %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val names = List("Joel", "Chris", "Ed")
+```
+{% endtab %}
+
+{% endtabs %}
+
+Напечатать каждое имя можно следующим способом:
+
+{% tabs list-loop-example class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+for (name <- names) println(name)
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+for name <- names do println(name)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Вот как это выглядит в REPL:
+
+{% tabs list-loop-repl class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+scala> for (name <- names) println(name)
+Joel
+Chris
+Ed
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+scala> for name <- names do println(name)
+Joel
+Chris
+Ed
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+Преимуществом использования выражений вида `for` с коллекциями в том, что Scala стандартизирован,
+и один и тот же подход работает со всеми последовательностями,
+включая `Array`, `ArrayBuffer`, `List`, `Seq`, `Vector`, `Map`, `Set` и т.д.
+
+### Немного истории
+
+Список Scala подобен списку из языка программирования [Lisp](https://en.wikipedia.org/wiki/Lisp_(programming_language)),
+который был впервые представлен в 1958 году.
+Действительно, в дополнение к привычному способу создания списка:
+
+{% tabs list-history-init %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val ints = List(1, 2, 3)
+```
+{% endtab %}
+
+{% endtabs %}
+
+точно такой же список можно создать следующим образом:
+
+{% tabs list-history-init2 %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val list = 1 :: 2 :: 3 :: Nil
+```
+{% endtab %}
+
+{% endtabs %}
+
+REPL показывает, как это работает:
+
+{% tabs list-history-repl %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+scala> val list = 1 :: 2 :: 3 :: Nil
+list: List[Int] = List(1, 2, 3)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Это работает, потому что `List` — односвязный список, оканчивающийся элементом `Nil`,
+а `::` — это метод `List`, работающий как оператор “cons” в Lisp.
+
+
+### Отступление: LazyList
+
+Коллекции Scala также включают [LazyList](https://www.scala-lang.org/api/current/scala/collection/immutable/LazyList.html),
+который представляет собой _ленивый_ неизменяемый связанный список.
+Он называется «ленивым» — или нестрогим — потому что вычисляет свои элементы только тогда, когда они необходимы.
+
+Вы можете увидеть отложенное вычисление `LazyList` в REPL:
+
+{% tabs lazylist-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val x = LazyList.range(1, Int.MaxValue)
+x.take(1) // LazyList()
+x.take(5) // LazyList()
+x.map(_ + 1) // LazyList()
+```
+{% endtab %}
+
+{% endtabs %}
+
+Во всех этих примерах ничего не происходит.
+Действительно, ничего не произойдет, пока вы не заставите это произойти, например, вызвав метод `foreach`:
+
+{% tabs lazylist-evaluation-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+scala> x.take(1).foreach(println)
+1
+```
+{% endtab %}
+
+{% endtabs %}
+
+Дополнительные сведения об использовании, преимуществах и недостатках строгих и нестрогих (ленивых) коллекций
+см. в обсуждениях “строгих” и “нестрогих” на странице [Архитектура коллекции в Scala 2.13][strict].
+
+## Vector
+
+[Vector](https://www.scala-lang.org/api/current/scala/collection/immutable/Vector.html) - это индексируемая неизменяемая последовательность.
+“Индексируемая” часть описания означает, что она обеспечивает произвольный доступ
+и обновление за практически постоянное время,
+поэтому можно быстро получить доступ к элементам `Vector` по значению их индекса,
+например, получить доступ к `listOfPeople(123_456_789)`.
+
+В общем, за исключением той разницы, что (а) `Vector` индексируется, а `List` - нет,
+и (б) `List` имеет метод `::`, эти два типа работают одинаково,
+поэтому мы быстро пробежимся по следующим примерам.
+
+Вот несколько способов создания `Vector`:
+
+{% tabs vector-creation %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val nums = Vector(1, 2, 3, 4, 5)
+
+val strings = Vector("one", "two")
+
+case class Person(name: String)
+val people = Vector(
+ Person("Bert"),
+ Person("Ernie"),
+ Person("Grover")
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Поскольку `Vector` неизменяем, в него нельзя добавить новые элементы.
+Вместо этого создается новая последовательность, с добавленными к существующему `Vector` в начало или в конец элементами.
+
+Например, так элементы добавляются в конец:
+
+{% tabs vector-appending %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val a = Vector(1,2,3) // Vector(1, 2, 3)
+val b = a :+ 4 // Vector(1, 2, 3, 4)
+val c = a ++ Vector(4, 5) // Vector(1, 2, 3, 4, 5)
+```
+{% endtab %}
+
+{% endtabs %}
+
+А так - в начало Vector-а:
+
+{% tabs vector-prepending %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val a = Vector(1,2,3) // Vector(1, 2, 3)
+val b = 0 +: a // Vector(0, 1, 2, 3)
+val c = Vector(-1, 0) ++: a // Vector(-1, 0, 1, 2, 3)
+```
+{% endtab %}
+
+{% endtabs %}
+
+В дополнение к быстрому произвольному доступу и обновлениям, `Vector` обеспечивает быстрое добавление в начало и конец.
+
+> Подробную информацию о производительности `Vector` и других коллекций
+> см. [в характеристиках производительности коллекций](https://docs.scala-lang.org/overviews/collections-2.13/performance-characteristics.html).
+
+Наконец, `Vector` в выражениях вида `for` используется точно так же, как `List`, `ArrayBuffer` или любая другая последовательность:
+
+{% tabs vector-loop class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+scala> val names = Vector("Joel", "Chris", "Ed")
+val names: Vector[String] = Vector(Joel, Chris, Ed)
+
+scala> for (name <- names) println(name)
+Joel
+Chris
+Ed
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+scala> val names = Vector("Joel", "Chris", "Ed")
+val names: Vector[String] = Vector(Joel, Chris, Ed)
+
+scala> for name <- names do println(name)
+Joel
+Chris
+Ed
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+## ArrayBuffer
+
+`ArrayBuffer` используется тогда, когда нужна изменяемая индексированная последовательность общего назначения.
+Поскольку `ArrayBuffer` индексирован, произвольный доступ к элементам выполняется быстро.
+
+### Создание ArrayBuffer
+
+Чтобы использовать `ArrayBuffer`, его нужно вначале импортировать:
+
+{% tabs arraybuffer-import %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+import scala.collection.mutable.ArrayBuffer
+```
+{% endtab %}
+
+{% endtabs %}
+
+Если необходимо начать с пустого `ArrayBuffer`, просто укажите его тип:
+
+{% tabs arraybuffer-creation %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+var strings = ArrayBuffer[String]()
+var ints = ArrayBuffer[Int]()
+var people = ArrayBuffer[Person]()
+```
+{% endtab %}
+
+{% endtabs %}
+
+Если известен примерный размер `ArrayBuffer`, его можно задать:
+
+{% tabs list-creation-with-size %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+// готов вместить 100 000 чисел
+val buf = new ArrayBuffer[Int](100_000)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Чтобы создать новый `ArrayBuffer` с начальными элементами,
+достаточно просто указать начальные элементы, как для `List` или `Vector`:
+
+{% tabs arraybuffer-init %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val nums = ArrayBuffer(1, 2, 3)
+val people = ArrayBuffer(
+ Person("Bert"),
+ Person("Ernie"),
+ Person("Grover")
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Добавление элементов в ArrayBuffer
+
+Новые элементы добавляются в `ArrayBuffer` с помощью методов `+=` и `++=`.
+Также можно использовать текстовый аналог: `append`, `appendAll`, `insert`, `insertAll`, `prepend` и `prependAll`.
+Вот несколько примеров с `+=` и `++=`:
+
+{% tabs arraybuffer-add %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val nums = ArrayBuffer(1, 2, 3) // ArrayBuffer(1, 2, 3)
+nums += 4 // ArrayBuffer(1, 2, 3, 4)
+nums ++= List(5, 6) // ArrayBuffer(1, 2, 3, 4, 5, 6)
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Удаление элементов из ArrayBuffer
+
+`ArrayBuffer` является изменяемым,
+поэтому у него есть такие методы, как `-=`, `--=`, `clear`, `remove` и другие.
+Примеры с `-=` и `--=`:
+
+{% tabs arraybuffer-remove %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val a = ArrayBuffer.range('a', 'h') // ArrayBuffer(a, b, c, d, e, f, g)
+a -= 'a' // ArrayBuffer(b, c, d, e, f, g)
+a --= Seq('b', 'c') // ArrayBuffer(d, e, f, g)
+a --= Set('d', 'e') // ArrayBuffer(f, g)
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Обновление элементов в ArrayBuffer
+
+Элементы в `ArrayBuffer` можно обновлять, либо переназначать:
+
+{% tabs arraybuffer-update %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val a = ArrayBuffer.range(1,5) // ArrayBuffer(1, 2, 3, 4)
+a(2) = 50 // ArrayBuffer(1, 2, 50, 4)
+a.update(0, 10) // ArrayBuffer(10, 2, 50, 4)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+
+## Maps
+
+`Map` — это итерируемая коллекция, состоящая из пар ключей и значений.
+В Scala есть как изменяемые, так и неизменяемые типы `Map`.
+В этом разделе показано, как использовать _неизменяемый_ `Map`.
+
+### Создание неизменяемой Map
+
+Неизменяемая `Map` создается следующим образом:
+
+{% tabs map-init %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val states = Map(
+ "AK" -> "Alaska",
+ "AL" -> "Alabama",
+ "AZ" -> "Arizona"
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Перемещаться по элементам `Map` используя выражение `for` можно следующим образом:
+
+{% tabs map-loop class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+for ((k, v) <- states) println(s"key: $k, value: $v")
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+for (k, v) <- states do println(s"key: $k, value: $v")
+```
+{% endtab %}
+
+{% endtabs %}
+
+REPL показывает, как это работает:
+
+{% tabs map-repl class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+scala> for ((k, v) <- states) println(s"key: $k, value: $v")
+key: AK, value: Alaska
+key: AL, value: Alabama
+key: AZ, value: Arizona
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+scala> for (k, v) <- states do println(s"key: $k, value: $v")
+key: AK, value: Alaska
+key: AL, value: Alabama
+key: AZ, value: Arizona
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Доступ к элементам Map
+
+Доступ к элементам `Map` осуществляется через указание в скобках значения ключа:
+
+{% tabs map-access-element %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val ak = states("AK") // ak: String = Alaska
+val al = states("AL") // al: String = Alabama
+```
+{% endtab %}
+
+{% endtabs %}
+
+На практике также используются такие методы, как `keys`, `keySet`, `keysIterator`, `for` выражения
+и функции высшего порядка, такие как `map`, для работы с ключами и значениями `Map`.
+
+### Добавление элемента в Map
+
+При добавлении элементов в неизменяемую мапу с помощью `+` и `++`, создается новая мапа:
+
+{% tabs map-add-element %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val a = Map(1 -> "one") // a: Map(1 -> one)
+val b = a + (2 -> "two") // b: Map(1 -> one, 2 -> two)
+val c = b ++ Seq(
+ 3 -> "three",
+ 4 -> "four"
+)
+// c: Map(1 -> one, 2 -> two, 3 -> three, 4 -> four)
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Удаление элементов из Map
+
+Элементы удаляются с помощью методов `-` или `--`.
+В случае неизменяемой `Map` создается новый экземпляр, который нужно присвоить новой переменной:
+
+{% tabs map-remove-element %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val a = Map(
+ 1 -> "one",
+ 2 -> "two",
+ 3 -> "three",
+ 4 -> "four"
+)
+
+val b = a - 4 // b: Map(1 -> one, 2 -> two, 3 -> three)
+val c = a - 4 - 3 // c: Map(1 -> one, 2 -> two)
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Обновление элементов в Map
+
+Чтобы обновить элементы на неизменяемой `Map`, используется метод `update` (или оператор `+`):
+
+{% tabs map-update-element %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val a = Map(
+ 1 -> "one",
+ 2 -> "two",
+ 3 -> "three"
+)
+
+val b = a.updated(3, "THREE!") // b: Map(1 -> one, 2 -> two, 3 -> THREE!)
+val c = a + (2 -> "TWO...") // c: Map(1 -> one, 2 -> TWO..., 3 -> three)
+```
+{% endtab %}
+
+{% endtabs %}
+
+### Перебор элементов в Map
+
+Элементы в `Map` можно перебрать с помощью выражения `for`, как и для остальных коллекций:
+
+{% tabs map-traverse class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+val states = Map(
+ "AK" -> "Alaska",
+ "AL" -> "Alabama",
+ "AZ" -> "Arizona"
+)
+
+for ((k, v) <- states) println(s"key: $k, value: $v")
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val states = Map(
+ "AK" -> "Alaska",
+ "AL" -> "Alabama",
+ "AZ" -> "Arizona"
+)
+
+for (k, v) <- states do println(s"key: $k, value: $v")
+```
+{% endtab %}
+
+{% endtabs %}
+
+Существует _много_ способов работы с ключами и значениями на `Map`.
+Общие методы `Map` включают `foreach`, `map`, `keys` и `values`.
+
+В Scala есть много других специализированных типов `Map`,
+включая `CollisionProofHashMap`, `HashMap`, `LinkedHashMap`, `ListMap`, `SortedMap`, `TreeMap`, `WeakHashMap` и другие.
+
+
+## Работа с множествами
+
+Множество ([Set]({{site.baseurl}}/overviews/collections-2.13/sets.html)) - итерируемая коллекция без повторяющихся элементов.
+
+В Scala есть как изменяемые, так и неизменяемые типы `Set`.
+В этом разделе демонстрируется _неизменяемое_ множество.
+
+### Создание множества
+
+Создание нового пустого множества:
+
+{% tabs set-creation %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val nums = Set[Int]()
+val letters = Set[Char]()
+```
+{% endtab %}
+
+{% endtabs %}
+
+Создание множества с исходными данными:
+
+{% tabs set-init %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val nums = Set(1, 2, 3, 3, 3) // Set(1, 2, 3)
+val letters = Set('a', 'b', 'c', 'c') // Set('a', 'b', 'c')
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+### Добавление элементов в множество
+
+В неизменяемое множество новые элементы добавляются с помощью `+` и `++`, результат присваивается новой переменной:
+
+{% tabs set-add-element %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val a = Set(1, 2) // Set(1, 2)
+val b = a + 3 // Set(1, 2, 3)
+val c = b ++ Seq(4, 1, 5, 5) // HashSet(5, 1, 2, 3, 4)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Стоит отметить, что повторяющиеся элементы не добавляются в множество,
+а также, что порядок элементов произвольный.
+
+
+### Удаление элементов из множества
+
+Элементы из множества удаляются с помощью методов `-` и `--`, результат также должен присваиваться новой переменной:
+
+{% tabs set-remove-element %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val a = Set(1, 2, 3, 4, 5) // HashSet(5, 1, 2, 3, 4)
+val b = a - 5 // HashSet(1, 2, 3, 4)
+val c = b -- Seq(3, 4) // HashSet(1, 2)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+
+## Диапазон (Range)
+
+`Range` часто используется для заполнения структур данных и для `for` выражений.
+Эти REPL примеры демонстрируют, как создавать диапазоны:
+
+{% tabs range-init %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+1 to 5 // Range(1, 2, 3, 4, 5)
+1 until 5 // Range(1, 2, 3, 4)
+1 to 10 by 2 // Range(1, 3, 5, 7, 9)
+'a' to 'c' // NumericRange(a, b, c)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Range можно использовать для заполнения коллекций:
+
+{% tabs range-conversion %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val x = (1 to 5).toList // List(1, 2, 3, 4, 5)
+val x = (1 to 5).toBuffer // ArrayBuffer(1, 2, 3, 4, 5)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Они также используются в `for` выражениях:
+
+{% tabs range-iteration class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+scala> for (i <- 1 to 3) println(i)
+1
+2
+3
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+scala> for i <- 1 to 3 do println(i)
+1
+2
+3
+```
+{% endtab %}
+
+{% endtabs %}
+
+Во многих коллекциях есть метод `range`:
+
+{% tabs range-methods %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+Vector.range(1, 5) // Vector(1, 2, 3, 4)
+List.range(1, 10, 2) // List(1, 3, 5, 7, 9)
+Set.range(1, 10) // HashSet(5, 1, 6, 9, 2, 7, 3, 8, 4)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Диапазоны также полезны для создания тестовых коллекций:
+
+{% tabs range-tests %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val evens = (0 to 10 by 2).toList // List(0, 2, 4, 6, 8, 10)
+val odds = (1 to 10 by 2).toList // List(1, 3, 5, 7, 9)
+val doubles = (1 to 5).map(_ * 2.0) // Vector(2.0, 4.0, 6.0, 8.0, 10.0)
+
+// Создание Map
+val map = (1 to 3).map(e => (e,s"$e")).toMap
+// map: Map[Int, String] = Map(1 -> "1", 2 -> "2", 3 -> "3")
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+## Больше деталей
+
+Если вам нужна дополнительная информация о специализированных коллекциях, см. следующие ресурсы:
+
+- [Конкретные неизменяемые классы коллекций](https://docs.scala-lang.org/overviews/collections-2.13/concrete-immutable-collection-classes.html)
+- [Конкретные изменяемые классы коллекций](https://docs.scala-lang.org/overviews/collections-2.13/concrete-mutable-collection-classes.html)
+- [Как устроены коллекции? Какую из них следует выбрать?](https://docs.scala-lang.org/tutorials/FAQ/collections.html)
+
+
+
+[strict]: {% link _overviews/core/architecture-of-scala-213-collections.md %}
+[collections1]: /resources/images/tour/collections-diagram-213.svg
+[collections2]: /resources/images/tour/collections-immutable-diagram-213.svg
+[collections3]: /resources/images/tour/collections-mutable-diagram-213.svg
diff --git a/_ru/scala3/book/collections-intro.md b/_ru/scala3/book/collections-intro.md
new file mode 100644
index 0000000000..c29c5ecc29
--- /dev/null
+++ b/_ru/scala3/book/collections-intro.md
@@ -0,0 +1,22 @@
+---
+layout: multipage-overview
+title: Коллекции в Scala
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: На этой странице представлено введение в общие классы коллекций и их методы в Scala 3.
+language: ru
+num: 37
+previous-page: packaging-imports
+next-page: collections-classes
+---
+
+В этой главе представлены наиболее распространенные коллекции Scala 3 и сопутствующие им методы.
+Scala поставляется с множеством типов коллекций,
+Вы можете многого добиться, начав использовать лишь небольшое количество типов, а затем, по мере необходимости, начать применять остальные.
+Точно так же у каждого типа есть десятки методов,
+облегчающих разработку, но можно многого добиться, начав лишь с нескольких.
+
+Поэтому в этом разделе представлены наиболее распространенные типы и методы коллекций,
+которые вам понадобятся для начала работы.
diff --git a/_ru/scala3/book/collections-methods.md b/_ru/scala3/book/collections-methods.md
new file mode 100644
index 0000000000..a11cdd1738
--- /dev/null
+++ b/_ru/scala3/book/collections-methods.md
@@ -0,0 +1,662 @@
+---
+layout: multipage-overview
+title: Методы в коллекциях
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице показаны общие методы классов коллекций Scala 3.
+language: ru
+num: 39
+previous-page: collections-classes
+next-page: collections-summary
+---
+
+
+
+Важным преимуществом коллекций Scala является то, что они поставляются с десятками методов “из коробки”,
+которые доступны как для неизменяемых, так и для изменяемых типов коллекций.
+Больше нет необходимости писать пользовательские циклы `for` каждый раз, когда нужно работать с коллекцией.
+При переходе от одного проекта к другому, можно обнаружить, что используются одни и те же методы.
+
+В коллекциях доступны _десятки_ методов, поэтому здесь показаны не все из них.
+Показаны только некоторые из наиболее часто используемых методов, в том числе:
+
+- `map`
+- `filter`
+- `foreach`
+- `head`
+- `tail`
+- `take`, `takeWhile`
+- `drop`, `dropWhile`
+- `reduce`
+
+Следующие методы работают со всеми типами последовательностей, включая `List`, `Vector`, `ArrayBuffer` и т.д.
+Примеры рассмотрены на `List`-е, если не указано иное.
+
+> Важно напомнить, что ни один из методов в `List` не изменяет список.
+> Все они работают в функциональном стиле, то есть возвращают новую коллекцию с измененными результатами.
+
+## Примеры распространенных методов
+
+Для общего представления в примерах ниже показаны некоторые из наиболее часто используемых методов коллекций.
+Вот несколько методов, которые не используют лямбда-выражения:
+
+{% tabs common-method-examples %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val a = List(10, 20, 30, 40, 10) // List(10, 20, 30, 40, 10)
+
+a.distinct // List(10, 20, 30, 40)
+a.drop(2) // List(30, 40, 10)
+a.dropRight(2) // List(10, 20, 30)
+a.head // 10
+a.headOption // Some(10)
+a.init // List(10, 20, 30, 40)
+a.intersect(List(19,20,21)) // List(20)
+a.last // 10
+a.lastOption // Some(10)
+a.slice(2,4) // List(30, 40)
+a.tail // List(20, 30, 40, 10)
+a.take(3) // List(10, 20, 30)
+a.takeRight(2) // List(40, 10)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+### Функции высшего порядка и лямбда-выражения
+
+Далее будут показаны некоторые часто используемые функции высшего порядка (HOF),
+которые принимают лямбды (анонимные функции).
+Для начала приведем несколько вариантов лямбда-синтаксиса,
+начиная с самой длинной формы, поэтапно переходящей к наиболее сжатой:
+
+{% tabs higher-order-functions-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+// все эти функции одинаковые и возвращают
+// одно и тоже: List(10, 20, 10)
+
+a.filter((i: Int) => i < 25) // 1. наиболее расширенная форма
+a.filter((i) => i < 25) // 2. `Int` необязателен
+a.filter(i => i < 25) // 3. скобки можно опустить
+a.filter(_ < 25) // 4. `i` необязателен
+```
+{% endtab %}
+
+{% endtabs %}
+
+В этих примерах:
+
+1. Первый пример показывает самую длинную форму.
+ Такое многословие требуется _редко_, только в самых сложных случаях.
+2. Компилятор знает, что `a` содержит `Int`, поэтому нет необходимости повторять это в функции.
+3. Если в функции только один параметр, например `i`, то скобки не нужны.
+4. В случае одного параметра, если он появляется в анонимной функции только раз, его можно заменить на `_`.
+
+В главе [Анонимные функции][lambdas] представлена более подробная информация
+и примеры правил, связанных с сокращением лямбда-выражений.
+
+Примеры других HOF, использующих краткий лямбда-синтаксис:
+
+{% tabs anonymous-functions-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+a.dropWhile(_ < 25) // List(30, 40, 10)
+a.filter(_ > 100) // List()
+a.filterNot(_ < 25) // List(30, 40)
+a.find(_ > 20) // Some(30)
+a.takeWhile(_ < 30) // List(10, 20)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Важно отметить, что HOF также принимают в качестве параметров методы и функции, а не только лямбда-выражения.
+Вот несколько примеров, в которых используется метод с именем `double`.
+Снова показаны несколько вариантов лямбда-выражений:
+
+{% tabs method-as-parameter-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+def double(i: Int) = i * 2
+
+// these all return `List(20, 40, 60, 80, 20)`
+a.map(i => double(i))
+a.map(double(_))
+a.map(double)
+```
+{% endtab %}
+
+{% endtabs %}
+
+В последнем примере, когда анонимная функция состоит из одного вызова функции, принимающей один аргумент,
+нет необходимости указывать имя аргумента, поэтому даже `_` не требуется.
+
+Наконец, HOF можно комбинировать:
+
+{% tabs higher-order-functions-combination-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+// выдает `List(100, 200)`
+a.filter(_ < 40)
+ .takeWhile(_ < 30)
+ .map(_ * 10)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+## Пример данных
+
+В следующих разделах используются такие списки:
+
+{% tabs sample-data %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val oneToTen = (1 to 10).toList
+val names = List("adam", "brandy", "chris", "david")
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+## `map`
+
+Метод `map` проходит через каждый элемент в списке, применяя переданную функцию к элементу, по одному за раз;
+затем возвращается новый список с измененными элементами.
+
+Вот пример применения метода `map` к списку `oneToTen`:
+
+{% tabs map-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+scala> val doubles = oneToTen.map(_ * 2)
+doubles: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Также можно писать анонимные функции, используя более длинную форму, например:
+
+{% tabs map-example-anonymous %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+scala> val doubles = oneToTen.map(i => i * 2)
+doubles: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Однако в этом документе будет всегда использоваться первая, более короткая форма.
+
+Вот еще несколько примеров применения метода `map` к `oneToTen` и `names`:
+
+{% tabs few-more-examples %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+scala> val capNames = names.map(_.capitalize)
+capNames: List[String] = List(Adam, Brandy, Chris, David)
+
+scala> val nameLengthsMap = names.map(s => (s, s.length)).toMap
+nameLengthsMap: Map[String, Int] = Map(adam -> 4, brandy -> 6, chris -> 5, david -> 5)
+
+scala> val isLessThanFive = oneToTen.map(_ < 5)
+isLessThanFive: List[Boolean] = List(true, true, true, true, false, false, false, false, false, false)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Как показано в последних двух примерах, совершенно законно (и распространено) использование `map` для возврата коллекции,
+которая имеет тип, отличный от исходного типа.
+
+
+## `filter`
+
+Метод `filter` создает новый список, содержащий только те элементы, которые удовлетворяют предоставленному предикату.
+Предикат или условие — это функция, которая возвращает `Boolean` (`true` или `false`).
+Вот несколько примеров:
+
+{% tabs filter-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+scala> val lessThanFive = oneToTen.filter(_ < 5)
+lessThanFive: List[Int] = List(1, 2, 3, 4)
+
+scala> val evens = oneToTen.filter(_ % 2 == 0)
+evens: List[Int] = List(2, 4, 6, 8, 10)
+
+scala> val shortNames = names.filter(_.length <= 4)
+shortNames: List[String] = List(adam)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Отличительной особенностью функциональных методов коллекций является то,
+что их можно объединять вместе для решения задач.
+Например, в этом примере показано, как связать `filter` и `map`:
+
+{% tabs filter-example-anonymous %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+oneToTen.filter(_ < 4).map(_ * 10)
+```
+{% endtab %}
+
+{% endtabs %}
+
+REPL показывает результат:
+
+{% tabs filter-example-anonymous-repl %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+scala> oneToTen.filter(_ < 4).map(_ * 10)
+val res1: List[Int] = List(10, 20, 30)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+## `foreach`
+
+Метод `foreach` используется для перебора всех элементов коллекции.
+Стоит обратить внимание, что `foreach` используется для побочных эффектов, таких как печать информации.
+Вот пример с `names`:
+
+{% tabs foreach-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+scala> names.foreach(println)
+adam
+brandy
+chris
+david
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+
+## `head`
+
+Метод `head` взят из Lisp и других более ранних языков функционального программирования.
+Он используется для доступа к первому элементу (головному (_head_) элементу) списка:
+
+{% tabs head-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+oneToTen.head // 1
+names.head // adam
+```
+{% endtab %}
+
+{% endtabs %}
+
+`String` можно рассматривать как последовательность символов, т.е. строка также является коллекцией,
+а значит содержит соответствующие методы.
+Вот как `head` работает со строками:
+
+{% tabs string-head-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+"foo".head // 'f'
+"bar".head // 'b'
+```
+{% endtab %}
+
+{% endtabs %}
+
+`head` — отличный метод для работы, но в качестве предостережения следует помнить, что
+он также может генерировать исключение при вызове для пустой коллекции:
+
+{% tabs head-error-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val emptyList = List[Int]() // emptyList: List[Int] = List()
+emptyList.head // java.util.NoSuchElementException: head of empty list
+```
+{% endtab %}
+
+{% endtabs %}
+
+Чтобы не натыкаться на исключение вместо `head` желательно использовать `headOption`,
+особенно при разработке в функциональном стиле:
+
+{% tabs head-option-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+emptyList.headOption // None
+```
+{% endtab %}
+
+{% endtabs %}
+
+`headOption` не генерирует исключение, а возвращает тип `Option` со значением `None`.
+Более подробно о функциональном стиле программирования будет рассказано [в соответствующей главе][fp-intro].
+
+
+## `tail`
+
+Метод `tail` также взят из Lisp и используется для вывода всех элементов в списке после `head`.
+
+{% tabs tail-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+oneToTen.head // 1
+oneToTen.tail // List(2, 3, 4, 5, 6, 7, 8, 9, 10)
+
+names.head // adam
+names.tail // List(brandy, chris, david)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Так же, как и `head`, `tail` можно использовать со строками:
+
+{% tabs string-tail-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+"foo".tail // "oo"
+"bar".tail // "ar"
+```
+{% endtab %}
+
+{% endtabs %}
+
+`tail` выбрасывает исключение _java.lang.UnsupportedOperationException_, если список пуст,
+поэтому, как и в случае с `head` и `headOption`, существует также метод `tailOption`,
+который предпочтительнее в функциональном программировании.
+
+Список матчится, поэтому можно использовать такие выражения:
+
+{% tabs tail-match-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val x :: xs = names
+```
+{% endtab %}
+
+{% endtabs %}
+
+Помещение этого кода в REPL показывает, что `x` назначается заглавному элементу списка, а `xs` назначается "хвосту":
+
+{% tabs tail-match-example-repl %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+scala> val x :: xs = names
+val x: String = adam
+val xs: List[String] = List(brandy, chris, david)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Подобное сопоставление с образцом полезно во многих случаях, например, при написании метода `sum` с использованием рекурсии:
+
+{% tabs tail-match-sum-example class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+def sum(list: List[Int]): Int = list match {
+ case Nil => 0
+ case x :: xs => x + sum(xs)
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+def sum(list: List[Int]): Int = list match
+ case Nil => 0
+ case x :: xs => x + sum(xs)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+
+## `take`, `takeRight`, `takeWhile`
+
+Методы `take`, `takeRight` и `takeWhile` предоставляют удобный способ “брать” (_taking_) элементы из списка для создания нового.
+Примеры `take` и `takeRight`:
+
+{% tabs take-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+oneToTen.take(1) // List(1)
+oneToTen.take(2) // List(1, 2)
+
+oneToTen.takeRight(1) // List(10)
+oneToTen.takeRight(2) // List(9, 10)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Обратите внимание, как эти методы работают с «пограничными» случаями,
+когда запрашивается больше элементов, чем есть в последовательности,
+или запрашивается ноль элементов:
+
+{% tabs take-edge-cases-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+oneToTen.take(Int.MaxValue) // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+oneToTen.takeRight(Int.MaxValue) // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+oneToTen.take(0) // List()
+oneToTen.takeRight(0) // List()
+```
+{% endtab %}
+
+{% endtabs %}
+
+А это `takeWhile`, который работает с функцией-предикатом:
+
+{% tabs take-while-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+oneToTen.takeWhile(_ < 5) // List(1, 2, 3, 4)
+names.takeWhile(_.length < 5) // List(adam)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+## `drop`, `dropRight`, `dropWhile`
+
+`drop`, `dropRight` и `dropWhile` удаляют элементы из списка
+и, по сути, противоположны своим аналогам “take”.
+Вот некоторые примеры:
+
+{% tabs drop-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+oneToTen.drop(1) // List(2, 3, 4, 5, 6, 7, 8, 9, 10)
+oneToTen.drop(5) // List(6, 7, 8, 9, 10)
+
+oneToTen.dropRight(8) // List(1, 2)
+oneToTen.dropRight(7) // List(1, 2, 3)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Пограничные случаи:
+
+{% tabs drop-edge-cases-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+oneToTen.drop(Int.MaxValue) // List()
+oneToTen.dropRight(Int.MaxValue) // List()
+oneToTen.drop(0) // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+oneToTen.dropRight(0) // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+```
+{% endtab %}
+
+{% endtabs %}
+
+А это `dropWhile`, который работает с функцией-предикатом:
+
+{% tabs drop-while-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+oneToTen.dropWhile(_ < 5) // List(5, 6, 7, 8, 9, 10)
+names.dropWhile(_ != "chris") // List(chris, david)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+## `reduce`
+
+Метод `reduce` позволяет свертывать коллекцию до одного агрегируемого значения.
+Он принимает функцию (или анонимную функцию) и последовательно применяет эту функцию к элементам в списке.
+
+Лучший способ объяснить `reduce` — создать небольшой вспомогательный метод.
+Например, метод `add`, который складывает вместе два целых числа,
+а также предоставляет хороший вывод отладочной информации:
+
+{% tabs reduce-example class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+def add(x: Int, y: Int): Int = {
+ val theSum = x + y
+ println(s"received $x and $y, their sum is $theSum")
+ theSum
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+def add(x: Int, y: Int): Int =
+ val theSum = x + y
+ println(s"received $x and $y, their sum is $theSum")
+ theSum
+```
+{% endtab %}
+
+{% endtabs %}
+
+Рассмотрим список:
+
+{% tabs reduce-example-init %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val a = List(1,2,3,4)
+```
+{% endtab %}
+
+{% endtabs %}
+
+вот что происходит, когда в `reduce` передается метод `add`:
+
+{% tabs reduce-example-evaluation %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+scala> a.reduce(add)
+received 1 and 2, their sum is 3
+received 3 and 3, their sum is 6
+received 6 and 4, their sum is 10
+res0: Int = 10
+```
+{% endtab %}
+
+{% endtabs %}
+
+Как видно из результата, функция `reduce` использует `add` для сокращения списка `a` до единственного значения,
+в данном случае — суммы всех чисел в списке.
+
+`reduce` можно использовать с анонимными функциями:
+
+{% tabs reduce-example-sum %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+scala> a.reduce(_ + _)
+res0: Int = 10
+```
+{% endtab %}
+
+{% endtabs %}
+
+Аналогично можно использовать другие функции, например, умножение:
+
+{% tabs reduce-example-multiply %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+scala> a.reduce(_ * _)
+res1: Int = 24
+```
+{% endtab %}
+
+{% endtabs %}
+
+> Важная концепция, которую следует знать о `reduce`, заключается в том, что, как следует из ее названия
+> (_reduce_ - сокращать), она используется для сокращения коллекции до одного значения.
+
+
+## Дальнейшее изучение коллекций
+
+В коллекциях Scala есть десятки дополнительных методов, которые избавляют от необходимости писать еще один цикл `for`.
+Более подробную информацию о коллекциях Scala см.
+в разделе [Изменяемые и неизменяемые коллекции][mut-immut-colls]
+и [Архитектура коллекций Scala][architecture].
+
+> В качестве последнего примечания, при использовании Java-кода в проекте Scala,
+> коллекции Java можно преобразовать в коллекции Scala.
+> После этого, их можно использовать в выражениях `for`,
+> а также воспользоваться преимуществами методов функциональных коллекций Scala.
+> Более подробную информацию можно найти в разделе [Взаимодействие с Java][interacting].
+
+
+[interacting]: {% link _overviews/scala3-book/interacting-with-java.md %}
+[lambdas]: {% link _overviews/scala3-book/fun-anonymous-functions.md %}
+[fp-intro]: {% link _overviews/scala3-book/fp-intro.md %}
+[mut-immut-colls]: {% link _overviews/collections-2.13/overview.md %}
+[architecture]: {% link _overviews/core/architecture-of-scala-213-collections.md %}
+
diff --git a/_ru/scala3/book/collections-summary.md b/_ru/scala3/book/collections-summary.md
new file mode 100644
index 0000000000..7d89b4961c
--- /dev/null
+++ b/_ru/scala3/book/collections-summary.md
@@ -0,0 +1,35 @@
+---
+layout: multipage-overview
+title: Обзор
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице представлен краткий итог главы «Коллекции».
+language: ru
+num: 40
+previous-page: collections-methods
+next-page: fp-intro
+---
+
+В этой главе представлен обзор общих коллекций Scala 3 и сопутствующих им методов.
+Как было показано, Scala поставляется с множеством коллекций и методов.
+
+Если вам нужно увидеть более подробную информацию о типах коллекций,
+показанных в этой главе, см. их Scaladoc страницы:
+
+- [List](https://www.scala-lang.org/api/current/scala/collection/immutable/List.html)
+- [Vector](https://www.scala-lang.org/api/current/scala/collection/immutable/Vector.html)
+- [ArrayBuffer](https://www.scala-lang.org/api/current/scala/collection/mutable/ArrayBuffer.html)
+- [Range](https://www.scala-lang.org/api/current/scala/collection/immutable/Range.html)
+
+Также упоминавшиеся неизменяемые `Map` и `Set`:
+
+- [Map](https://www.scala-lang.org/api/current/scala/collection/immutable/Map.html)
+- [Set](https://www.scala-lang.org/api/current/scala/collection/immutable/Set.html)
+
+и изменяемые `Map` и `Set`:
+
+- [Map](https://www.scala-lang.org/api/current/scala/collection/mutable/Map.html)
+- [Set](https://www.scala-lang.org/api/current/scala/collection/mutable/Set.html)
+
diff --git a/_ru/scala3/book/concurrency.md b/_ru/scala3/book/concurrency.md
new file mode 100644
index 0000000000..ec43810bfa
--- /dev/null
+++ b/_ru/scala3/book/concurrency.md
@@ -0,0 +1,333 @@
+---
+layout: multipage-overview
+title: Параллелизм
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: На этой странице обсуждается, как работает параллелизм в Scala, с упором на Scala Futures.
+language: ru
+num: 68
+previous-page: ca-summary
+next-page: scala-tools
+---
+
+Для написания параллельных приложений на Scala, _можно_ использовать нативный Java `Thread`,
+но Scala [Future](https://www.scala-lang.org/api/current/scala/concurrent/Future$.html) предлагает более высокоуровневый
+и идиоматический подход, поэтому он предпочтителен и рассматривается в этой главе.
+
+## Введение
+
+Вот описание Scala `Future` из его Scaladoc:
+
+> "`Future` представляет собой значение, которое может быть или не быть доступным _в настоящее время_,
+> но будет доступно в какой-то момент, или вызовет исключение, если это значение не может быть сделано доступным".
+
+Чтобы продемонстрировать, что это значит, сначала рассмотрим однопоточное программирование.
+В однопоточном мире результат вызова метода привязывается к переменной следующим образом:
+
+```scala
+def aShortRunningTask(): Int = 42
+val x = aShortRunningTask()
+```
+
+В этом коде значение `42` сразу привязывается к `x`.
+
+При работе с `Future` процесс назначения выглядит примерно так:
+
+```scala
+def aLongRunningTask(): Future[Int] = ???
+val x = aLongRunningTask()
+```
+
+Но главное отличие в этом случае заключается в том, что, поскольку `aLongRunningTask` возвращает неопределенное время,
+значение `x` может быть доступно или недоступно _в данный момент_, но оно будет доступно в какой-то момент — в будущем.
+
+Другой способ взглянуть на это с точки зрения блокировки.
+В этом однопоточном примере оператор `println` не печатается до тех пор, пока не завершится выполнение `aShortRunningTask`:
+
+```scala
+def aShortRunningTask(): Int =
+ Thread.sleep(500)
+ 42
+val x = aShortRunningTask()
+println("Here")
+```
+
+И наоборот, если `aShortRunningTask` создается как `Future`, оператор `println` печатается почти сразу,
+потому что `aShortRunningTask` порождается в другом потоке — он не блокируется.
+
+В этой главе будет рассказано, как использовать `Future`,
+в том числе как запускать несколько `Future` параллельно и объединять их результаты в выражении `for`.
+Также будут показаны примеры методов, которые используются для обработки значения `Future` после его возврата.
+
+> О `Future`, важно знать, что они задуманы как одноразовая конструкция
+> "Обработайте это относительно медленное вычисление в каком-нибудь другом потоке и верните мне результат, когда закончите".
+> В отличие от этого, акторы [Akka](https://akka.io) предназначены для работы в течение длительного времени
+> и отвечают на множество запросов в течение своей жизни.
+> В то время как субъект может жить вечно, `Future` в конечном итоге содержит результат вычисления,
+> которое выполнялось только один раз.
+
+## Пример в REPL
+
+`Future` используется для создания временного кармана параллелизма.
+Например, можно использовать `Future`, когда нужно вызвать алгоритм,
+который выполняется неопределенное количество времени — например, вызов удаленного микросервиса, —
+поэтому его желательно запустить вне основного потока.
+
+Чтобы продемонстрировать, как это работает, начнем с примера `Future` в REPL.
+Во-первых, вставим необходимые инструкции импорта:
+
+```scala
+import scala.concurrent.Future
+import scala.concurrent.ExecutionContext.Implicits.global
+import scala.util.{Failure, Success}
+```
+
+Теперь можно создать `Future`.
+Для этого примера сначала определим долговременный однопоточный алгоритм:
+
+```scala
+def longRunningAlgorithm() =
+ Thread.sleep(10_000)
+ 42
+```
+
+Этот причудливый алгоритм возвращает целочисленное значение `42` после десятисекундной задержки.
+Теперь вызовем этот алгоритм, поместив его в конструктор `Future` и присвоив результат переменной:
+
+```scala
+scala> val eventualInt = Future(longRunningAlgorithm())
+eventualInt: scala.concurrent.Future[Int] = Future()
+```
+
+Вычисления начинают выполняться после вызова `longRunningAlgorithm()`.
+Если сразу проверить значение переменной `eventualInt`, то можно увидеть, что `Future` еще не завершен:
+
+```scala
+scala> eventualInt
+val res1: scala.concurrent.Future[Int] = Future()
+```
+
+Но если проверить через десять секунд ещё раз, то можно увидеть, что оно выполнено успешно:
+
+```scala
+scala> eventualInt
+val res2: scala.concurrent.Future[Int] = Future(Success(42))
+```
+
+Хотя это относительно простой пример, он демонстрирует основной подход:
+просто создайте новое `Future` с помощью своего долговременного алгоритма.
+
+Одна вещь, на которую следует обратить внимание -
+это то, что ожидаемый результат `42` обернут в `Success`, который обернут в `Future`.
+Это ключевая концепция для понимания: значение `Future` всегда является экземпляром одного из `scala.util.Try`: `Success` или `Failure`.
+Поэтому, при работе с результатом `Future`, используются обычные методы обработки `Try`.
+
+### Использование `map` с `Future`
+
+`Future` содержит метод `map`, который используется точно так же, как метод `map` для коллекций.
+Вот как выглядит результат, при вызове `map` сразу после создания переменной `a`:
+
+```scala
+scala> val a = Future(longRunningAlgorithm()).map(_ * 2)
+a: scala.concurrent.Future[Int] = Future()
+```
+
+Как показано, для `Future`, созданного с помощью `longRunningAlgorithm`, первоначальный вывод показывает `Future()`.
+Но если проверить значение `a` через десять секунд, то можно увидеть, что оно содержит ожидаемый результат `84`:
+
+```scala
+scala> a
+res1: scala.concurrent.Future[Int] = Future(Success(84))
+```
+
+Еще раз, успешный результат обернут внутри `Success` и `Future`.
+
+### Использование методов обратного вызова с `Future`
+
+В дополнение к функциям высшего порядка, таким как `map`, с `Future` также можно использовать методы обратного вызова.
+Одним из часто используемых методов обратного вызова является `onComplete`, принимающий _частично определенную функцию_,
+в которой обрабатываются случаи `Success` и `Failure`:
+
+```scala
+Future(longRunningAlgorithm()).onComplete {
+ case Success(value) => println(s"Got the callback, value = $value")
+ case Failure(e) => e.printStackTrace
+}
+```
+
+Если вставить этот код в REPL, то в конечном итоге придет результат:
+
+```scala
+Got the callback, value = 42
+```
+
+## Другие методы `Future`
+
+Класс `Future` содержит некоторые методы, которые можно найти в классах коллекций Scala, в том числе:
+
+- `filter`
+- `flatMap`
+- `map`
+
+Методы обратного вызова:
+
+- `onComplete`
+- `andThen`
+- `foreach`
+
+Другие методы трансформации:
+
+- `fallbackTo`
+- `recover`
+- `recoverWith`
+
+См. страницу [Futures and Promises][futures] для обсуждения дополнительных методов, доступных для `Future`.
+
+## Запуск нескольких `Future` и объединение результатов
+
+Чтобы запустить несколько вычислений параллельно и соединить их результаты после завершения всех `Future`,
+можно использовать выражение `for`.
+
+Правильный подход такой:
+
+1. Запустить вычисления, которые возвращают `Future` результаты
+2. Объединить их результаты в выражении `for`
+3. Извлечь объединенный результат, используя `onComplete` или аналогичный метод
+
+### Пример
+
+Три шага правильного подхода показаны в следующем примере.
+Ключевой момент - сначала запускаются вычисления, возвращающие `Future`, а затем они объединяются в выражении `for`:
+
+```scala
+import scala.concurrent.Future
+import scala.concurrent.ExecutionContext.Implicits.global
+import scala.util.{Failure, Success}
+
+val startTime = System.currentTimeMillis()
+def delta() = System.currentTimeMillis() - startTime
+def sleep(millis: Long) = Thread.sleep(millis)
+
+@main def multipleFutures1 =
+
+ println(s"creating the futures: ${delta()}")
+
+ // (1) запуск вычислений, возвращающих Future
+ val f1 = Future { sleep(800); 1 } // в конце концов возвращается 1
+ val f2 = Future { sleep(200); 2 } // в конце концов возвращается 2
+ val f3 = Future { sleep(400); 3 } // в конце концов возвращается 3
+
+ // (2) объединение нескольких Future в выражении `for`
+ val result =
+ for
+ r1 <- f1
+ r2 <- f2
+ r3 <- f3
+ yield
+ println(s"in the 'yield': ${delta()}")
+ (r1 + r2 + r3)
+
+ // (3) обработка результата
+ result.onComplete {
+ case Success(x) =>
+ println(s"in the Success case: ${delta()}")
+ println(s"result = $x")
+ case Failure(e) =>
+ e.printStackTrace
+ }
+
+ println(s"before the 'sleep(3000)': ${delta()}")
+
+ // важно для небольшой параллельной демонстрации: не глушить jvm
+ sleep(3000)
+```
+
+После запуска этого приложения, вывод выглядит следующим образом:
+
+```
+creating the futures: 1
+before the 'sleep(3000)': 2
+in the 'yield': 806
+in the Success case: 806
+result = 6
+```
+
+Как показывает вывод, `Future` создаются очень быстро,
+и всего за две миллисекунды достигается оператор печати непосредственно перед операцией `sleep(3000)` в конце метода.
+Весь этот код выполняется в основном потоке JVM. Затем, через 806 мс, три `Future` завершаются, и выполняется код в блоке `yield`.
+Затем код немедленно переходит к варианту `Success` в методе `onComplete`.
+
+Вывод 806 мс является ключом к тому, чтобы убедиться, что три вычисления выполняются параллельно.
+Если бы они выполнялись последовательно, общее время составило бы около 1400 мс — сумма времени ожидания трех вычислений.
+Но поскольку они выполняются параллельно, общее время чуть больше, чем у самого продолжительного вычисления `f1`,
+которое составляет 800 мс.
+
+> Обратите внимание, что если бы вычисления выполнялись в выражении `for`,
+> они выполнялись бы последовательно, а не параллельно:
+>
+> ```
+> // последовательное выполнение (без параллелизма!)
+> for
+> r1 <- Future { sleep(800); 1 }
+> r2 <- Future { sleep(200); 2 }
+> r3 <- Future { sleep(400); 3 }
+> yield
+> r1 + r2 + r3
+> ```
+>
+> Итак, если необходимо, чтобы вычисления выполнялись параллельно, не забудьте запустить их вне выражения `for`.
+
+### Метод, возвращающий Future
+
+Было показано, как передавать однопоточный алгоритм в конструктор `Future`.
+Ту же технику можно использовать для создания метода, который возвращает `Future`:
+
+```scala
+// моделируем медленно работающий метод
+def slowlyDouble(x: Int, delay: Long): Future[Int] = Future {
+ sleep(delay)
+ x * 2
+}
+```
+
+Как и в предыдущих примерах, достаточно просто присвоить результат вызова метода новой переменной.
+Тогда, если сразу проверить результат, то можно увидеть, что он не завершен,
+но по истечении времени задержки в `Future` результат будет выдан:
+
+```
+scala> val f = slowlyDouble(2, 5_000L)
+val f: concurrent.Future[Int] = Future()
+
+scala> f
+val res0: concurrent.Future[Int] = Future()
+
+scala> f
+val res1: concurrent.Future[Int] = Future(Success(4))
+```
+
+## Ключевые моменты о Future
+
+Надеюсь, эти примеры дадут вам представление о том, как работает Scala `Future`.
+Подводя итог, несколько ключевых моментов о `Future`:
+
+- `Future` создается для запуска задач вне основного потока
+- `Future` предназначены для одноразовых, потенциально длительных параллельных задач, которые _в конечном итоге_ возвращают значение;
+ они создают временный карман параллелизма
+- `Future` начинает работать в момент построения
+- преимущество `Future` над потоками заключается в том, что они работают с выражениями `for`
+ и имеют множество методов обратного вызова, упрощающих процесс работы с параллельными потоками
+- при работе с `Future` не нужно беспокоиться о низкоуровневых деталях управления потоками
+- результат `Future` обрабатывается с помощью методов обратного вызова, таких как `onComplete` и `andThen`,
+ или методов преобразования, таких как `filter`, `map` и т.д.
+- значение внутри `Future` всегда является экземпляром одного из типов `Try`: `Success` или `Failure`
+- при использовании нескольких `Future` для получения одного результата, они объединяются в выражении `for`
+
+Кроме того, как было видно по операторам `import`, Scala `Future` зависит от `ExecutionContext`.
+
+Дополнительные сведения о `Future` см. в статье [Futures and Promises][futures],
+в которой обсуждаются futures, promises и execution contexts.
+В ней также обсуждается, как выражение `for` транслируется в операцию `flatMap`.
+
+[futures]: {% link _overviews/core/futures.md %}
diff --git a/_ru/scala3/book/control-structures.md b/_ru/scala3/book/control-structures.md
new file mode 100644
index 0000000000..41b5e0646f
--- /dev/null
+++ b/_ru/scala3/book/control-structures.md
@@ -0,0 +1,1016 @@
+---
+layout: multipage-overview
+title: Структуры управления
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: На этой странице представлено введение в структуры управления Scala, включая if/then/else, циклы for, выражения for, выражения match, try/catch/finally и циклы while.
+language: ru
+num: 19
+previous-page: string-interpolation
+next-page: domain-modeling-intro
+---
+
+
+В Scala есть все структуры управления, которые вы ожидаете найти в языке программирования, в том числе:
+
+- `if`/`then`/`else`
+- циклы `for`
+- циклы `while`
+- `try`/`catch`/`finally`
+
+Здесь также есть две другие мощные конструкции, которые вы, возможно, не видели раньше,
+в зависимости от вашего опыта программирования:
+
+- `for` выражения (также известные как _`for` comprehensions_)
+- `match` выражения
+
+Все они продемонстрированы в следующих разделах.
+
+
+## Конструкция if/then/else
+
+Однострочный Scala оператор `if` выглядит так:
+
+{% tabs control-structures-1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-1 %}
+```scala
+if (x == 1) println(x)
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-1 %}
+```scala
+if x == 1 then println(x)
+```
+{% endtab %}
+{% endtabs %}
+
+Когда необходимо выполнить несколько строк кода после `if`, используется синтаксис:
+
+{% tabs control-structures-2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-2 %}
+```scala
+if (x == 1) {
+ println("x is 1, as you can see:")
+ println(x)
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-2 %}
+```scala
+if x == 1 then
+ println("x is 1, as you can see:")
+ println(x)
+```
+{% endtab %}
+{% endtabs %}
+
+`if`/`else` синтаксис выглядит так:
+
+{% tabs control-structures-3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-3 %}
+```scala
+if (x == 1) {
+ println("x is 1, as you can see:")
+ println(x)
+} else {
+ println("x was not 1")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-3 %}
+```scala
+if x == 1 then
+ println("x is 1, as you can see:")
+ println(x)
+else
+ println("x was not 1")
+```
+{% endtab %}
+{% endtabs %}
+
+А это синтаксис `if`/`else if`/`else`:
+
+{% tabs control-structures-4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-4 %}
+```scala
+if (x < 0)
+ println("negative")
+else if (x == 0)
+ println("zero")
+else
+ println("positive")
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-4 %}
+```scala
+if x < 0 then
+ println("negative")
+else if x == 0 then
+ println("zero")
+else
+ println("positive")
+```
+{% endtab %}
+{% endtabs %}
+
+### Утверждение `end if`
+
+
+ Это новое в Scala 3 и не поддерживается в Scala 2.
+
+
+При желании можно дополнительно включить оператор `end if` в конце каждого выражения:
+```scala
+if x == 1 then
+ println("x is 1, as you can see:")
+ println(x)
+end if
+```
+
+### `if`/`else` выражения всегда возвращают результат
+
+Сравнения `if`/`else` образуют _выражения_ - это означает, что они возвращают значение, которое можно присвоить переменной.
+Поэтому нет необходимости в специальном тернарном операторе:
+
+{% tabs control-structures-6 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-6 %}
+```scala
+val minValue = if (a < b) a else b
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-6 %}
+```scala
+val minValue = if a < b then a else b
+```
+{% endtab %}
+{% endtabs %}
+
+
+Поскольку эти выражения возвращают значение, то выражения `if`/`else` можно использовать в качестве тела метода:
+
+{% tabs control-structures-7 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-7 %}
+```scala
+def compare(a: Int, b: Int): Int =
+ if (a < b)
+ -1
+ else if (a == b)
+ 0
+ else
+ 1
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-7 %}
+```scala
+def compare(a: Int, b: Int): Int =
+ if a < b then
+ -1
+ else if a == b then
+ 0
+ else
+ 1
+```
+{% endtab %}
+{% endtabs %}
+
+### В сторону: программирование, ориентированное на выражения
+
+Кратко о программировании в целом: когда каждое написанное вами выражение возвращает значение,
+такой стиль называется _программированием, ориентированным на выражения_,
+или EOP (_expression-oriented programming_).
+Например, это _выражение_:
+
+{% tabs control-structures-8 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-8 %}
+```scala
+val minValue = if (a < b) a else b
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-8 %}
+```scala
+val minValue = if a < b then a else b
+```
+{% endtab %}
+{% endtabs %}
+
+И наоборот, строки кода, которые не возвращают значения, называются _операторами_
+и используются для получения _побочных эффектов_.
+Например, эти строки кода не возвращают значения, поэтому они используются для побочных эффектов:
+
+{% tabs control-structures-9 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-9 %}
+```scala
+if (a == b) action()
+println("Hello")
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-9 %}
+```scala
+if a == b then action()
+println("Hello")
+```
+{% endtab %}
+{% endtabs %}
+
+В первом примере метод `action` запускается как побочный эффект, когда `a` равно `b`.
+Второй пример используется для побочного эффекта печати строки в STDOUT.
+Когда вы узнаете больше о Scala, то обнаружите, что пишете больше _выражений_ и меньше _операторов_.
+
+## Циклы `for`
+
+В самом простом случае цикл `for` в Scala можно использовать для перебора элементов в коллекции.
+Например, имея последовательность целых чисел,
+вы можете перебрать ее элементы и вывести их значения следующим образом:
+
+{% tabs control-structures-10 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-10 %}
+```scala
+val ints = Seq(1, 2, 3)
+for (i <- ints) println(i)
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-10 %}
+```scala
+val ints = Seq(1, 2, 3)
+for i <- ints do println(i)
+```
+{% endtab %}
+{% endtabs %}
+
+
+Код `i <- ints` называется _генератором_.
+
+Вот как выглядит результат в Scala REPL:
+
+{% tabs control-structures-11 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-11 %}
+````
+scala> val ints = Seq(1,2,3)
+ints: Seq[Int] = List(1, 2, 3)
+
+scala> for (i <- ints) println(i)
+1
+2
+3
+````
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-11 %}
+````
+scala> val ints = Seq(1,2,3)
+ints: Seq[Int] = List(1, 2, 3)
+
+scala> for i <- ints do println(i)
+1
+2
+3
+````
+{% endtab %}
+{% endtabs %}
+
+
+Если вам нужен многострочный блок кода после генератора `for`, используйте следующий синтаксис:
+
+{% tabs control-structures-12 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-12 %}
+```scala
+for (i <- ints) {
+ val x = i * 2
+ println(s"i = $i, x = $x")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-12 %}
+```scala
+for i <- ints
+do
+ val x = i * 2
+ println(s"i = $i, x = $x")
+```
+{% endtab %}
+{% endtabs %}
+
+
+### Несколько генераторов
+
+Циклы `for` могут иметь несколько генераторов, как показано в этом примере:
+
+{% tabs control-structures-13 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-13 %}
+```scala
+for {
+ i <- 1 to 2
+ j <- 'a' to 'b'
+ k <- 1 to 10 by 5
+} {
+ println(s"i = $i, j = $j, k = $k")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-13 %}
+```scala
+for
+ i <- 1 to 2
+ j <- 'a' to 'b'
+ k <- 1 to 10 by 5
+do
+ println(s"i = $i, j = $j, k = $k")
+```
+{% endtab %}
+{% endtabs %}
+
+
+Это выражение выводит следующее:
+
+````
+i = 1, j = a, k = 1
+i = 1, j = a, k = 6
+i = 1, j = b, k = 1
+i = 1, j = b, k = 6
+i = 2, j = a, k = 1
+i = 2, j = a, k = 6
+i = 2, j = b, k = 1
+i = 2, j = b, k = 6
+````
+
+### "Ограничители"
+
+Циклы `for` также могут содержать операторы `if`, известные как _ограничители_ (_guards_):
+
+{% tabs control-structures-14 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-14 %}
+```scala
+for {
+ i <- 1 to 5
+ if i % 2 == 0
+} {
+ println(i)
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-14 %}
+```scala
+for
+ i <- 1 to 5
+ if i % 2 == 0
+do
+ println(i)
+```
+{% endtab %}
+{% endtabs %}
+
+
+Результат этого цикла:
+
+````
+2
+4
+````
+
+Цикл `for` может содержать столько стражников, сколько необходимо.
+В этом примере показан один из способов печати числа `4`:
+
+{% tabs control-structures-15 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-15 %}
+```scala
+for {
+ i <- 1 to 10
+ if i > 3
+ if i < 6
+ if i % 2 == 0
+} {
+ println(i)
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-15 %}
+```scala
+for
+ i <- 1 to 10
+ if i > 3
+ if i < 6
+ if i % 2 == 0
+do
+ println(i)
+```
+{% endtab %}
+{% endtabs %}
+
+### Использование `for` с Maps
+
+Вы также можете использовать циклы `for` с `Map`.
+Например, если задана такая `Map` с аббревиатурами штатов и их полными названиями:
+
+{% tabs map %}
+{% tab 'Scala 2 и 3' for=map %}
+```scala
+val states = Map(
+ "AK" -> "Alaska",
+ "AL" -> "Alabama",
+ "AR" -> "Arizona"
+)
+```
+{% endtab %}
+{% endtabs %}
+
+, то можно распечатать ключи и значения, используя `for`. Например:
+
+{% tabs control-structures-16 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-16 %}
+```scala
+for ((abbrev, fullName) <- states) println(s"$abbrev: $fullName")
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-16 %}
+```scala
+for (abbrev, fullName) <- states do println(s"$abbrev: $fullName")
+```
+{% endtab %}
+{% endtabs %}
+
+Вот как это выглядит в REPL:
+
+{% tabs control-structures-17 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-17 %}
+```scala
+scala> for ((abbrev, fullName) <- states) println(s"$abbrev: $fullName")
+AK: Alaska
+AL: Alabama
+AR: Arizona
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-17 %}
+```scala
+scala> for (abbrev, fullName) <- states do println(s"$abbrev: $fullName")
+AK: Alaska
+AL: Alabama
+AR: Arizona
+```
+{% endtab %}
+{% endtabs %}
+
+Когда цикл `for` перебирает мапу, каждая пара ключ/значение привязывается
+к переменным `abbrev` и `fullName`, которые находятся в кортеже:
+
+```scala
+(abbrev, fullName) <- states
+```
+
+По мере выполнения цикла переменная `abbrev` принимает значение текущего _ключа_ в мапе,
+а переменная `fullName` - соответствующему ключу _значению_.
+
+## Выражение `for`
+
+В предыдущих примерах циклов `for` все эти циклы использовались для _побочных эффектов_,
+в частности для вывода этих значений в STDOUT с помощью `println`.
+
+Важно знать, что вы также можете создавать _выражения_ `for`, которые возвращают значения.
+Вы создаете выражение `for`, добавляя ключевое слово `yield` и возвращаемое выражение, например:
+
+{% tabs control-structures-18 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-18 %}
+```scala
+val list =
+ for (i <- 10 to 12)
+ yield i * 2
+
+// list: IndexedSeq[Int] = Vector(20, 22, 24)
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-18 %}
+```scala
+val list =
+ for i <- 10 to 12
+ yield i * 2
+
+// list: IndexedSeq[Int] = Vector(20, 22, 24)
+```
+{% endtab %}
+{% endtabs %}
+
+
+После выполнения этого выражения `for` переменная `list` содержит `Vector` с отображаемыми значениями.
+Вот как работает выражение:
+
+1. Выражение `for` начинает перебирать значения в диапазоне `(10, 11, 12)`.
+ Сначала оно работает со значением `10`, умножает его на `2`, затем выдает результат - `20`.
+2. Далее берет `11` — второе значение в диапазоне. Умножает его на `2`, а затем выдает значение `22`.
+ Можно представить эти полученные значения как накопление во временном хранилище.
+3. Наконец, цикл берет число `12` из диапазона, умножает его на `2`, получая число `24`.
+ Цикл завершается в этой точке и выдает конечный результат - `Vector(20, 22, 24)`.
+
+Хотя целью этого раздела является демонстрация выражений `for`, полезно знать,
+что показанное выражение `for` эквивалентно вызову метода `map`:
+
+{% tabs map-call %}
+{% tab 'Scala 2 и 3' for=map-call %}
+```scala
+val list = (10 to 12).map(i => i * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+Выражения `for` можно использовать в любой момент, когда вам нужно просмотреть все элементы в коллекции
+и применить алгоритм к этим элементам для создания нового списка.
+
+Вот пример, который показывает, как использовать блок кода после `yield`:
+
+{% tabs control-structures-19 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-19 %}
+```scala
+val names = List("_olivia", "_walter", "_peter")
+
+val capNames = for (name <- names) yield {
+ val nameWithoutUnderscore = name.drop(1)
+ val capName = nameWithoutUnderscore.capitalize
+ capName
+}
+
+// capNames: List[String] = List(Olivia, Walter, Peter)
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-19 %}
+```scala
+val names = List("_olivia", "_walter", "_peter")
+
+val capNames = for name <- names yield
+ val nameWithoutUnderscore = name.drop(1)
+ val capName = nameWithoutUnderscore.capitalize
+ capName
+
+// capNames: List[String] = List(Olivia, Walter, Peter)
+```
+{% endtab %}
+{% endtabs %}
+
+### Использование выражения `for` в качестве тела метода
+
+
+Поскольку выражение `for` возвращает результат, его можно использовать в качестве тела метода,
+который возвращает полезное значение.
+Этот метод возвращает все значения в заданном списке целых чисел, которые находятся между `3` и `10`:
+
+{% tabs control-structures-20 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-20 %}
+```scala
+def between3and10(xs: List[Int]): List[Int] =
+ for {
+ x <- xs
+ if x >= 3
+ if x <= 10
+ } yield x
+
+between3and10(List(1, 3, 7, 11)) // : List[Int] = List(3, 7)
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-20 %}
+```scala
+def between3and10(xs: List[Int]): List[Int] =
+ for
+ x <- xs
+ if x >= 3
+ if x <= 10
+ yield x
+
+between3and10(List(1, 3, 7, 11)) // : List[Int] = List(3, 7)
+```
+{% endtab %}
+{% endtabs %}
+
+## Циклы `while`
+
+Синтаксис цикла `while` в Scala выглядит следующим образом:
+
+{% tabs control-structures-21 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-21 %}
+```scala
+var i = 0
+
+while (i < 3) {
+ println(i)
+ i += 1
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-21 %}
+```scala
+var i = 0
+
+while i < 3 do
+ println(i)
+ i += 1
+```
+{% endtab %}
+{% endtabs %}
+
+## `match` выражения
+
+Сопоставление с образцом (_pattern matching_) является основой функциональных языков программирования.
+Scala включает в себя pattern matching, обладающий множеством возможностей.
+
+В самом простом случае можно использовать выражение `match`, подобное оператору Java `switch`,
+сопоставляя на основе целочисленного значения.
+Как и предыдущие структуры, сопоставление с образцом - это действительно выражение, поскольку оно вычисляет результат:
+
+{% tabs control-structures-22 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-22 %}
+```scala
+// `i` is an integer
+val day = i match {
+ case 0 => "Sunday"
+ case 1 => "Monday"
+ case 2 => "Tuesday"
+ case 3 => "Wednesday"
+ case 4 => "Thursday"
+ case 5 => "Friday"
+ case 6 => "Saturday"
+ case _ => "invalid day" // по умолчанию, перехватывает остальное
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-22 %}
+```scala
+// `i` is an integer
+val day = i match
+ case 0 => "Sunday"
+ case 1 => "Monday"
+ case 2 => "Tuesday"
+ case 3 => "Wednesday"
+ case 4 => "Thursday"
+ case 5 => "Friday"
+ case 6 => "Saturday"
+ case _ => "invalid day" // по умолчанию, перехватывает остальное
+```
+{% endtab %}
+{% endtabs %}
+
+
+В этом примере переменная `i` сопоставляется с заданными числами.
+Если она находится между `0` и `6`, `day` принимает значение строки, представляющей день недели.
+В противном случае она соответствует подстановочному знаку, представленному символом `_`,
+и `day` принимает значение строки `"invalid day"`.
+
+Поскольку сопоставляемые значения рассматриваются в том порядке, в котором они заданы,
+и используется первое совпадение,
+случай по умолчанию, соответствующий любому значению, должен идти последним.
+Любые сопоставляемые случаи после значения по умолчанию будут помечены как недоступные и будет выведено предупреждение.
+
+> При написании простых выражений соответствия, подобных этому, рекомендуется использовать аннотацию `@switch` для переменной `i`.
+> Эта аннотация содержит предупреждение во время компиляции, если switch не может быть скомпилирован в `tableswitch`
+> или `lookupswitch`, которые лучше подходят с точки зрения производительности.
+
+
+### Использование значения по умолчанию
+
+Когда необходимо получить доступ к универсальному значению по умолчанию в `match` выражении,
+просто укажите вместо `_` имя переменной в левой части оператора `case`,
+а затем используйте это имя переменной в правой части оператора при необходимости:
+
+{% tabs control-structures-23 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-23 %}
+```scala
+i match {
+ case 0 => println("1")
+ case 1 => println("2")
+ case what => println(s"You gave me: $what")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-23 %}
+```scala
+i match
+ case 0 => println("1")
+ case 1 => println("2")
+ case what => println(s"You gave me: $what")
+```
+{% endtab %}
+{% endtabs %}
+
+Имя, используемое в шаблоне, должно начинаться со строчной буквы.
+Имя, начинающееся с заглавной буквы, не представляет собой новую переменную,
+но соответствует значению в области видимости:
+
+{% tabs control-structures-24 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-24 %}
+```scala
+val N = 42
+i match {
+ case 0 => println("1")
+ case 1 => println("2")
+ case N => println("42")
+ case n => println(s"You gave me: $n" )
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-24 %}
+```scala
+val N = 42
+i match
+ case 0 => println("1")
+ case 1 => println("2")
+ case N => println("42")
+ case n => println(s"You gave me: $n" )
+```
+{% endtab %}
+{% endtabs %}
+
+Если `i` равно `42`, то оно будет соответствовать `case N` и напечатает строку `"42"`.
+И не достигнет случая по умолчанию.
+
+### Обработка нескольких возможных совпадений в одной строке
+
+Как уже упоминалось, `match` выражения многофункциональны.
+В этом примере показано, как в каждом операторе `case` использовать несколько возможных совпадений:
+
+{% tabs control-structures-25 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-25 %}
+```scala
+val evenOrOdd = i match {
+ case 1 | 3 | 5 | 7 | 9 => println("odd")
+ case 2 | 4 | 6 | 8 | 10 => println("even")
+ case _ => println("some other number")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-25 %}
+```scala
+val evenOrOdd = i match
+ case 1 | 3 | 5 | 7 | 9 => println("odd")
+ case 2 | 4 | 6 | 8 | 10 => println("even")
+ case _ => println("some other number")
+```
+{% endtab %}
+{% endtabs %}
+
+### Использование `if` стражников в `case` предложениях
+
+В case выражениях также можно использовать стражников.
+В этом примере второй и третий case используют стражников для сопоставления нескольких целочисленных значений:
+
+{% tabs control-structures-26 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-26 %}
+```scala
+i match {
+ case 1 => println("one, a lonely number")
+ case x if x == 2 || x == 3 => println("two’s company, three’s a crowd")
+ case x if x > 3 => println("4+, that’s a party")
+ case _ => println("i’m guessing your number is zero or less")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-26 %}
+```scala
+i match
+ case 1 => println("one, a lonely number")
+ case x if x == 2 || x == 3 => println("two’s company, three’s a crowd")
+ case x if x > 3 => println("4+, that’s a party")
+ case _ => println("i’m guessing your number is zero or less")
+```
+{% endtab %}
+{% endtabs %}
+
+
+Вот еще один пример, который показывает, как сопоставить заданное значение с диапазоном чисел:
+
+{% tabs control-structures-27 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-27 %}
+```scala
+i match {
+ case a if 0 to 9 contains a => println(s"0-9 range: $a")
+ case b if 10 to 19 contains b => println(s"10-19 range: $b")
+ case c if 20 to 29 contains c => println(s"20-29 range: $c")
+ case _ => println("Hmmm...")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-27 %}
+```scala
+i match
+ case a if 0 to 9 contains a => println(s"0-9 range: $a")
+ case b if 10 to 19 contains b => println(s"10-19 range: $b")
+ case c if 20 to 29 contains c => println(s"20-29 range: $c")
+ case _ => println("Hmmm...")
+```
+{% endtab %}
+{% endtabs %}
+
+
+#### Case классы и сопоставление с образцом
+
+Вы также можете извлекать поля из `case` классов — и классов, которые имеют корректно написанные методы `apply`/`unapply` —
+и использовать их в своих условиях.
+Вот пример использования простого case класса `Person`:
+
+{% tabs control-structures-28 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-28 %}
+```scala
+case class Person(name: String)
+
+def speak(p: Person) = p match {
+ case Person(name) if name == "Fred" => println(s"$name says, Yubba dubba doo")
+ case Person(name) if name == "Bam Bam" => println(s"$name says, Bam bam!")
+ case _ => println("Watch the Flintstones!")
+}
+
+speak(Person("Fred")) // "Fred says, Yubba dubba doo"
+speak(Person("Bam Bam")) // "Bam Bam says, Bam bam!"
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-28 %}
+```scala
+case class Person(name: String)
+
+def speak(p: Person) = p match
+ case Person(name) if name == "Fred" => println(s"$name says, Yubba dubba doo")
+ case Person(name) if name == "Bam Bam" => println(s"$name says, Bam bam!")
+ case _ => println("Watch the Flintstones!")
+
+speak(Person("Fred")) // "Fred says, Yubba dubba doo"
+speak(Person("Bam Bam")) // "Bam Bam says, Bam bam!"
+```
+{% endtab %}
+{% endtabs %}
+
+### Использование `match` выражения в качестве тела метода
+
+Поскольку `match` выражения возвращают значение, их можно использовать в качестве тела метода.
+Метод `isTruthy` принимает в качестве входного параметра значение `Matchable`
+и возвращает `Boolean` на основе сопоставления с образцом:
+
+{% tabs control-structures-29 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-29 %}
+```scala
+def isTruthy(a: Matchable) = a match {
+ case 0 | "" | false => false
+ case _ => true
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-29 %}
+```scala
+def isTruthy(a: Matchable) = a match
+ case 0 | "" | false => false
+ case _ => true
+```
+{% endtab %}
+{% endtabs %}
+
+Входной параметр `a` имеет [тип `Matchable`][matchable], являющийся основой всех типов Scala,
+для которых может выполняться сопоставление с образцом.
+Метод реализован путем сопоставления на входе в метод, обрабатывая два варианта:
+первый проверяет, является ли заданное значение целым числом `0`, пустой строкой или `false` и в этом случае возвращается `false`.
+Для любого другого значения в случае по умолчанию мы возвращаем `true`.
+Примеры ниже показывают, как работает этот метод:
+
+{% tabs is-truthy-call %}
+{% tab 'Scala 2 и 3' for=is-truthy-call %}
+```scala
+isTruthy(0) // false
+isTruthy(false) // false
+isTruthy("") // false
+isTruthy(1) // true
+isTruthy(" ") // true
+isTruthy(2F) // true
+```
+{% endtab %}
+{% endtabs %}
+
+Использование сопоставления с образцом в качестве тела метода очень распространено.
+
+#### Использование различных шаблонов в сопоставлении с образцом
+
+Для выражения `match` можно использовать множество различных шаблонов.
+Например:
+
+- Сравнение с константой (такое как `case 3 =>`)
+- Сравнение с последовательностями (такое как `case List(els : _*) =>`)
+- Сравнение с кортежами (такое как `case (x, y) =>`)
+- Сравнение с конструктором класса (такое как `case Person(first, last) =>`)
+- Сравнение по типу (такое как `case p: Person =>`)
+
+Все эти виды шаблонов показаны в следующем методе `pattern`,
+который принимает входной параметр типа `Matchable` и возвращает `String`:
+
+{% tabs control-structures-30 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-30 %}
+```scala
+def pattern(x: Matchable): String = x match {
+
+ // сравнение с константой
+ case 0 => "zero"
+ case true => "true"
+ case "hello" => "you said 'hello'"
+ case Nil => "an empty List"
+
+ // сравнение с последовательностями
+ case List(0, _, _) => "a 3-element list with 0 as the first element"
+ case List(1, _*) => "list, starts with 1, has any number of elements"
+ case Vector(1, _*) => "vector, starts w/ 1, has any number of elements"
+
+ // сравнение с кортежами
+ case (a, b) => s"got $a and $b"
+ case (a, b, c) => s"got $a, $b, and $c"
+
+ // сравнение с конструктором класса
+ case Person(first, "Alexander") => s"Alexander, first name = $first"
+ case Dog("Zeus") => "found a dog named Zeus"
+
+ // сравнение по типу
+ case s: String => s"got a string: $s"
+ case i: Int => s"got an int: $i"
+ case f: Float => s"got a float: $f"
+ case a: Array[Int] => s"array of int: ${a.mkString(",")}"
+ case as: Array[String] => s"string array: ${as.mkString(",")}"
+ case d: Dog => s"dog: ${d.name}"
+ case list: List[?] => s"got a List: $list"
+ case m: Map[?, ?] => m.toString
+
+ // значение по умолчанию с подстановочным знаком
+ case _ => "Unknown"
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-30 %}
+```scala
+def pattern(x: Matchable): String = x match
+
+ // сравнение с константой
+ case 0 => "zero"
+ case true => "true"
+ case "hello" => "you said 'hello'"
+ case Nil => "an empty List"
+
+ // сравнение с последовательностями
+ case List(0, _, _) => "a 3-element list with 0 as the first element"
+ case List(1, _*) => "list, starts with 1, has any number of elements"
+ case Vector(1, _*) => "vector, starts w/ 1, has any number of elements"
+
+ // сравнение с кортежами
+ case (a, b) => s"got $a and $b"
+ case (a, b, c) => s"got $a, $b, and $c"
+
+ // сравнение с конструктором класса
+ case Person(first, "Alexander") => s"Alexander, first name = $first"
+ case Dog("Zeus") => "found a dog named Zeus"
+
+ // сравнение по типу
+ case s: String => s"got a string: $s"
+ case i: Int => s"got an int: $i"
+ case f: Float => s"got a float: $f"
+ case a: Array[Int] => s"array of int: ${a.mkString(",")}"
+ case as: Array[String] => s"string array: ${as.mkString(",")}"
+ case d: Dog => s"dog: ${d.name}"
+ case list: List[?] => s"got a List: $list"
+ case m: Map[?, ?] => m.toString
+
+ // значение по умолчанию с подстановочным знаком
+ case _ => "Unknown"
+```
+{% endtab %}
+{% endtabs %}
+
+## try/catch/finally
+
+Как и в Java, в Scala есть конструкция `try`/`catch`/`finally`, позволяющая перехватывать исключения и управлять ими.
+Для обеспечения согласованности Scala использует тот же синтаксис, что и выражения `match`,
+и поддерживает сопоставление с образцом для различных возможных исключений.
+
+В следующем примере `openAndReadAFile` - это метод, который выполняет то, что следует из его названия:
+он открывает файл и считывает из него текст, присваивая результат изменяемой переменной `text`:
+
+{% tabs control-structures-31 class=tabs-scala-version %}
+{% tab 'Scala 2' for=control-structures-31 %}
+```scala
+var text = ""
+try {
+ text = openAndReadAFile(filename)
+} catch {
+ case fnf: FileNotFoundException => fnf.printStackTrace()
+ case ioe: IOException => ioe.printStackTrace()
+} finally {
+ // здесь необходимо закрыть ресурсы
+ println("Came to the 'finally' clause.")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=control-structures-31 %}
+```scala
+var text = ""
+try
+ text = openAndReadAFile(filename)
+catch
+ case fnf: FileNotFoundException => fnf.printStackTrace()
+ case ioe: IOException => ioe.printStackTrace()
+finally
+ // здесь необходимо закрыть ресурсы
+ println("Came to the 'finally' clause.")
+```
+{% endtab %}
+{% endtabs %}
+
+Предполагая, что метод `openAndReadAFile` использует Java `java.io.*` классы для чтения файла
+и не перехватывает его исключения, попытка открыть и прочитать файл может привести как к `FileNotFoundException`,
+так и к `IOException`, и эти два исключения перехватываются в блоке `catch` этого примера.
+
+[matchable]: {{ site.scala3ref }}/other-new-features/matchable.html
diff --git a/_ru/scala3/book/domain-modeling-fp.md b/_ru/scala3/book/domain-modeling-fp.md
new file mode 100644
index 0000000000..a5bdb326c5
--- /dev/null
+++ b/_ru/scala3/book/domain-modeling-fp.md
@@ -0,0 +1,825 @@
+---
+layout: multipage-overview
+title: Моделирование ФП
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этой главе представлено введение в моделирование предметной области с использованием ФП в Scala 3.
+language: ru
+num: 23
+previous-page: domain-modeling-oop
+next-page: methods-intro
+---
+
+
+В этой главе представлено введение в моделирование предметной области
+с использованием функционального программирования (ФП) в Scala 3.
+При моделировании окружающего нас мира с помощью ФП обычно используются следующие конструкции Scala:
+
+- Перечисления
+- Case классы
+- Trait-ы
+
+> Если вы не знакомы с алгебраическими типами данных (ADT) и их обобщенной версией (GADT),
+> то можете прочитать главу ["Алгебраические типы данных"][adts], прежде чем читать этот раздел.
+
+## Введение
+
+В ФП *данные* и *операции над этими данными* — это две разные вещи; вы не обязаны инкапсулировать их вместе, как в ООП.
+
+Концепция аналогична числовой алгебре.
+Когда вы думаете о целых числах, больших либо равных нулю,
+у вас есть *набор* возможных значений, который выглядит следующим образом:
+
+````
+0, 1, 2 ... Int.MaxValue
+````
+
+Игнорируя деление целых чисел, возможные *операции* над этими значениями такие:
+
+````
++, -, *
+````
+
+Схема ФП реализуется аналогичным образом:
+
+- описывается свой набор значений (данные)
+- описываются операции, которые работают с этими значениями (функции)
+
+> Как будет видно, рассуждения о программах в этом стиле сильно отличаются от объектно-ориентированного программирования.
+> Проще говоря о данных в ФП:
+> Отделение функциональности от данных позволяет проверять свои данные, не беспокоясь о поведении.
+
+В этой главе мы смоделируем данные и операции для “пиццы” в пиццерии.
+Будет показано, как реализовать часть “данных” модели Scala/ФП,
+а затем - несколько различных способов организации операций с этими данными.
+
+## Моделирование данных
+
+В Scala достаточно просто описать модель данных:
+
+- если необходимо смоделировать данные с различными вариантами, то используется конструкция `enum` (или `case object` в Scala 2)
+- если необходимо только сгруппировать сущности (или нужен более детальный контроль), то используются case class-ы
+
+### Описание вариантов
+
+Данные, которые просто состоят из различных вариантов, таких как размер корочки, тип корочки и начинка,
+кратко моделируются с помощью перечислений:
+
+{% tabs data_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=data_1 %}
+
+В Scala 2 перечисления выражаются комбинацией `sealed class` и нескольких `case object`, которые расширяют класс:
+
+```scala
+sealed abstract class CrustSize
+object CrustSize {
+ case object Small extends CrustSize
+ case object Medium extends CrustSize
+ case object Large extends CrustSize
+}
+
+sealed abstract class CrustType
+object CrustType {
+ case object Thin extends CrustType
+ case object Thick extends CrustType
+ case object Regular extends CrustType
+}
+
+sealed abstract class Topping
+object Topping {
+ case object Cheese extends Topping
+ case object Pepperoni extends Topping
+ case object BlackOlives extends Topping
+ case object GreenOlives extends Topping
+ case object Onions extends Topping
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=data_1 %}
+
+В Scala 3 перечисления кратко выражаются конструкцией `enum`:
+
+```scala
+enum CrustSize:
+ case Small, Medium, Large
+
+enum CrustType:
+ case Thin, Thick, Regular
+
+enum Topping:
+ case Cheese, Pepperoni, BlackOlives, GreenOlives, Onions
+```
+
+{% endtab %}
+{% endtabs %}
+
+> Типы данных, которые описывают различные варианты (например, `CrustSize`),
+> также иногда называются суммированными типами (_sum types_).
+
+### Описание основных данных
+
+Пиццу можно рассматривать как _составной_ контейнер с различными атрибутами, указанными выше.
+Мы можем использовать `case class`, чтобы описать,
+что `Pizza` состоит из `crustSize`, `crustType` и, возможно, нескольких `toppings`:
+
+{% tabs data_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=data_2 %}
+
+```scala
+import CrustSize._
+import CrustType._
+import Topping._
+
+case class Pizza(
+ crustSize: CrustSize,
+ crustType: CrustType,
+ toppings: Seq[Topping]
+)
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=data_2 %}
+
+```scala
+import CrustSize.*
+import CrustType.*
+import Topping.*
+
+case class Pizza(
+ crustSize: CrustSize,
+ crustType: CrustType,
+ toppings: Seq[Topping]
+)
+```
+
+{% endtab %}
+{% endtabs %}
+
+> Типы данных, объединяющие несколько компонентов (например, `Pizza`), также иногда называют типами продуктов (_product types_).
+
+И все. Это модель данных для системы доставки пиццы в стиле ФП.
+Решение очень лаконично, поскольку оно не требует объединения модели данных с операциями с пиццей.
+Модель данных легко читается, как объявление дизайна для реляционной базы данных.
+Также очень легко создавать значения нашей модели данных и проверять их:
+
+{% tabs data_3 %}
+{% tab 'Scala 2 и 3' for=data_3 %}
+
+```scala
+val myFavPizza = Pizza(Small, Regular, Seq(Cheese, Pepperoni))
+println(myFavPizza.crustType) // печатает Regular
+```
+
+{% endtab %}
+{% endtabs %}
+
+#### Подробнее о модели данных
+
+Таким же образом можно было бы смоделировать всю систему заказа пиццы.
+Вот несколько других `case class`-ов, которые используются для моделирования такой системы:
+
+{% tabs data_4 %}
+{% tab 'Scala 2 и 3' for=data_4 %}
+
+```scala
+case class Address(
+ street1: String,
+ street2: Option[String],
+ city: String,
+ state: String,
+ zipCode: String
+)
+
+case class Customer(
+ name: String,
+ phone: String,
+ address: Address
+)
+
+case class Order(
+ pizzas: Seq[Pizza],
+ customer: Customer
+)
+```
+
+{% endtab %}
+{% endtabs %}
+
+#### “Узкие доменные объекты”
+
+В своей книге *Functional and Reactive Domain Modeling*, Debasish Ghosh утверждает,
+что там, где специалисты по ООП описывают свои классы как “широкие модели предметной области”,
+которые инкапсулируют данные и поведение,
+модели данных ФП можно рассматривать как “узкие объекты предметной области”.
+Это связано с тем, что, как показано выше, модели данных определяются как `case` классы с атрибутами,
+но без поведения, что приводит к коротким и лаконичным структурам данных.
+
+## Моделирование операций
+
+Возникает интересный вопрос: поскольку ФП отделяет данные от операций над этими данными,
+то как эти операции реализуются в Scala?
+
+Ответ на самом деле довольно прост: пишутся функции (или методы), работающие со значениями смоделированных данных.
+Например, можно определить функцию, которая вычисляет цену пиццы.
+
+{% tabs data_5 class=tabs-scala-version %}
+{% tab 'Scala 2' for=data_5 %}
+
+```scala
+def pizzaPrice(p: Pizza): Double = p match {
+ case Pizza(crustSize, crustType, toppings) => {
+ val base = 6.00
+ val crust = crustPrice(crustSize, crustType)
+ val tops = toppings.map(toppingPrice).sum
+ base + crust + tops
+ }
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=data_5 %}
+
+```scala
+def pizzaPrice(p: Pizza): Double = p match
+ case Pizza(crustSize, crustType, toppings) =>
+ val base = 6.00
+ val crust = crustPrice(crustSize, crustType)
+ val tops = toppings.map(toppingPrice).sum
+ base + crust + tops
+```
+
+{% endtab %}
+{% endtabs %}
+
+Можно заметить, что реализация функции просто повторяет форму данных: поскольку `Pizza` является case class-ом,
+используется сопоставление с образцом для извлечения компонентов,
+а затем вызываются вспомогательные функции для вычисления отдельных цен.
+
+{% tabs data_6 class=tabs-scala-version %}
+{% tab 'Scala 2' for=data_6 %}
+
+```scala
+def toppingPrice(t: Topping): Double = t match {
+ case Cheese | Onions => 0.5
+ case Pepperoni | BlackOlives | GreenOlives => 0.75
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=data_6 %}
+
+```scala
+def toppingPrice(t: Topping): Double = t match
+ case Cheese | Onions => 0.5
+ case Pepperoni | BlackOlives | GreenOlives => 0.75
+```
+
+{% endtab %}
+{% endtabs %}
+
+Точно так же, поскольку `Topping` является перечислением,
+используется сопоставление с образцом, чтобы разделить варианты.
+Сыр и лук продаются по 50 центов за штуку, остальные — по 75.
+
+{% tabs data_7 class=tabs-scala-version %}
+{% tab 'Scala 2' for=data_7 %}
+
+```scala
+def crustPrice(s: CrustSize, t: CrustType): Double =
+ (s, t) match {
+ // если размер корочки маленький или средний, тип не важен
+ case (Small | Medium, _) => 0.25
+ case (Large, Thin) => 0.50
+ case (Large, Regular) => 0.75
+ case (Large, Thick) => 1.00
+ }
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=data_7 %}
+
+```scala
+def crustPrice(s: CrustSize, t: CrustType): Double =
+ (s, t) match
+ // если размер корочки маленький или средний, тип не важен
+ case (Small | Medium, _) => 0.25
+ case (Large, Thin) => 0.50
+ case (Large, Regular) => 0.75
+ case (Large, Thick) => 1.00
+```
+
+{% endtab %}
+{% endtabs %}
+
+Чтобы рассчитать цену корки, мы одновременно сопоставляем образцы как по размеру, так и по типу корки.
+
+> Важным моментом во всех показанных выше функциях является то, что они являются чистыми функциями (_pure functions_):
+> они не изменяют данные и не имеют других побочных эффектов (таких, как выдача исключений или запись в файл).
+> Всё, что они делают - это просто получают значения и вычисляют результат.
+
+## Как организовать функциональность?
+
+При реализации функции `pizzaPrice`, описанной выше, не было сказано, _где_ ее определять.
+Scala предоставляет множество отличных инструментов для организации логики в различных пространствах имен и модулях.
+
+Существует несколько способов реализации и организации поведения:
+
+- определить функции в сопутствующих объектах (companion object)
+- использовать модульный стиль программирования
+- использовать подход “функциональных объектов”
+- определить функциональность в методах расширения
+
+Эти различные решения показаны в оставшейся части этого раздела.
+
+### Сопутствующий объект
+
+Первый подход — определить поведение (функции) в сопутствующем объекте.
+
+> Как обсуждалось в разделе [“Инструменты”][modeling-tools],
+> _сопутствующий объект_ — это `object` с тем же именем, что и у класса, и объявленный в том же файле, что и класс.
+
+При таком подходе в дополнение к `enum` или `case class` также определяется сопутствующий объект с таким же именем,
+который содержит поведение (функции).
+
+{% tabs org_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=org_1 %}
+
+```scala
+case class Pizza(
+ crustSize: CrustSize,
+ crustType: CrustType,
+ toppings: Seq[Topping]
+)
+
+// сопутствующий объект для case class Pizza
+object Pizza {
+ // тоже самое, что и `pizzaPrice`
+ def price(p: Pizza): Double = ...
+}
+
+sealed abstract class Topping
+
+// сопутствующий объект для перечисления Topping
+object Topping {
+ case object Cheese extends Topping
+ case object Pepperoni extends Topping
+ case object BlackOlives extends Topping
+ case object GreenOlives extends Topping
+ case object Onions extends Topping
+
+ // тоже самое, что и `toppingPrice`
+ def price(t: Topping): Double = ...
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=org_1 %}
+
+```scala
+case class Pizza(
+ crustSize: CrustSize,
+ crustType: CrustType,
+ toppings: Seq[Topping]
+)
+
+// сопутствующий объект для case class Pizza
+object Pizza:
+ // тоже самое, что и `pizzaPrice`
+ def price(p: Pizza): Double = ...
+
+enum Topping:
+ case Cheese, Pepperoni, BlackOlives, GreenOlives, Onions
+
+// сопутствующий объект для перечисления Topping
+object Topping:
+ // тоже самое, что и `toppingPrice`
+ def price(t: Topping): Double = ...
+```
+
+{% endtab %}
+{% endtabs %}
+
+При таком подходе можно создать `Pizza` и вычислить ее цену следующим образом:
+
+{% tabs org_2 %}
+{% tab 'Scala 2 и 3' for=org_2 %}
+
+```scala
+val pizza1 = Pizza(Small, Thin, Seq(Cheese, Onions))
+Pizza.price(pizza1)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Группировка функциональности с помощью сопутствующих объектов имеет несколько преимуществ:
+
+- связывает функциональность с данными и облегчает их поиск программистам (и компилятору).
+- создает пространство имен и, например, позволяет использовать `price` в качестве имени метода, не полагаясь на перегрузку.
+- реализация `Topping.price` может получить доступ к значениям перечисления, таким как `Cheese`, без необходимости их импорта.
+
+Однако также есть несколько компромиссов, которые следует учитывать:
+
+- модель данных тесно связывается с функциональностью.
+ В частности, сопутствующий объект должен быть определен в том же файле, что и `case class`.
+- неясно, где определять такие функции, как `crustPrice`,
+ которые с одинаковым успехом можно поместить в сопутствующий объект `CrustSize` или `CrustType`.
+
+## Модули
+
+Второй способ организации поведения — использование “модульного” подхода.
+В книге _“Программирование на Scala”_ _модуль_ определяется как
+“небольшая часть программы с четко определенным интерфейсом и скрытой реализацией”.
+Давайте посмотрим, что это значит.
+
+### Создание интерфейса `PizzaService`
+
+Первое, о чем следует подумать, — это “поведение” `Pizza`.
+Делая это, определяем `trait PizzaServiceInterface` следующим образом:
+
+{% tabs module_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=module_1 %}
+
+```scala
+trait PizzaServiceInterface {
+
+ def price(p: Pizza): Double
+
+ def addTopping(p: Pizza, t: Topping): Pizza
+ def removeAllToppings(p: Pizza): Pizza
+
+ def updateCrustSize(p: Pizza, cs: CrustSize): Pizza
+ def updateCrustType(p: Pizza, ct: CrustType): Pizza
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=module_1 %}
+
+```scala
+trait PizzaServiceInterface:
+
+ def price(p: Pizza): Double
+
+ def addTopping(p: Pizza, t: Topping): Pizza
+ def removeAllToppings(p: Pizza): Pizza
+
+ def updateCrustSize(p: Pizza, cs: CrustSize): Pizza
+ def updateCrustType(p: Pizza, ct: CrustType): Pizza
+```
+
+{% endtab %}
+{% endtabs %}
+
+Как показано, каждый метод принимает `Pizza` в качестве входного параметра вместе с другими параметрами,
+а затем возвращает экземпляр `Pizza` в качестве результата.
+
+Когда пишется такой чистый интерфейс, можно думать о нем как о контракте,
+в котором говорится: “Все неабстрактные классы, расширяющие этот trait, должны предоставлять реализацию этих сервисов”.
+
+На этом этапе также можно представить, что вы являетесь потребителем этого API.
+Когда вы это сделаете, будет полезно набросать некоторый пример “потребительского” кода,
+чтобы убедиться, что API выглядит так, как хотелось:
+
+{% tabs module_2 %}
+{% tab 'Scala 2 и 3' for=module_2 %}
+
+```scala
+val p = Pizza(Small, Thin, Seq(Cheese))
+
+// как вы хотите использовать методы в PizzaServiceInterface
+val p1 = addTopping(p, Pepperoni)
+val p2 = addTopping(p1, Onions)
+val p3 = updateCrustType(p2, Thick)
+val p4 = updateCrustSize(p3, Large)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Если с этим кодом все в порядке, как правило, можно начать набрасывать другой API, например API для заказов,
+но, поскольку сейчас рассматривается только `Pizza`, перейдем к созданию конкретной реализации этого интерфейса.
+
+> Обратите внимание, что обычно это двухэтапный процесс.
+> На первом шаге набрасывается контракт API в качестве _интерфейса_.
+> На втором шаге создается конкретная _реализация_ этого интерфейса.
+> В некоторых случаях в конечном итоге создается несколько конкретных реализаций базового интерфейса.
+
+### Создание конкретной реализации
+
+Теперь, когда известно, как выглядит `PizzaServiceInterface`, можно создать конкретную реализацию,
+написав тело для всех методов, определенных в интерфейсе:
+
+{% tabs module_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=module_3 %}
+
+```scala
+object PizzaService extends PizzaServiceInterface {
+
+ def price(p: Pizza): Double =
+ ... // реализация была дана выше
+
+ def addTopping(p: Pizza, t: Topping): Pizza =
+ p.copy(toppings = p.toppings :+ t)
+
+ def removeAllToppings(p: Pizza): Pizza =
+ p.copy(toppings = Seq.empty)
+
+ def updateCrustSize(p: Pizza, cs: CrustSize): Pizza =
+ p.copy(crustSize = cs)
+
+ def updateCrustType(p: Pizza, ct: CrustType): Pizza =
+ p.copy(crustType = ct)
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=module_3 %}
+
+```scala
+object PizzaService extends PizzaServiceInterface:
+
+ def price(p: Pizza): Double =
+ ... // реализация была дана выше
+
+ def addTopping(p: Pizza, t: Topping): Pizza =
+ p.copy(toppings = p.toppings :+ t)
+
+ def removeAllToppings(p: Pizza): Pizza =
+ p.copy(toppings = Seq.empty)
+
+ def updateCrustSize(p: Pizza, cs: CrustSize): Pizza =
+ p.copy(crustSize = cs)
+
+ def updateCrustType(p: Pizza, ct: CrustType): Pizza =
+ p.copy(crustType = ct)
+
+end PizzaService
+```
+
+{% endtab %}
+{% endtabs %}
+
+Хотя двухэтапный процесс создания интерфейса с последующей реализацией не всегда необходим,
+явное продумывание API и его использования — хороший подход.
+
+Когда все готово, можно использовать `Pizza` и `PizzaService`:
+
+{% tabs module_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=module_4 %}
+
+```scala
+import PizzaService._
+
+val p = Pizza(Small, Thin, Seq(Cheese))
+
+// использование методов PizzaService
+val p1 = addTopping(p, Pepperoni)
+val p2 = addTopping(p1, Onions)
+val p3 = updateCrustType(p2, Thick)
+val p4 = updateCrustSize(p3, Large)
+
+println(price(p4)) // печатает 8.75
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=module_4 %}
+
+```scala
+import PizzaService.*
+
+val p = Pizza(Small, Thin, Seq(Cheese))
+
+// использование методов PizzaService
+val p1 = addTopping(p, Pepperoni)
+val p2 = addTopping(p1, Onions)
+val p3 = updateCrustType(p2, Thick)
+val p4 = updateCrustSize(p3, Large)
+
+println(price(p4)) // печатает 8.75
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Функциональные объекты
+
+В книге _“Программирование на Scala”_ авторы определяют термин “Функциональные объекты” как
+“объекты, которые не имеют никакого изменяемого состояния”.
+Это также относится к типам в `scala.collection.immutable`.
+Например, методы в `List` не изменяют внутреннего состояния, а вместо этого в результате создают копию `List`.
+
+Об этом подходе можно думать, как о “гибридном дизайне ФП/ООП”, потому что:
+
+- данные моделируются, используя неизменяемые `case` классы.
+- определяется поведение (методы) _того же типа_, что и данные.
+- поведение реализуется как чистые функции: они не изменяют никакого внутреннего состояния; скорее - возвращают копию.
+
+> Это действительно гибридный подход: как и в **дизайне ООП**, методы инкапсулированы в класс с данными,
+> но, как это обычно бывает **в дизайне ФП**, методы реализованы как чистые функции, которые данные не изменяют.
+
+#### Пример
+
+Используя этот подход, можно напрямую реализовать функциональность пиццы в `case class`:
+
+{% tabs module_5 class=tabs-scala-version %}
+{% tab 'Scala 2' for=module_5 %}
+
+```scala
+case class Pizza(
+ crustSize: CrustSize,
+ crustType: CrustType,
+ toppings: Seq[Topping]
+) {
+
+ // операции этой модели данных
+ def price: Double =
+ pizzaPrice(this) // такая же имплементация, как и выше
+
+ def addTopping(t: Topping): Pizza =
+ this.copy(toppings = this.toppings :+ t)
+
+ def removeAllToppings: Pizza =
+ this.copy(toppings = Seq.empty)
+
+ def updateCrustSize(cs: CrustSize): Pizza =
+ this.copy(crustSize = cs)
+
+ def updateCrustType(ct: CrustType): Pizza =
+ this.copy(crustType = ct)
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=module_5 %}
+
+```scala
+case class Pizza(
+ crustSize: CrustSize,
+ crustType: CrustType,
+ toppings: Seq[Topping]
+):
+
+ // операции этой модели данных
+ def price: Double =
+ pizzaPrice(this) // такая же имплементация, как и выше
+
+ def addTopping(t: Topping): Pizza =
+ this.copy(toppings = this.toppings :+ t)
+
+ def removeAllToppings: Pizza =
+ this.copy(toppings = Seq.empty)
+
+ def updateCrustSize(cs: CrustSize): Pizza =
+ this.copy(crustSize = cs)
+
+ def updateCrustType(ct: CrustType): Pizza =
+ this.copy(crustType = ct)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Обратите внимание, что в отличие от предыдущих подходов, поскольку это методы класса `Pizza`,
+они не принимают ссылку `Pizza` в качестве входного параметра.
+Вместо этого у них есть собственная ссылка на текущий экземпляр пиццы - `this`.
+
+Теперь можно использовать этот новый дизайн следующим образом:
+
+{% tabs module_6 %}
+{% tab 'Scala 2 и 3' for=module_6 %}
+
+```scala
+Pizza(Small, Thin, Seq(Cheese))
+ .addTopping(Pepperoni)
+ .updateCrustType(Thick)
+ .price
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Методы расширения
+
+Методы расширения - подход, который находится где-то между первым (определение функций в сопутствующем объекте)
+и последним (определение функций как методов самого типа).
+
+Методы расширения позволяют создавать API, похожий на API функционального объекта,
+без необходимости определять функции как методы самого типа.
+Это может иметь несколько преимуществ:
+
+- модель данных снова _очень лаконична_ и не упоминает никакого поведения.
+- можно _задним числом_ развить функциональность типов дополнительными методами, не изменяя исходного определения.
+- помимо сопутствующих объектов или прямых методов типов, методы расширения могут быть определены _извне_ в другом файле.
+
+Вернемся к примеру:
+
+{% tabs module_7 class=tabs-scala-version %}
+{% tab 'Scala 2' for=module_7 %}
+
+```scala
+case class Pizza(
+ crustSize: CrustSize,
+ crustType: CrustType,
+ toppings: Seq[Topping]
+)
+
+implicit class PizzaOps(p: Pizza) {
+ def price: Double =
+ pizzaPrice(p) // такая же имплементация, как и выше
+
+ def addTopping(t: Topping): Pizza =
+ p.copy(toppings = p.toppings :+ t)
+
+ def removeAllToppings: Pizza =
+ p.copy(toppings = Seq.empty)
+
+ def updateCrustSize(cs: CrustSize): Pizza =
+ p.copy(crustSize = cs)
+
+ def updateCrustType(ct: CrustType): Pizza =
+ p.copy(crustType = ct)
+}
+```
+В приведенном выше коде мы определяем различные методы для пиццы как методы в _неявном классе_ (_implicit class_).
+С `implicit class PizzaOps(p: Pizza)` тогда, где бы `PizzaOps` ни был импортирован,
+его методы будут доступны в экземплярах `Pizza`.
+Получатель в этом случае `p`.
+
+{% endtab %}
+{% tab 'Scala 3' for=module_7 %}
+
+```scala
+case class Pizza(
+ crustSize: CrustSize,
+ crustType: CrustType,
+ toppings: Seq[Topping]
+)
+
+extension (p: Pizza)
+ def price: Double =
+ pizzaPrice(p) // такая же имплементация, как и выше
+
+ def addTopping(t: Topping): Pizza =
+ p.copy(toppings = p.toppings :+ t)
+
+ def removeAllToppings: Pizza =
+ p.copy(toppings = Seq.empty)
+
+ def updateCrustSize(cs: CrustSize): Pizza =
+ p.copy(crustSize = cs)
+
+ def updateCrustType(ct: CrustType): Pizza =
+ p.copy(crustType = ct)
+```
+В приведенном выше коде мы определяем различные методы для пиццы как _методы расширения_ (_extension methods_).
+С помощью `extension (p: Pizza)` мы говорим, что хотим сделать методы доступными для экземпляров `Pizza`.
+Получатель в этом случае `p`.
+
+{% endtab %}
+{% endtabs %}
+
+Используя наши методы расширения, мы можем получить тот же API, что и раньше:
+
+{% tabs module_8 %}
+{% tab 'Scala 2 и 3' for=module_8 %}
+
+```scala
+Pizza(Small, Thin, Seq(Cheese))
+ .addTopping(Pepperoni)
+ .updateCrustType(Thick)
+ .price
+```
+
+{% endtab %}
+{% endtabs %}
+
+При этом методы расширения можно определить в любом другом модуле.
+Как правило, если вы являетесь разработчиком модели данных, то определяете свои методы расширения в сопутствующем объекте.
+Таким образом, они уже доступны всем пользователям.
+В противном случае методы расширения должны быть импортированы явно, чтобы их можно было использовать.
+
+## Резюме функционального подхода
+
+Определение модели данных в Scala/ФП, как правило, простое:
+моделируются варианты данных с помощью перечислений и составных данных с помощью `case` классов.
+Затем, чтобы смоделировать поведение, определяются функции, которые работают со значениями модели данных.
+Были рассмотрены разные способы организации функций:
+
+- можно поместить методы в сопутствующие объекты
+- можно использовать модульный стиль программирования, разделяющий интерфейс и реализацию
+- можно использовать подход “функциональных объектов” и хранить методы в определенном типе данных
+- можно использовать методы расширения, чтобы снабдить модель данных функциональностью
+
+[adts]: {% link _overviews/scala3-book/types-adts-gadts.md %}
+[modeling-tools]: {% link _overviews/scala3-book/domain-modeling-tools.md %}
diff --git a/_ru/scala3/book/domain-modeling-intro.md b/_ru/scala3/book/domain-modeling-intro.md
new file mode 100644
index 0000000000..79828b6d84
--- /dev/null
+++ b/_ru/scala3/book/domain-modeling-intro.md
@@ -0,0 +1,19 @@
+---
+layout: multipage-overview
+title: Моделирование предметной области
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: В этой главе показано, как можно моделировать предметную область с помощью Scala 3.
+language: ru
+num: 20
+previous-page: control-structures
+next-page: domain-modeling-tools
+---
+
+В этой главе показано, как можно смоделировать предметную область с помощью Scala 3:
+
+- В разделе "Инструменты" представлены доступные вам инструменты, включая классы, трейты, перечисления и многое другое.
+- В разделе "Моделирование ООП" рассматриваются атрибуты и поведение моделирования в стиле объектно-ориентированного программирования (ООП).
+- В разделе "Моделирование ФП" рассматривается моделирование предметной области в стиле функционального программирования (ФП).
diff --git a/_ru/scala3/book/domain-modeling-oop.md b/_ru/scala3/book/domain-modeling-oop.md
new file mode 100644
index 0000000000..f9de517ddd
--- /dev/null
+++ b/_ru/scala3/book/domain-modeling-oop.md
@@ -0,0 +1,602 @@
+---
+layout: multipage-overview
+title: Моделирование ООП
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этой главе представлено введение в моделирование предметной области с использованием ООП в Scala 3.
+language: ru
+num: 22
+previous-page: domain-modeling-tools
+next-page: domain-modeling-fp
+---
+
+В этой главе представлено введение в моделирование предметной области с использованием
+объектно-ориентированного программирования (ООП) в Scala 3.
+
+## Введение
+
+Scala предоставляет все необходимые инструменты для объектно-ориентированного проектирования:
+
+- **Traits** позволяют указывать (абстрактные) интерфейсы, а также конкретные реализации.
+- **Mixin Composition** предоставляет инструменты для создания компонентов из более мелких деталей.
+- **Классы** могут реализовывать интерфейсы, заданные трейтами.
+- **Экземпляры** классов могут иметь свое собственное приватное состояние.
+- **Subtyping** позволяет использовать экземпляр одного класса там, где ожидается экземпляр его суперкласса.
+- **Модификаторы доступа** позволяют управлять, к каким членам класса можно получить доступ с помощью какой части кода.
+
+## Трейты
+
+В отличие от других языков с поддержкой ООП, таких как Java, возможно,
+основным инструментом декомпозиции в Scala являются не классы, а трейты.
+Они могут служить для описания абстрактных интерфейсов, таких как:
+
+{% tabs traits_1 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait Showable {
+ def show: String
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+trait Showable:
+ def show: String
+```
+{% endtab %}
+{% endtabs %}
+
+а также могут содержать конкретные реализации:
+
+{% tabs traits_2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait Showable {
+ def show: String
+ def showHtml = "
"
+```
+{% endtab %}
+{% endtabs %}
+
+На примере видно, что метод `showHtml` определяется в терминах абстрактного метода `show`.
+
+[Odersky и Zenger][scalable] представляют _сервис-ориентированную компонентную модель_ и рассматривают:
+
+- **абстрактные члены** как _требуемые_ службы: их все еще необходимо реализовать в подклассе.
+- **конкретные члены** как _предоставляемые_ услуги: они предоставляются подклассу.
+
+Это видно на примере со `Showable`: определяя класс `Document`, который расширяет `Showable`,
+все еще нужно определить `show`, но `showHtml` уже предоставляется:
+
+{% tabs traits_3 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+class Document(text: String) extends Showable {
+ def show = text
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+class Document(text: String) extends Showable:
+ def show = text
+```
+
+{% endtab %}
+{% endtabs %}
+
+#### Абстрактные члены
+
+Абстрактными в `trait` могут оставаться не только методы.
+`trait` может содержать:
+
+- абстрактные методы (`def m(): T`)
+- абстрактные переменные (`val x: T`)
+- абстрактные типы (`type T`), потенциально с ограничениями (`type T <: S`)
+- абстрактные given (`given t: T`) только в Scala 3
+
+Каждая из вышеперечисленных функций может быть использована для определения той или иной формы требований к реализатору `trait`.
+
+## Смешанная композиция
+
+Кроме того, что `trait`-ы могут содержать абстрактные и конкретные определения,
+Scala также предоставляет мощный способ создания нескольких `trait`:
+структура, которую часто называют _смешанной композицией_.
+
+Предположим, что существуют следующие два (потенциально независимо определенные) `trait`-а:
+
+{% tabs traits_4 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait GreetingService {
+ def translate(text: String): String
+ def sayHello = translate("Hello")
+}
+
+trait TranslationService {
+ def translate(text: String): String = "..."
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+trait GreetingService:
+ def translate(text: String): String
+ def sayHello = translate("Hello")
+
+trait TranslationService:
+ def translate(text: String): String = "..."
+```
+
+{% endtab %}
+{% endtabs %}
+
+Чтобы скомпоновать два сервиса, можно просто создать новый `trait`, расширяющий их:
+
+{% tabs traits_5 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait ComposedService extends GreetingService with TranslationService
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+trait ComposedService extends GreetingService, TranslationService
+```
+
+{% endtab %}
+{% endtabs %}
+
+Абстрактные элементы в одном `trait`-е (например, `translate` в `GreetingService`)
+автоматически сопоставляются с конкретными элементами в другом `trait`-е.
+Это работает не только с методами, как в этом примере, но и со всеми другими абстрактными членами,
+упомянутыми выше (то есть типами, переменными и т.д.).
+
+## Классы
+
+`trait`-ы отлично подходят для модуляции компонентов и описания интерфейсов (обязательных и предоставляемых).
+Но в какой-то момент возникнет необходимость создавать их экземпляры.
+При разработке программного обеспечения в Scala часто бывает полезно рассмотреть возможность
+использования классов только на начальных этапах модели наследования:
+
+{% tabs table-traits-cls-summary class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+| Трейты | `T1`, `T2`, `T3`
+| Составные трейты | `S1 extends T1 with T2`, `S2 extends T2 with T3`
+| Классы | `C extends S1 with T3`
+| Экземпляры | `new C()`
+{% endtab %}
+{% tab 'Scala 3' %}
+| Трейты | `T1`, `T2`, `T3`
+| Составные трейты | `S1 extends T1, T2`, `S2 extends T2, T3`
+| Классы | `C extends S1, T3`
+| Экземпляры | `C()`
+{% endtab %}
+{% endtabs %}
+
+Это еще более актуально в Scala 3, где трейты теперь также могут принимать параметры конструктора,
+что еще больше устраняет необходимость в классах.
+
+#### Определение класса
+
+Подобно `trait`-ам, классы могут расширять несколько `trait`-ов (но только один суперкласс):
+
+{% tabs class_1 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+class MyService(name: String) extends ComposedService with Showable {
+ def show = s"$name says $sayHello"
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+class MyService(name: String) extends ComposedService, Showable:
+ def show = s"$name says $sayHello"
+```
+
+{% endtab %}
+{% endtabs %}
+
+#### Подтипы
+
+Экземпляр `MyService` создается следующим образом:
+
+{% tabs class_2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+val s1: MyService = new MyService("Service 1")
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+val s1: MyService = MyService("Service 1")
+```
+
+{% endtab %}
+{% endtabs %}
+
+С помощью подтипов экземпляр `s1` можно использовать везде, где ожидается любое из расширенных свойств:
+
+{% tabs class_3 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val s2: GreetingService = s1
+val s3: TranslationService = s1
+val s4: Showable = s1
+// ... и так далее ...
+```
+{% endtab %}
+{% endtabs %}
+
+#### Планирование расширения
+
+Как упоминалось ранее, можно расширить еще один класс:
+
+{% tabs class_4 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+class Person(name: String)
+class SoftwareDeveloper(name: String, favoriteLang: String)
+ extends Person(name)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Однако, поскольку `trait`-ы разработаны как основное средство декомпозиции,
+то не рекомендуется расширять класс, определенный в одном файле, из другого файла.
+
+
Открытые классы только в Scala 3
+
+В Scala 3 расширение неабстрактных классов в других файлах ограничено.
+Чтобы разрешить это, базовый класс должен быть помечен как `open`:
+
+{% tabs class_5 %}
+{% tab 'Только в Scala 3' %}
+
+```scala
+open class Person(name: String)
+```
+{% endtab %}
+{% endtabs %}
+
+Маркировка классов с помощью [`open`][open] - это новая функция Scala 3.
+Необходимость явно помечать классы как открытые позволяет избежать многих распространенных ошибок в ООП.
+В частности, это требует, чтобы разработчики библиотек явно планировали расширение
+и, например, документировали классы, помеченные как открытые.
+
+## Экземпляры и приватное изменяемое состояние
+
+Как и в других языках с поддержкой ООП, трейты и классы в Scala могут определять изменяемые поля:
+
+{% tabs instance_6 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+class Counter {
+ // получить значение можно только с помощью метода `count`
+ private var currentCount = 0
+
+ def tick(): Unit = currentCount += 1
+ def count: Int = currentCount
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+class Counter:
+ // получить значение можно только с помощью метода `count`
+ private var currentCount = 0
+
+ def tick(): Unit = currentCount += 1
+ def count: Int = currentCount
+```
+
+{% endtab %}
+{% endtabs %}
+
+Каждый экземпляр класса `Counter` имеет собственное приватное состояние,
+которое можно получить только через метод `count`, как показано в следующем взаимодействии:
+
+{% tabs instance_7 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+val c1 = new Counter()
+c1.count // 0
+c1.tick()
+c1.tick()
+c1.count // 2
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+val c1 = Counter()
+c1.count // 0
+c1.tick()
+c1.tick()
+c1.count // 2
+```
+
+{% endtab %}
+{% endtabs %}
+
+#### Модификаторы доступа
+
+По умолчанию все определения элементов в Scala общедоступны.
+Чтобы скрыть детали реализации, можно определить элементы (методы, поля, типы и т.д.) в качестве `private` или `protected`.
+Таким образом, вы можете управлять доступом к ним или их переопределением.
+Закрытые (`private`) элементы видны только самому классу/трейту и его сопутствующему объекту.
+Защищенные (`protected`) элементы также видны для подклассов класса.
+
+## Дополнительный пример: сервис-ориентированный дизайн
+
+Далее будут проиллюстрированы некоторые расширенные возможности Scala и показано,
+как их можно использовать для структурирования более крупных программных компонентов.
+Примеры взяты из статьи Мартина Одерски и Маттиаса Зенгера ["Scalable Component Abstractions"][scalable].
+Пример в первую очередь предназначен для демонстрации того,
+как использовать несколько функций типа для создания более крупных компонентов.
+
+Цель состоит в том, чтобы определить программный компонент с семейством типов,
+которые могут быть уточнены позже при реализации компонента.
+Конкретно, следующий код определяет компонент `SubjectObserver` как `trait` с двумя членами абстрактного типа,
+`S` (для субъектов) и `O` (для наблюдателей):
+
+{% tabs example_1 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait SubjectObserver {
+
+ type S <: Subject
+ type O <: Observer
+
+ trait Subject { self: S =>
+ private var observers: List[O] = List()
+ def subscribe(obs: O): Unit = {
+ observers = obs :: observers
+ }
+ def publish() = {
+ for ( obs <- observers ) obs.notify(this)
+ }
+ }
+
+ trait Observer {
+ def notify(sub: S): Unit
+ }
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+trait SubjectObserver:
+
+ type S <: Subject
+ type O <: Observer
+
+ trait Subject:
+ self: S =>
+ private var observers: List[O] = List()
+ def subscribe(obs: O): Unit =
+ observers = obs :: observers
+ def publish() =
+ for obs <- observers do obs.notify(this)
+
+ trait Observer:
+ def notify(sub: S): Unit
+```
+
+{% endtab %}
+{% endtabs %}
+
+Есть несколько вещей, которые нуждаются в объяснении.
+
+#### Члены абстрактного типа
+
+Тип объявления `S <: Subject` говорит, что внутри trait `SubjectObserver` можно ссылаться на
+некоторый _неизвестный_ (то есть абстрактный) тип, который называется `S`.
+Однако этот тип не является полностью неизвестным: мы знаем, по крайней мере, что это какой-то подтип `Subject`.
+Все trait-ы и классы, расширяющие `SubjectObserver`, могут свободно выбирать любой тип для `S`,
+если выбранный тип является подтипом `Subject`.
+Часть `<: Subject` декларации также упоминается как верхняя граница на `S`.
+
+#### Вложенные trait-ы
+
+_В рамках_ trait-а `SubjectObserver` определяются два других trait-а.
+trait `Observer`, который определяет только один абстрактный метод `notify` с одним аргументом типа `S`.
+Как будет видно, важно, чтобы аргумент имел тип `S`, а не тип `Subject`.
+
+Второй trait, `Subject`, определяет одно приватное поле `observers` для хранения всех наблюдателей,
+подписавшихся на этот конкретный объект. Подписка на объект просто сохраняет объект в списке.
+Опять же, тип параметра `obs` - это `O`, а не `Observer`.
+
+#### Аннотации собственного типа
+
+Наконец, что означает `self: S =>` в trait-е `Subject`? Это называется аннотацией собственного типа.
+И требует, чтобы подтипы `Subject` также были подтипами `S`.
+Это необходимо, чтобы иметь возможность вызывать `obs.notify` с `this` в качестве аргумента,
+поскольку для этого требуется значение типа `S`.
+Если бы `S` был конкретным типом, аннотацию собственного типа можно было бы заменить на `trait Subject extends S`.
+
+### Реализация компонента
+
+Теперь можно реализовать вышеуказанный компонент и определить члены абстрактного типа как конкретные типы:
+
+{% tabs example_2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+object SensorReader extends SubjectObserver {
+ type S = Sensor
+ type O = Display
+
+ class Sensor(val label: String) extends Subject {
+ private var currentValue = 0.0
+ def value = currentValue
+ def changeValue(v: Double) = {
+ currentValue = v
+ publish()
+ }
+ }
+
+ class Display extends Observer {
+ def notify(sub: Sensor) =
+ println(s"${sub.label} has value ${sub.value}")
+ }
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+object SensorReader extends SubjectObserver:
+ type S = Sensor
+ type O = Display
+
+ class Sensor(val label: String) extends Subject:
+ private var currentValue = 0.0
+ def value = currentValue
+ def changeValue(v: Double) =
+ currentValue = v
+ publish()
+
+ class Display extends Observer:
+ def notify(sub: Sensor) =
+ println(s"${sub.label} has value ${sub.value}")
+```
+
+{% endtab %}
+{% endtabs %}
+
+В частности, мы определяем _singleton_ `object SensorReader`, который расширяет `SubjectObserver`.
+В реализации `SensorReader` говорится, что тип `S` теперь определяется как тип `Sensor`,
+а тип `O` определяется как тип `Display`.
+И `Sensor`, и `Display` определяются как вложенные классы в `SensorReader`,
+реализующие trait-ы `Subject` и `Observer` соответственно.
+
+Помимо того, что этот код является примером сервис-ориентированного дизайна,
+он также освещает многие аспекты объектно-ориентированного программирования:
+
+- Класс `Sensor` вводит свое собственное частное состояние (`currentValue`)
+ и инкапсулирует изменение состояния за методом `changeValue`.
+- Реализация `changeValue` использует метод `publish`, определенный в родительском trait-е.
+- Класс `Display` расширяет trait `Observer` и реализует отсутствующий метод `notify`.
+
+Важно отметить, что реализация `notify` может безопасно получить доступ только к `label` и значению `sub`,
+поскольку мы изначально объявили параметр типа `S`.
+
+### Использование компонента
+
+Наконец, следующий код иллюстрирует, как использовать компонент `SensorReader`:
+
+{% tabs example_3 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+import SensorReader._
+
+// настройка сети
+val s1 = new Sensor("sensor1")
+val s2 = new Sensor("sensor2")
+val d1 = new Display()
+val d2 = new Display()
+s1.subscribe(d1)
+s1.subscribe(d2)
+s2.subscribe(d1)
+
+// распространение обновлений по сети
+s1.changeValue(2)
+s2.changeValue(3)
+
+// печатает:
+// sensor1 has value 2.0
+// sensor1 has value 2.0
+// sensor2 has value 3.0
+
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+import SensorReader.*
+
+// настройка сети
+val s1 = Sensor("sensor1")
+val s2 = Sensor("sensor2")
+val d1 = Display()
+val d2 = Display()
+s1.subscribe(d1)
+s1.subscribe(d2)
+s2.subscribe(d1)
+
+// распространение обновлений по сети
+s1.changeValue(2)
+s2.changeValue(3)
+
+// печатает:
+// sensor1 has value 2.0
+// sensor1 has value 2.0
+// sensor2 has value 3.0
+```
+
+{% endtab %}
+{% endtabs %}
+
+Имея под рукой все утилиты объектно-ориентированного программирования, в следующем разделе будет продемонстрировано,
+как разрабатывать программы в функциональном стиле.
+
+[scalable]: https://doi.org/10.1145/1094811.1094815
+[open]: {{ site.scala3ref }}/other-new-features/open-classes.html
+[trait-params]: {{ site.scala3ref }}/other-new-features/trait-parameters.html
diff --git a/_ru/scala3/book/domain-modeling-tools.md b/_ru/scala3/book/domain-modeling-tools.md
new file mode 100644
index 0000000000..ec35430443
--- /dev/null
+++ b/_ru/scala3/book/domain-modeling-tools.md
@@ -0,0 +1,1175 @@
+---
+layout: multipage-overview
+title: Инструменты
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этой главе представлено введение в доступные инструменты моделирования предметной области в Scala 3, включая классы, трейты, перечисления и многое другое.
+language: ru
+num: 21
+previous-page: domain-modeling-intro
+next-page: domain-modeling-oop
+---
+
+
+Scala предоставляет множество различных конструкций для моделирования предметной области:
+
+- Классы
+- Объекты
+- Сопутствующие объекты
+- Трейты
+- Абстрактные классы
+- Перечисления только в Scala 3
+- Case классы
+- Case объекты
+
+В этом разделе кратко представлена каждая из этих языковых конструкций.
+
+
+## Классы
+
+Как и в других языках, _класс_ в Scala — это шаблон для создания экземпляров объекта.
+Вот несколько примеров классов:
+
+{% tabs class_1 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+class Person(var name: String, var vocation: String)
+class Book(var title: String, var author: String, var year: Int)
+class Movie(var name: String, var director: String, var year: Int)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Эти примеры показывают, что в Scala есть очень легкий способ объявления классов.
+
+Все параметры в примерах наших классов определены как `var` поля, а значит, они изменяемы: их можно читать, а также изменять.
+Если вы хотите, чтобы они были неизменяемыми — только для чтения — создайте их как `val` поля или используйте case класс.
+
+До Scala 3 для создания нового экземпляра класса использовалось ключевое слово `new`:
+
+{% tabs class_2 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val p = new Person("Robert Allen Zimmerman", "Harmonica Player")
+// ---
+```
+
+{% endtab %}
+{% endtabs %}
+
+Однако с [универсальными apply методами][creator] в Scala 3 этого больше не требуется: только в Scala 3.
+
+{% tabs class_3 %}
+{% tab 'Только в Scala 3' %}
+
+```scala
+val p = Person("Robert Allen Zimmerman", "Harmonica Player")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Если у вас есть экземпляр класса, такой как `p`, то вы можете получить доступ к полям экземпляра,
+которые в этом примере являются параметрами конструктора:
+
+{% tabs class_4 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+p.name // "Robert Allen Zimmerman"
+p.vocation // "Harmonica Player"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Как уже упоминалось, все эти параметры были созданы как `var` поля, поэтому они изменяемые:
+
+{% tabs class_5 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+p.name = "Bob Dylan"
+p.vocation = "Musician"
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Поля и методы
+
+Классы также могут содержать методы и дополнительные поля, не являющиеся частью конструкторов.
+Они определены в теле класса.
+Тело инициализируется как часть конструктора по умолчанию:
+
+{% tabs method class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+class Person(var firstName: String, var lastName: String) {
+
+ println("initialization begins")
+ val fullName = firstName + " " + lastName
+
+ // метод класса
+ def printFullName: Unit =
+ // обращение к полю `fullName`, определенному выше
+ println(fullName)
+
+ printFullName
+ println("initialization ends")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+class Person(var firstName: String, var lastName: String):
+
+ println("initialization begins")
+ val fullName = firstName + " " + lastName
+
+ // метод класса
+ def printFullName: Unit =
+ // обращение к полю `fullName`, определенному выше
+ println(fullName)
+
+ printFullName
+ println("initialization ends")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Следующая сессия REPL показывает, как создать новый экземпляр `Person` с этим классом:
+
+{% tabs demo-person class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+````scala
+scala> val john = new Person("John", "Doe")
+initialization begins
+John Doe
+initialization ends
+val john: Person = Person@55d8f6bb
+
+scala> john.printFullName
+John Doe
+````
+{% endtab %}
+{% tab 'Scala 3' %}
+````scala
+scala> val john = Person("John", "Doe")
+initialization begins
+John Doe
+initialization ends
+val john: Person = Person@55d8f6bb
+
+scala> john.printFullName
+John Doe
+````
+{% endtab %}
+{% endtabs %}
+
+Классы также могут расширять трейты и абстрактные классы, которые мы рассмотрим в специальных разделах ниже.
+
+### Значения параметров по умолчанию
+
+В качестве беглого взгляда на некоторые другие функции,
+параметры конструктора класса также могут иметь значения по умолчанию:
+
+{% tabs default-values_1 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+class Socket(val timeout: Int = 5_000, val linger: Int = 5_000) {
+ override def toString = s"timeout: $timeout, linger: $linger"
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+class Socket(val timeout: Int = 5_000, val linger: Int = 5_000):
+ override def toString = s"timeout: $timeout, linger: $linger"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Отличительной особенностью этой функции является то, что она позволяет потребителям вашего кода
+создавать классы различными способами, как если бы у класса были альтернативные конструкторы:
+
+{% tabs default-values_2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+val s = new Socket() // timeout: 5000, linger: 5000
+val s = new Socket(2_500) // timeout: 2500, linger: 5000
+val s = new Socket(10_000, 10_000) // timeout: 10000, linger: 10000
+val s = new Socket(timeout = 10_000) // timeout: 10000, linger: 5000
+val s = new Socket(linger = 10_000) // timeout: 5000, linger: 10000
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+val s = Socket() // timeout: 5000, linger: 5000
+val s = Socket(2_500) // timeout: 2500, linger: 5000
+val s = Socket(10_000, 10_000) // timeout: 10000, linger: 10000
+val s = Socket(timeout = 10_000) // timeout: 10000, linger: 5000
+val s = Socket(linger = 10_000) // timeout: 5000, linger: 10000
+```
+
+{% endtab %}
+{% endtabs %}
+
+При создании нового экземпляра класса вы также можете использовать именованные параметры.
+Это особенно полезно, когда несколько параметров имеют одинаковый тип, как показано в этом сравнении:
+
+{% tabs default-values_3 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+// пример 1
+val s = new Socket(10_000, 10_000)
+
+// пример 2
+val s = new Socket(
+ timeout = 10_000,
+ linger = 10_000
+)
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+// пример 1
+val s = Socket(10_000, 10_000)
+
+// пример 2
+val s = Socket(
+ timeout = 10_000,
+ linger = 10_000
+)
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Вспомогательные конструкторы
+
+Вы можете определить класс с несколькими конструкторами,
+чтобы клиенты вашего класса могли создавать его различными способами.
+Например, предположим, что вам нужно написать код для моделирования студентов в системе приема в колледж.
+При анализе требований вы увидели, что необходимо создавать экземпляр `Student` тремя способами:
+
+- С именем и государственным удостоверением личности, когда они впервые начинают процесс приема
+- С именем, государственным удостоверением личности и дополнительной датой подачи заявки, когда они подают заявку
+- С именем, государственным удостоверением личности и студенческим билетом после того, как они будут приняты
+
+Один из способов справиться с этой ситуацией в стиле ООП - с помощью нижеследующего кода:
+
+{% tabs structor_1 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+import java.time._
+
+// [1] основной конструктор
+class Student(
+ var name: String,
+ var govtId: String
+) {
+ private var _applicationDate: Option[LocalDate] = None
+ private var _studentId: Int = 0
+
+ // [2] конструктор для студента, подавшего заявку
+ def this(
+ name: String,
+ govtId: String,
+ applicationDate: LocalDate
+ ) = {
+ this(name, govtId)
+ _applicationDate = Some(applicationDate)
+ }
+
+ // [3] конструктор, когда учащийся принят и теперь имеет студенческий билет
+ def this(
+ name: String,
+ govtId: String,
+ studentId: Int
+ ) = {
+ this(name, govtId)
+ _studentId = studentId
+ }
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+import java.time.*
+
+// [1] основной конструктор
+class Student(
+ var name: String,
+ var govtId: String
+):
+ private var _applicationDate: Option[LocalDate] = None
+ private var _studentId: Int = 0
+
+ // [2] конструктор для студента, подавшего заявку
+ def this(
+ name: String,
+ govtId: String,
+ applicationDate: LocalDate
+ ) =
+ this(name, govtId)
+ _applicationDate = Some(applicationDate)
+
+ // [3] конструктор, когда учащийся принят и теперь имеет студенческий билет
+ def this(
+ name: String,
+ govtId: String,
+ studentId: Int
+ ) =
+ this(name, govtId)
+ _studentId = studentId
+```
+
+{% endtab %}
+{% endtabs %}
+
+Класс содержит три конструктора, обозначенных комментариями в коде:
+
+1. Первичный конструктор, заданный `name` и `govtId` в определении класса
+2. Вспомогательный конструктор с параметрами `name`, `govtId` и `applicationDate`
+3. Другой вспомогательный конструктор с параметрами `name`, `govtId` и `studentId`
+
+Эти конструкторы можно вызывать следующим образом:
+
+{% tabs structor_2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+val s1 = new Student("Mary", "123")
+val s2 = new Student("Mary", "123", LocalDate.now)
+val s3 = new Student("Mary", "123", 456)
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+val s1 = Student("Mary", "123")
+val s2 = Student("Mary", "123", LocalDate.now)
+val s3 = Student("Mary", "123", 456)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Хотя этот метод можно использовать, имейте в виду, что параметры конструктора также могут иметь значения по умолчанию,
+из-за чего создается впечатление, что класс содержит несколько конструкторов.
+Это показано в предыдущем примере `Socket`.
+
+## Объекты
+
+Объект — это класс, который имеет ровно один экземпляр.
+Инициализируется он лениво, тогда, когда на его элементы ссылаются, подобно `lazy val`.
+Объекты в Scala позволяют группировать методы и поля в одном пространстве имен, аналогично тому,
+как вы используете `static` члены в классе в Java, Javascript (ES6) или `@staticmethod` в Python.
+
+Объявление `object` аналогично объявлению `class`.
+Вот пример объекта “строковые утилиты”, который содержит набор методов для работы со строками:
+
+{% tabs object_1 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+object StringUtils {
+ def truncate(s: String, length: Int): String = s.take(length)
+ def containsWhitespace(s: String): Boolean = s.matches(".*\\s.*")
+ def isNullOrEmpty(s: String): Boolean = s == null || s.trim.isEmpty
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+object StringUtils:
+ def truncate(s: String, length: Int): String = s.take(length)
+ def containsWhitespace(s: String): Boolean = s.matches(".*\\s.*")
+ def isNullOrEmpty(s: String): Boolean = s == null || s.trim.isEmpty
+```
+
+{% endtab %}
+{% endtabs %}
+
+Мы можем использовать объект следующим образом:
+
+{% tabs object_2 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+StringUtils.truncate("Chuck Bartowski", 5) // "Chuck"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Импорт в Scala очень гибкий и позволяет импортировать _все_ члены объекта:
+
+{% tabs object_3 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+import StringUtils._
+truncate("Chuck Bartowski", 5) // "Chuck"
+containsWhitespace("Sarah Walker") // true
+isNullOrEmpty("John Casey") // false
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+import StringUtils.*
+truncate("Chuck Bartowski", 5) // "Chuck"
+containsWhitespace("Sarah Walker") // true
+isNullOrEmpty("John Casey") // false
+```
+
+{% endtab %}
+{% endtabs %}
+
+или только _некоторые_:
+
+{% tabs object_4 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+import StringUtils.{truncate, containsWhitespace}
+truncate("Charles Carmichael", 7) // "Charles"
+containsWhitespace("Captain Awesome") // true
+isNullOrEmpty("Morgan Grimes") // Not found: isNullOrEmpty (error)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Объекты также могут содержать поля, доступ к которым также осуществляется как к статическим элементам:
+
+{% tabs object_5 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+object MathConstants {
+ val PI = 3.14159
+ val E = 2.71828
+}
+
+println(MathConstants.PI) // 3.14159
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+object MathConstants:
+ val PI = 3.14159
+ val E = 2.71828
+
+println(MathConstants.PI) // 3.14159
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Сопутствующие объекты
+
+Объект `object`, имеющий то же имя, что и класс, и объявленный в том же файле, что и класс,
+называется _"сопутствующим объектом"_. Точно так же соответствующий класс называется сопутствующим классом объекта.
+Сопутствующие класс или объект могут получить доступ к закрытым членам своего “соседа”.
+
+Сопутствующие объекты используются для методов и значений, не относящихся к экземплярам сопутствующего класса.
+Например, в следующем примере у класса `Circle` есть элемент с именем `area`, специфичный для каждого экземпляра,
+а у его сопутствующего объекта есть метод с именем `calculateArea`,
+который (а) не специфичен для экземпляра и (б) доступен для каждого экземпляра:
+
+{% tabs companion class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+import scala.math._
+
+class Circle(val radius: Double) {
+ def area: Double = Circle.calculateArea(radius)
+}
+
+object Circle {
+ private def calculateArea(radius: Double): Double = Pi * pow(radius, 2.0)
+}
+
+val circle1 = new Circle(5.0)
+circle1.area
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+import scala.math.*
+
+class Circle(val radius: Double):
+ def area: Double = Circle.calculateArea(radius)
+
+object Circle:
+ private def calculateArea(radius: Double): Double = Pi * pow(radius, 2.0)
+
+val circle1 = Circle(5.0)
+circle1.area
+```
+
+{% endtab %}
+{% endtabs %}
+
+В этом примере метод `area`, доступный для каждого экземпляра `Circle`,
+использует метод `calculateArea`, определенный в сопутствующем объекте.
+Кроме того, поскольку `calculateArea` является приватным, к нему нельзя получить доступ с помощью другого кода,
+но, как показано, его могут видеть экземпляры класса `Circle`.
+
+### Другие виды использования сопутствующих объектов
+
+Сопутствующие объекты могут использоваться для нескольких целей:
+
+- их можно использовать для группировки “статических” методов в пространстве имен, как в примере выше
+ - эти методы могут быть `public` или `private`
+ - если бы `calculateArea` был `public`, к нему можно было бы получить доступ из любого места как `Circle.calculateArea`
+- они могут содержать методы `apply`, которые — благодаря некоторому синтаксическому сахару —
+ работают как фабричные методы для создания новых экземпляров
+- они могут содержать методы `unapply`, которые используются для деконструкции объектов, например, с помощью сопоставления с шаблоном
+
+Вот краткий обзор того, как методы `apply` можно использовать в качестве фабричных методов для создания новых объектов:
+
+{% tabs companion-use class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+class Person {
+ var name = ""
+ var age = 0
+ override def toString = s"$name is $age years old"
+}
+
+object Person {
+ // фабричный метод с одним аргументом
+ def apply(name: String): Person = {
+ var p = new Person
+ p.name = name
+ p
+ }
+
+ // фабричный метод с двумя аргументами
+ def apply(name: String, age: Int): Person = {
+ var p = new Person
+ p.name = name
+ p.age = age
+ p
+ }
+}
+
+val joe = Person("Joe")
+val fred = Person("Fred", 29)
+
+//val joe: Person = Joe is 0 years old
+//val fred: Person = Fred is 29 years old
+```
+
+Метод `unapply` здесь не рассматривается, но описан в [Спецификации языка](https://scala-lang.org/files/archive/spec/2.13/08-pattern-matching.html#extractor-patterns).
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+class Person:
+ var name = ""
+ var age = 0
+ override def toString = s"$name is $age years old"
+
+object Person:
+
+ // фабричный метод с одним аргументом
+ def apply(name: String): Person =
+ var p = new Person
+ p.name = name
+ p
+
+ // фабричный метод с двумя аргументами
+ def apply(name: String, age: Int): Person =
+ var p = new Person
+ p.name = name
+ p.age = age
+ p
+
+end Person
+
+val joe = Person("Joe")
+val fred = Person("Fred", 29)
+
+//val joe: Person = Joe is 0 years old
+//val fred: Person = Fred is 29 years old
+```
+
+Метод `unapply` здесь не рассматривается, но описан в [справочной документации]({{ site.scala3ref }}/changed-features/pattern-matching.html).
+
+{% endtab %}
+{% endtabs %}
+
+## Трейты
+
+Если провести аналогию с Java, то Scala `trait` похож на интерфейс в Java 8+.
+Trait-ы могут содержать:
+
+- абстрактные методы и поля
+- конкретные методы и поля
+
+В базовом использовании `trait` может использоваться как интерфейс, определяющий только абстрактные члены,
+которые будут реализованы другими классами:
+
+{% tabs traits_1 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait Employee {
+ def id: Int
+ def firstName: String
+ def lastName: String
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+trait Employee:
+ def id: Int
+ def firstName: String
+ def lastName: String
+```
+
+{% endtab %}
+{% endtabs %}
+
+Однако трейты также могут содержать конкретные члены.
+Например, следующий трейт определяет два абстрактных члена — `numLegs` и `walk()` —
+а также имеет конкретную реализацию метода `stop()`:
+
+{% tabs traits_2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait HasLegs {
+ def numLegs: Int
+ def walk(): Unit
+ def stop() = println("Stopped walking")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+trait HasLegs:
+ def numLegs: Int
+ def walk(): Unit
+ def stop() = println("Stopped walking")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Вот еще один трейт с абстрактным членом и двумя конкретными реализациями:
+
+{% tabs traits_3 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait HasTail {
+ def tailColor: String
+ def wagTail() = println("Tail is wagging")
+ def stopTail() = println("Tail is stopped")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+trait HasTail:
+ def tailColor: String
+ def wagTail() = println("Tail is wagging")
+ def stopTail() = println("Tail is stopped")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Обратите внимание, что каждый трейт обрабатывает только очень специфичные атрибуты и поведение:
+`HasLegs` имеет дело только с "лапами", а `HasTail` имеет дело только с функциональностью, связанной с хвостом.
+Трейты позволяют создавать такие небольшие модули.
+
+Позже в вашем коде классы могут смешивать несколько трейтов для создания более крупных компонентов:
+
+{% tabs traits_4 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+class IrishSetter(name: String) extends HasLegs with HasTail {
+ val numLegs = 4
+ val tailColor = "Red"
+ def walk() = println("I’m walking")
+ override def toString = s"$name is a Dog"
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+class IrishSetter(name: String) extends HasLegs, HasTail:
+ val numLegs = 4
+ val tailColor = "Red"
+ def walk() = println("I’m walking")
+ override def toString = s"$name is a Dog"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Обратите внимание, что класс `IrishSetter` реализует абстрактные члены, определенные в `HasLegs` и `HasTail`.
+Теперь вы можете создавать новые экземпляры `IrishSetter`:
+
+{% tabs traits_5 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+val d = new IrishSetter("Big Red") // "Big Red is a Dog"
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+val d = IrishSetter("Big Red") // "Big Red is a Dog"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Это всего лишь пример того, чего можно добиться с помощью trait-ов.
+Дополнительные сведения см. в остальных уроках по моделированию.
+
+## Абстрактные классы
+
+Когда необходимо написать класс, но известно, что в нем будут абстрактные члены, можно создать либо `trait`, либо абстрактный класс.
+В большинстве случаев желательно использовать `trait`, но исторически сложилось так, что было две ситуации,
+когда предпочтительнее использование абстрактного класса:
+
+- необходимо создать базовый класс, который принимает аргументы конструктора
+- код будет вызван из Java-кода
+
+### Базовый класс, который принимает аргументы конструктора
+
+До Scala 3, когда базовому классу нужно было принимать аргументы конструктора, он объявлялся как `abstract class`:
+
+{% tabs abstract_1 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+abstract class Pet(name: String) {
+ def greeting: String
+ def age: Int
+ override def toString = s"My name is $name, I say $greeting, and I’m $age"
+}
+
+class Dog(name: String, var age: Int) extends Pet(name) {
+ val greeting = "Woof"
+}
+
+val d = new Dog("Fido", 1)
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+abstract class Pet(name: String):
+ def greeting: String
+ def age: Int
+ override def toString = s"My name is $name, I say $greeting, and I’m $age"
+
+class Dog(name: String, var age: Int) extends Pet(name):
+ val greeting = "Woof"
+
+val d = Dog("Fido", 1)
+```
+
+{% endtab %}
+{% endtabs %}
+
+
Параметры в trait только в Scala 3
+
+Однако в Scala 3 трейты теперь могут иметь [параметры][trait-params],
+так что теперь вы можете использовать трейты в той же ситуации:
+
+{% tabs abstract_2 %}
+
+{% tab 'Только в Scala 3' %}
+
+```scala
+trait Pet(name: String):
+ def greeting: String
+ def age: Int
+ override def toString = s"My name is $name, I say $greeting, and I’m $age"
+
+class Dog(name: String, var age: Int) extends Pet(name):
+ val greeting = "Woof"
+
+val d = Dog("Fido", 1)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Trait-ы более гибки в составлении, потому что можно смешивать (наследовать) несколько trait-ов, но только один класс.
+В большинстве случаев trait-ы следует предпочитать классам и абстрактным классам.
+Правило выбора состоит в том, чтобы использовать классы всякий раз, когда необходимо создавать экземпляры определенного типа,
+и trait-ы, когда желательно разложить и повторно использовать поведение.
+
+
Перечисления только в Scala 3
+
+Перечисление (_an enumeration_) может быть использовано для определения типа,
+состоящего из конечного набора именованных значений (в разделе, посвященном [моделированию ФП][fp-modeling],
+будут показаны дополнительные возможности перечислений).
+Базовые перечисления используются для определения наборов констант,
+таких как месяцы в году, дни в неделе, направления, такие как север/юг/восток/запад, и многое другое.
+
+В качестве примера, рассмотрим перечисления, определяющие наборы атрибутов, связанных с пиццами:
+
+{% tabs enum_1 %}
+{% tab 'Только в Scala 3' %}
+
+```scala
+enum CrustSize:
+ case Small, Medium, Large
+
+enum CrustType:
+ case Thin, Thick, Regular
+
+enum Topping:
+ case Cheese, Pepperoni, BlackOlives, GreenOlives, Onions
+```
+
+{% endtab %}
+{% endtabs %}
+
+Для использования в коде в первую очередь перечисление нужно импортировать, а затем - использовать:
+
+{% tabs enum_2 %}
+{% tab 'Только в Scala 3' %}
+
+```scala
+import CrustSize.*
+val currentCrustSize = Small
+```
+
+{% endtab %}
+{% endtabs %}
+
+Значения перечислений можно сравнивать (`==`) и использовать в сопоставлении:
+
+{% tabs enum_3 %}
+{% tab 'Только в Scala 3' %}
+
+```scala
+// if/then
+if currentCrustSize == Large then
+ println("You get a prize!")
+
+// match
+currentCrustSize match
+ case Small => println("small")
+ case Medium => println("medium")
+ case Large => println("large")
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Дополнительные функции перечисления
+
+Перечисления также могут быть параметризованы:
+
+{% tabs enum_4 %}
+{% tab 'Только в Scala 3' %}
+
+```scala
+enum Color(val rgb: Int):
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+```
+
+{% endtab %}
+{% endtabs %}
+
+И они также могут содержать элементы (например, поля и методы):
+
+{% tabs enum_5 %}
+{% tab 'Только в Scala 3' %}
+
+```scala
+enum Planet(mass: Double, radius: Double):
+ private final val G = 6.67300E-11
+ def surfaceGravity = G * mass / (radius * radius)
+ def surfaceWeight(otherMass: Double) =
+ otherMass * surfaceGravity
+
+ case Mercury extends Planet(3.303e+23, 2.4397e6)
+ case Earth extends Planet(5.976e+24, 6.37814e6)
+ // далее идут остальные планеты ...
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Совместимость с перечислениями Java
+
+Если вы хотите использовать перечисления, определенные в Scala, как перечисления Java,
+то можете сделать это, расширив класс `java.lang.Enum` (импортированный по умолчанию) следующим образом:
+
+{% tabs enum_6 %}
+{% tab 'Только в Scala 3' %}
+
+```scala
+enum Color extends Enum[Color] { case Red, Green, Blue }
+```
+
+{% endtab %}
+{% endtabs %}
+
+Параметр типа берется из определения Java `enum` и должен совпадать с типом перечисления.
+Нет необходимости предоставлять аргументы конструктора (как определено в документации Java API) для `java.lang.Enum`
+при его расширении — компилятор генерирует их автоматически.
+
+После такого определения `Color` вы можете использовать его так же, как перечисление Java:
+
+````
+scala> Color.Red.compareTo(Color.Green)
+val res0: Int = -1
+````
+
+В разделе об [алгебраических типах данных][adts] и [справочной документации][ref-enums] перечисления рассматриваются более подробно.
+
+## Case class-ы
+
+Case class используются для моделирования неизменяемых структур данных.
+Возьмем следующий пример:
+
+{% tabs case-classes_1 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala:
+case class Person(name: String, relation: String)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Поскольку мы объявляем `Person` как `case class`, поля `name` и `relation` по умолчанию общедоступны и неизменяемы.
+Мы можем создавать экземпляры case классов следующим образом:
+
+{% tabs case-classes_2 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val christina = Person("Christina", "niece")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Обратите внимание, что поля не могут быть изменены:
+
+{% tabs case-classes_3 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+christina.name = "Fred" // ошибка: reassignment to val
+```
+
+{% endtab %}
+{% endtabs %}
+
+Поскольку предполагается, что поля case класса неизменяемы,
+компилятор Scala может сгенерировать для вас множество полезных методов:
+
+- Генерируется метод `unapply`, позволяющий выполнять сопоставление с образцом case класса (то есть `case Person(n, r) => ...`).
+- В классе генерируется метод `copy`, полезный для создания модифицированных копий экземпляра.
+- Генерируются методы `equals` и `hashCode`, использующие структурное равенство,
+ что позволяет использовать экземпляры case классов в `Map`-ах.
+- Генерируется дефолтный метод `toString`, полезный для отладки.
+
+Эти дополнительные функции показаны в следующем примере:
+
+{% tabs case-classes_4 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+// Case class-ы можно использовать в качестве шаблонов
+christina match {
+ case Person(n, r) => println("name is " + n)
+}
+
+// для вас генерируются методы `equals` и `hashCode`
+val hannah = Person("Hannah", "niece")
+christina == hannah // false
+
+// метод `toString`
+println(christina) // Person(Christina,niece)
+
+// встроенный метод `copy`
+case class BaseballTeam(name: String, lastWorldSeriesWin: Int)
+val cubs1908 = BaseballTeam("Chicago Cubs", 1908)
+val cubs2016 = cubs1908.copy(lastWorldSeriesWin = 2016)
+// в результате:
+// cubs2016: BaseballTeam = BaseballTeam(Chicago Cubs,2016)
+
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+// Case class-ы можно использовать в качестве шаблонов
+christina match
+ case Person(n, r) => println("name is " + n)
+
+// для вас генерируются методы `equals` и `hashCode`
+val hannah = Person("Hannah", "niece")
+christina == hannah // false
+
+// метод `toString`
+println(christina) // Person(Christina,niece)
+
+// встроенный метод `copy`
+case class BaseballTeam(name: String, lastWorldSeriesWin: Int)
+val cubs1908 = BaseballTeam("Chicago Cubs", 1908)
+val cubs2016 = cubs1908.copy(lastWorldSeriesWin = 2016)
+// в результате:
+// cubs2016: BaseballTeam = BaseballTeam(Chicago Cubs,2016)
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Поддержка функционального программирования
+
+Как уже упоминалось ранее, case class-ы поддерживают функциональное программирование (ФП):
+
+- ФП избегает изменения структур данных.
+ Поэтому поля конструктора по умолчанию имеют значение `val`.
+ Поскольку экземпляры case class не могут быть изменены, ими можно легко делиться, не опасаясь мутаций или условий гонки.
+- вместо изменения экземпляра можно использовать метод `copy` в качестве шаблона для создания нового (потенциально измененного) экземпляра.
+ Этот процесс можно назвать “обновлением по мере копирования”.
+- наличие автоматически сгенерированного метода `unapply` позволяет использовать case class в сопоставлении шаблонов.
+
+## Case object-ы
+
+Case object-ы относятся к объектам так же, как case class-ы относятся к классам:
+они предоставляют ряд автоматически генерируемых методов, чтобы сделать их более мощными.
+Case object-ы особенно полезны тогда, когда необходим одноэлементный объект,
+который нуждается в небольшой дополнительной функциональности,
+например, для использования с сопоставлением шаблонов в выражениях `match`.
+
+Case object-ы полезны, когда необходимо передавать неизменяемые сообщения.
+Например, представим проект музыкального проигрывателя, и создадим набор команд или сообщений:
+
+{% tabs case-objects_1 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+sealed trait Message
+case class PlaySong(name: String) extends Message
+case class IncreaseVolume(amount: Int) extends Message
+case class DecreaseVolume(amount: Int) extends Message
+case object StopPlaying extends Message
+```
+
+{% endtab %}
+{% endtabs %}
+
+Затем в других частях кода можно написать методы, которые используют сопоставление с образцом
+для обработки входящего сообщения
+(при условии, что методы `playSong`, `changeVolume` и `stopPlayingSong` определены где-то еще):
+
+{% tabs case-objects_2 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+def handleMessages(message: Message): Unit = message match {
+ case PlaySong(name) => playSong(name)
+ case IncreaseVolume(amount) => changeVolume(amount)
+ case DecreaseVolume(amount) => changeVolume(-amount)
+ case StopPlaying => stopPlayingSong()
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+def handleMessages(message: Message): Unit = message match
+ case PlaySong(name) => playSong(name)
+ case IncreaseVolume(amount) => changeVolume(amount)
+ case DecreaseVolume(amount) => changeVolume(-amount)
+ case StopPlaying => stopPlayingSong()
+```
+
+{% endtab %}
+{% endtabs %}
+
+[ref-enums]: {{ site.scala3ref }}/enums/enums.html
+[adts]: {% link _overviews/scala3-book/types-adts-gadts.md %}
+[fp-modeling]: {% link _overviews/scala3-book/domain-modeling-fp.md %}
+[creator]: {{ site.scala3ref }}/other-new-features/creator-applications.html
+[unapply]: {{ site.scala3ref }}/changed-features/pattern-matching.html
+[trait-params]: {{ site.scala3ref }}/other-new-features/trait-parameters.html
diff --git a/_ru/scala3/book/first-look-at-types.md b/_ru/scala3/book/first-look-at-types.md
new file mode 100644
index 0000000000..5873df07f7
--- /dev/null
+++ b/_ru/scala3/book/first-look-at-types.md
@@ -0,0 +1,354 @@
+---
+layout: multipage-overview
+title: Первый взгляд на типы
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: На этой странице представлено краткое введение во встроенные типы данных Scala, включая Int, Double, String, Long, Any, AnyRef, Nothing и Null.
+language: ru
+num: 17
+previous-page: taste-summary
+next-page: string-interpolation
+---
+
+## Все значения имеют тип
+
+В Scala все значения имеют тип, включая числовые значения и функции.
+На приведенной ниже диаграмме показано подмножество иерархии типов.
+
+
+
+## Иерархия типов Scala
+
+`Any` - это супертип всех типов, также называемый **верхним типом** (**the top type**).
+Он определяет универсальные методы, такие как `equals`, `hashCode` и `toString`.
+
+У верхнего типа `Any` есть подтип [`Matchable`][matchable], который используется для обозначения всех типов,
+для которых возможно выполнить pattern matching (сопоставление с образцом).
+Важно гарантировать вызов свойства _“параметричность”_, что вкратце означает,
+что мы не можем сопоставлять шаблоны для значений типа `Any`, а только для значений, которые являются подтипом `Matchable`.
+[Справочная документация][matchable] содержит более подробную информацию о `Matchable`.
+
+`Matchable` содержит два важных подтипа: `AnyVal` и `AnyRef`.
+
+_`AnyVal`_ представляет типы значений.
+Существует несколько предопределенных типов значений, и они non-nullable:
+`Double`, `Float`, `Long`, `Int`, `Short`, `Byte`, `Char`, `Unit` и `Boolean`.
+`Unit` - это тип значения, который не несет никакой значимой информации. Существует ровно один экземпляр `Unit` - `()`.
+
+_`AnyRef`_ представляет ссылочные типы. Все типы, не являющиеся значениями, определяются как ссылочные типы.
+Каждый пользовательский тип в Scala является подтипом `AnyRef`.
+Если Scala используется в контексте среды выполнения Java, `AnyRef` соответствует `java.lang.Object`.
+
+В языках, основанных на операторах, `void` используется для методов, которые ничего не возвращают.
+В Scala для методов, которые не имеют возвращаемого значения,
+такие как следующий метод, для той же цели используется `Unit`:
+
+{% tabs unit %}
+{% tab 'Scala 2 и 3' for=unit %}
+
+```scala
+def printIt(a: Any): Unit = println(a)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Вот пример, демонстрирующий, что строки, целые числа, символы, логические значения и функции являются экземплярами `Any`
+и могут обрабатываться так же, как и любой другой объект:
+
+{% tabs any %}
+{% tab 'Scala 2 и 3' for=any %}
+
+```scala
+val list: List[Any] = List(
+ "a string",
+ 732, // число
+ 'c', // буква
+ '\'', // Экранированный символ
+ true, // булево значение
+ () => "an anonymous function returning a string"
+)
+
+list.foreach(element => println(element))
+```
+
+{% endtab %}
+{% endtabs %}
+
+Код определяет список значений типа `List[Any]`.
+Список инициализируется элементами различных типов, но каждый из них является экземпляром `scala.Any`,
+поэтому мы можем добавить их в список.
+
+Вот вывод программы:
+
+```
+a string
+732
+c
+'
+true
+
+```
+
+## Типы значений в Scala
+
+Как показано выше, числовые типы Scala расширяют `AnyVal`, и все они являются полноценными объектами.
+В этих примерах показано, как объявлять переменные этих числовых типов:
+
+{% tabs anyval %}
+{% tab 'Scala 2 и 3' for=anyval %}
+
+```scala
+val b: Byte = 1
+val i: Int = 1
+val l: Long = 1
+val s: Short = 1
+val d: Double = 2.0
+val f: Float = 3.0
+```
+
+{% endtab %}
+{% endtabs %}
+
+В первых четырех примерах, если явно не указать тип, то тип числа `1` по умолчанию будет равен `Int`,
+поэтому, если нужен один из других типов данных — `Byte`, `Long` или `Short` — необходимо явно объявить эти типы.
+Числа с десятичной дробью (например, `2.0`) по умолчанию будут иметь тип `Double`,
+поэтому, если необходим `Float`, нужно объявить `Float` явно, как показано в последнем примере.
+
+Поскольку `Int` и `Double` являются числовыми типами по умолчанию, их можно создавать без явного объявления типа данных:
+
+{% tabs anynum %}
+{% tab 'Scala 2 и 3' for=anynum %}
+
+```scala
+val i = 123 // по умолчанию Int
+val x = 1.0 // по умолчанию Double
+```
+
+{% endtab %}
+{% endtabs %}
+
+Также можно добавить символы `L`, `D`, and `F` (или их эквивалент в нижнем регистре)
+для того, чтобы задать `Long`, `Double` или `Float` значения:
+
+{% tabs type-post %}
+{% tab 'Scala 2 и 3' for=type-post %}
+
+```scala
+val x = 1_000L // val x: Long = 1000
+val y = 2.2D // val y: Double = 2.2
+val z = -3.3F // val z: Float = -3.3
+```
+
+Вы также можете использовать шестнадцатеричное представление для форматирования целых чисел
+(обычно это `Int`, но также поддерживается суффикс `L` для указания `Long`):
+
+```scala
+val a = 0xACE // val a: Int = 2766
+val b = 0xfd_3aL // val b: Long = 64826
+```
+
+Scala поддерживает множество различных способов форматирования одного и того же числа с плавающей запятой,
+например:
+
+```scala
+val q = .25 // val q: Double = 0.25
+val r = 2.5e-1 // val r: Double = 0.25
+val s = .0025e2F // val s: Float = 0.25
+```
+
+{% endtab %}
+{% endtabs %}
+
+В Scala также есть типы `String` и `Char`, которые обычно можно объявить в неявной форме:
+
+{% tabs type-string %}
+{% tab 'Scala 2 и 3' for=type-string %}
+
+```scala
+val s = "Bill"
+val c = 'a'
+```
+
+{% endtab %}
+{% endtabs %}
+
+Как показано, заключайте строки в двойные кавычки или тройные кавычки для многострочных строк,
+а одиночный символ заключайте в одинарные кавычки.
+
+Типы данных и их диапазоны:
+
+| Тип данных | Возможные значения |
+| ---------- | ------------------------------------------------------------------------------------------------------------------------------ |
+| Boolean | `true` или `false` |
+| Byte | 8-битное целое число в дополнении до двух со знаком (от -2^7 до 2^7-1 включительно) от -128 до 127 |
+| Short | 16-битное целое число в дополнении до двух со знаком (от -2^15 до 2^15-1 включительно) от -32 768 до 32 767 |
+| Int | 32-битное целое число с дополнением до двух со знаком (от -2^31 до 2^31-1 включительно) от -2 147 483 648 до 2 147 483 647 |
+| Long | 64-битное целое число с дополнением до двух со знаком (от -2^63 до 2^63-1 включительно) (от -2^63 до 2^63-1 включительно) |
+| Float | 32-разрядный IEEE 754 одинарной точности с плавающей точкой от 1,40129846432481707e-45 до 3,40282346638528860e+38 |
+| Double | 64-битный IEEE 754 двойной точности с плавающей запятой от 4,94065645841246544e-324 до 1,79769313486231570e+308 |
+| Char | 16-битный символ Unicode без знака (от 0 до 2^16-1 включительно) от 0 до 65 535 |
+| String | последовательность `Char` |
+
+## Строки
+
+Строки Scala похожи на строки Java,
+хотя в отличие от Java (по крайней мере, до Java 15)
+в Scala легко создавать многострочные строки с тройными кавычками:
+
+{% tabs string-mlines1 %}
+{% tab 'Scala 2 и 3' for=string-mlines1 %}
+
+```scala
+val quote = """The essence of Scala:
+ Fusion of functional and object-oriented
+ programming in a typed setting."""
+```
+
+{% endtab %}
+{% endtabs %}
+
+Одним из недостатков этого базового подхода является то,
+что строки после первой строки содержат отступ и выглядят следующим образом:
+
+{% tabs string-mlines2 %}
+{% tab 'Scala 2 и 3' for=string-mlines2 %}
+
+```scala
+"The essence of Scala:
+ Fusion of functional and object-oriented
+ programming in a typed setting."
+```
+
+{% endtab %}
+{% endtabs %}
+
+Если важно исключить отступ, можно поставить символ `|` перед всеми строками после первой
+и вызвать метод `stripMargin` после строки:
+
+{% tabs string-mlines3 %}
+{% tab 'Scala 2 и 3' for=string-mlines3 %}
+
+```scala
+val quote = """The essence of Scala:
+ |Fusion of functional and object-oriented
+ |programming in a typed setting.""".stripMargin
+```
+
+{% endtab %}
+{% endtabs %}
+
+Теперь все строки выравниваются по левому краю:
+
+{% tabs string-mlines4 %}
+{% tab 'Scala 2 и 3' for=string-mlines4 %}
+
+```scala
+"The essence of Scala:
+Fusion of functional and object-oriented
+programming in a typed setting."
+```
+
+{% endtab %}
+{% endtabs %}
+
+Строки Scala также поддерживают мощные методы интерполяции строк,
+о которых мы поговорим [в следующей главе][string-interpolation].
+
+## `BigInt` и `BigDecimal`
+
+Для действительно больших чисел можно использовать типы `BigInt` и `BigDecimal`:
+
+{% tabs type-bigint %}
+{% tab 'Scala 2 и 3' for=type-bigint %}
+
+```scala
+val a = BigInt(1_234_567_890_987_654_321L)
+val b = BigDecimal(123456.789)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Где `Double` и `Float` являются приблизительными десятичными числами,
+а `BigDecimal` используется для точной арифметики, например, при работе с валютой.
+
+`BigInt` и `BigDecimal` поддерживают все привычные числовые операторы:
+
+{% tabs type-bigint2 %}
+{% tab 'Scala 2 и 3' for=type-bigint2 %}
+
+```scala
+val b = BigInt(1234567890) // scala.math.BigInt = 1234567890
+val c = b + b // scala.math.BigInt = 2469135780
+val d = b * b // scala.math.BigInt = 1524157875019052100
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Приведение типов
+
+Типы значений могут быть приведены следующим образом:
+
+
+
+Например:
+
+{% tabs cast1 %}
+{% tab 'Scala 2 и 3' for=cast1 %}
+
+```scala
+val b: Byte = 127
+val i: Int = b // 127
+
+val face: Char = '☺'
+val number: Int = face // 9786
+```
+
+{% endtab %}
+{% endtabs %}
+
+Вы можете привести к типу, только если нет потери информации.
+В противном случае вам нужно четко указать приведение типов:
+
+{% tabs cast2 %}
+{% tab 'Scala 2 и 3' for=cast2 %}
+
+```scala
+val x: Long = 987654321
+val y: Float = x.toFloat // 9.8765434E8 (обратите внимание, что требуется `.toFloat`, потому что приведение приводит к потере точности)
+val z: Long = y // Ошибка
+```
+
+{% endtab %}
+{% endtabs %}
+
+Вы также можете привести ссылочный тип к подтипу.
+Это будет рассмотрено в книге позже.
+
+## `Nothing` и `null`
+
+`Nothing` является подтипом всех типов, также называемым **нижним типом** (**the bottom type**).
+Нет значения, которое имело бы тип `Nothing`.
+Он обычно сигнализирует о прекращении, таком как thrown exception, выходе из программы или бесконечном цикле -
+т.е. это тип выражения, который не вычисляется до определенного значения, или метод, который нормально не возвращается.
+
+`Null` - это подтип всех ссылочных типов (т.е. любой подтип `AnyRef`).
+Он имеет единственное значение, определяемое ключевым словом `null`.
+В настоящее время применение `null` считается плохой практикой.
+Его следует использовать в основном для взаимодействия с другими языками JVM.
+Опция компилятора `opt-in` изменяет статус `Null`, делая все ссылочные типы non-nullable.
+Этот параметр может [стать значением по умолчанию][safe-null] в будущей версии Scala.
+
+В то же время `null` почти никогда не следует использовать в коде Scala.
+Альтернативы `null` обсуждаются в главе о [функциональном программировании][fp] и в [документации API][option-api].
+
+[reference]: {{ site.scala3ref }}/overview.html
+[matchable]: {{ site.scala3ref }}/other-new-features/matchable.html
+[fp]: {% link _overviews/scala3-book/fp-intro.md %}
+[string-interpolation]: {% link _overviews/scala3-book/string-interpolation.md %}
+[option-api]: https://scala-lang.org/api/3.x/scala/Option.html
+[safe-null]: {{ site.scala3ref }}/experimental/explicit-nulls.html
diff --git a/_ru/scala3/book/fp-functional-error-handling.md b/_ru/scala3/book/fp-functional-error-handling.md
new file mode 100644
index 0000000000..ca3f7857eb
--- /dev/null
+++ b/_ru/scala3/book/fp-functional-error-handling.md
@@ -0,0 +1,436 @@
+---
+layout: multipage-overview
+title: Функциональная обработка ошибок
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлено введение в функциональную обработку ошибок в Scala 3.
+language: ru
+num: 46
+previous-page: fp-functions-are-values
+next-page: fp-summary
+---
+
+
+
+Функциональное программирование похоже на написание ряда алгебраических уравнений,
+и поскольку алгебра не имеет null значений или исключений, они не используются и в ФП.
+Что поднимает интересный вопрос: как быть в ситуациях, в которых вы обычно используете null значение или исключение программируя в ООП стиле?
+
+Решение Scala заключается в использовании конструкций, основанных на классах типа `Option`/`Some`/`None`.
+Этот урок представляет собой введение в использование такого подхода.
+
+Примечание:
+
+- классы `Some` и `None` являются подклассами `Option`
+- вместо того чтобы многократно повторять “`Option`/`Some`/`None`”,
+ следующий текст обычно просто ссылается на “`Option`” или на “классы `Option`”
+
+
+## Первый пример
+
+Хотя этот первый пример не имеет дело с `null` значениями, это хороший способ познакомиться с классами `Option`.
+
+Представим, что нужно написать метод, который упрощает преобразование строк в целочисленные значения.
+И нужен элегантный способ обработки исключения, которое возникает,
+когда метод получает строку типа `"Hello"` вместо `"1"`.
+Первое предположение о таком методе может выглядеть следующим образом:
+
+{% tabs fp-java-try class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+def makeInt(s: String): Int =
+ try {
+ Integer.parseInt(s.trim)
+ } catch {
+ case e: Exception => 0
+ }
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+def makeInt(s: String): Int =
+ try
+ Integer.parseInt(s.trim)
+ catch
+ case e: Exception => 0
+```
+{% endtab %}
+
+{% endtabs %}
+
+Если преобразование работает, метод возвращает правильное значение `Int`, но в случае сбоя метод возвращает `0`.
+Для некоторых целей это может быть хорошо, но не совсем точно.
+Например, метод мог получить `"0"`, но мог также получить `"foo"`, `"bar"`
+или бесконечное количество других строк, которые выдадут исключение.
+Это реальная проблема: как определить, когда метод действительно получил `"0"`, а когда получил что-то еще?
+При таком подходе нет способа узнать правильный ответ наверняка.
+
+
+## Использование Option/Some/None
+
+Распространенным решением этой проблемы в Scala является использование классов,
+известных как `Option`, `Some` и `None`.
+Классы `Some` и `None` являются подклассами `Option`, поэтому решение работает следующим образом:
+
+- объявляется, что `makeInt` возвращает тип `Option`
+- если `makeInt` получает строку, которую он _может_ преобразовать в `Int`, ответ помещается внутрь `Some`
+- если `makeInt` получает строку, которую _не может_ преобразовать, то возвращает `None`
+
+Вот доработанная версия `makeInt`:
+
+{% tabs fp--try-option class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+def makeInt(s: String): Option[Int] =
+ try {
+ Some(Integer.parseInt(s.trim))
+ } catch {
+ case e: Exception => None
+ }
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+def makeInt(s: String): Option[Int] =
+ try
+ Some(Integer.parseInt(s.trim))
+ catch
+ case e: Exception => None
+```
+{% endtab %}
+
+{% endtabs %}
+
+Этот код можно прочитать следующим образом:
+“Когда данная строка преобразуется в целое число, верните значение `Int`, заключенное в `Some`, например `Some(1)`.
+Когда строка не может быть преобразована в целое число и генерируется исключение, метод возвращает значение `None`.”
+
+Эти примеры показывают, как работает `makeInt`:
+
+{% tabs fp-try-option-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val a = makeInt("1") // Some(1)
+val b = makeInt("one") // None
+```
+{% endtab %}
+
+{% endtabs %}
+
+Как показано, строка `"1"` приводится к `Some(1)`, а строка `"one"` - к `None`.
+В этом суть альтернативного подхода к обработке ошибок.
+Данная техника используется для того, чтобы методы могли возвращать _значения_ вместо _исключений_.
+В других ситуациях значения `Option` также используются для замены `null` значений.
+
+Примечание:
+
+- этот подход используется во всех классах библиотеки Scala, а также в сторонних библиотеках Scala.
+- ключевым моментом примера является то, что функциональные методы не генерируют исключения;
+ вместо этого они возвращают такие значения, как `Option`.
+
+
+## Потребитель makeInt
+
+Теперь представим, что мы являемся потребителем метода `makeInt`.
+Известно, что он возвращает подкласс `Option[Int]`, поэтому возникает вопрос:
+как работать с такими возвращаемыми типами?
+
+Есть два распространенных ответа, в зависимости от потребностей:
+
+- использование `match` выражений
+- использование `for` выражений
+
+## Использование `match` выражений
+
+Одним из возможных решений является использование выражения `match`:
+
+{% tabs fp-option-match class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+makeInt(x) match {
+ case Some(i) => println(i)
+ case None => println("That didn’t work.")
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+makeInt(x) match
+ case Some(i) => println(i)
+ case None => println("That didn’t work.")
+```
+{% endtab %}
+
+{% endtabs %}
+
+В этом примере, если `x` можно преобразовать в `Int`, вычисляется первый вариант в правой части предложения `case`;
+если `x` не может быть преобразован в `Int`, вычисляется второй вариант в правой части предложения `case`.
+
+
+## Использование `for` выражений
+
+Другим распространенным решением является использование выражения `for`, то есть комбинации `for`/`yield`.
+Например, представим, что необходимо преобразовать три строки в целочисленные значения, а затем сложить их.
+Решение задачи с использованием выражения `for`:
+
+{% tabs fp-for-comprehension class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+val y = for {
+ a <- makeInt(stringA)
+ b <- makeInt(stringB)
+ c <- makeInt(stringC)
+} yield {
+ a + b + c
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val y = for
+ a <- makeInt(stringA)
+ b <- makeInt(stringB)
+ c <- makeInt(stringC)
+yield
+ a + b + c
+```
+{% endtab %}
+
+{% endtabs %}
+
+После выполнения этого выражения `y` может принять одно из двух значений:
+
+- если _все_ три строки конвертируются в значения `Int`, `y` будет равно `Some[Int]`, т.е. целым числом, обернутым внутри `Some`
+- если _какая-либо_ из трех строк не может быть преобразована в `Int`, `y` равен `None`
+
+Это можно проверить на примере:
+
+{% tabs fp-for-comprehension-evaluation class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+val stringA = "1"
+val stringB = "2"
+val stringC = "3"
+
+val y = for {
+ a <- makeInt(stringA)
+ b <- makeInt(stringB)
+ c <- makeInt(stringC)
+} yield {
+ a + b + c
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val stringA = "1"
+val stringB = "2"
+val stringC = "3"
+
+val y = for
+ a <- makeInt(stringA)
+ b <- makeInt(stringB)
+ c <- makeInt(stringC)
+yield
+ a + b + c
+```
+{% endtab %}
+
+{% endtabs %}
+
+С этими демонстрационными данными переменная `y` примет значение `Some(6)`.
+
+Чтобы увидеть негативный кейс, достаточно изменить любую из строк на что-то, что нельзя преобразовать в целое число.
+В этом случае `y` равно `None`:
+
+{% tabs fp-for-comprehension-failure-result %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+y: Option[Int] = None
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+## Восприятие Option, как контейнера
+
+Для лучшего восприятия `Option`, его можно представить как _контейнер_:
+
+- `Some` представляет собой контейнер с одним элементом
+- `None` не является контейнером, в нем ничего нет
+
+Если предпочтительнее думать об `Option` как о ящике, то `None` подобен пустому ящику.
+Что-то в нём могло быть, но нет.
+
+
+## Использование `Option` для замены `null`
+
+Возвращаясь к значениям `null`, место, где `null` значение может незаметно проникнуть в код, — класс, подобный этому:
+
+{% tabs fp=case-class-nulls %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+class Address(
+ var street1: String,
+ var street2: String,
+ var city: String,
+ var state: String,
+ var zip: String
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Хотя каждый адрес имеет значение `street1`, значение `street2` не является обязательным.
+В результате полю `street2` можно присвоить значение `null`:
+
+{% tabs fp-case-class-nulls-example class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+val santa = new Address(
+ "1 Main Street",
+ null, // <-- О! Значение null!
+ "North Pole",
+ "Alaska",
+ "99705"
+)
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val santa = Address(
+ "1 Main Street",
+ null, // <-- О! Значение null!
+ "North Pole",
+ "Alaska",
+ "99705"
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Исторически сложилось так, что в этой ситуации разработчики использовали пустые строки и значения `null`,
+оба варианта это “костыль” для решения основной проблемы: `street2` - _необязательное_ поле.
+В Scala и других современных языках правильное решение состоит в том,
+чтобы заранее объявить, что `street2` является необязательным:
+
+
+{% tabs fp-case-class-with-options %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+class Address(
+ var street1: String,
+ var street2: Option[String], // необязательное значение
+ var city: String,
+ var state: String,
+ var zip: String
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Теперь можно написать более точный код:
+
+{% tabs fp-case-class-with-options-example-none class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+val santa = new Address(
+ "1 Main Street",
+ None, // 'street2' не имеет значения
+ "North Pole",
+ "Alaska",
+ "99705"
+)
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val santa = Address(
+ "1 Main Street",
+ None, // 'street2' не имеет значения
+ "North Pole",
+ "Alaska",
+ "99705"
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+или так:
+
+{% tabs fp-case-class-with-options-example-some class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+val santa = new Address(
+ "123 Main Street",
+ Some("Apt. 2B"),
+ "Talkeetna",
+ "Alaska",
+ "99676"
+)
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val santa = Address(
+ "123 Main Street",
+ Some("Apt. 2B"),
+ "Talkeetna",
+ "Alaska",
+ "99676"
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+
+## `Option` — не единственное решение
+
+В этом разделе основное внимание уделялось `Option` классам, но у Scala есть несколько других альтернатив.
+
+Например, три класса, известные как `Try`/`Success`/`Failure`, работают также,
+но (а) эти классы в основном используются, когда код может генерировать исключения,
+и (б) когда желательно использовать класс `Failure`, потому что он дает доступ к сообщению об исключении.
+Например, классы `Try` обычно используются при написании методов, которые взаимодействуют с файлами,
+базами данных или интернет-службами, поскольку эти функции могут легко создавать исключения.
+
+
+## Краткое ревью
+
+Этот раздел был довольно большим, поэтому давайте подведем краткое ревью:
+
+- функциональные программисты не используют `null` значения
+- основной заменой `null` значениям является использование классов `Option`
+- функциональные методы не выдают исключений; вместо этого они возвращают такие значения, как `Option`, `Try` или `Either`
+- распространенными способами работы со значениями `Option` являются выражения `match` и `for`
+- `Option` можно рассматривать как контейнеры с одним элементом (`Some`) и без элементов (`None`)
+- `Option` также можно использовать для необязательных параметров конструктора или метода
diff --git a/_ru/scala3/book/fp-functions-are-values.md b/_ru/scala3/book/fp-functions-are-values.md
new file mode 100644
index 0000000000..9a6cd6c423
--- /dev/null
+++ b/_ru/scala3/book/fp-functions-are-values.md
@@ -0,0 +1,161 @@
+---
+layout: multipage-overview
+title: Функции — это значения
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе рассматривается использование функций в качестве значений в функциональном программировании.
+language: ru
+num: 45
+previous-page: fp-pure-functions
+next-page: fp-functional-error-handling
+---
+
+
+Хотя каждый когда-либо созданный язык программирования, вероятно, позволяет писать чистые функции,
+вторая важная особенность ФП на Scala заключается в том, что _функции можно создавать как значения_,
+точно так же, как создаются значения `String` и `Int`.
+
+Эта особенность даёт много преимуществ, опишем наиболее распространенные из них:
+(a) можно определять методы, принимающие в качестве параметров функции
+и (b) можно передавать функции в качестве параметров в методы.
+
+Такой подход можно было наблюдать в предыдущих главах, когда демонстрировались такие методы, как `map` и `filter`:
+
+{% tabs fp-function-as-values-anonymous %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val nums = (1 to 10).toList
+
+val doubles = nums.map(_ * 2) // удваивает каждое значение
+val lessThanFive = nums.filter(_ < 5) // List(1,2,3,4)
+```
+{% endtab %}
+
+{% endtabs %}
+
+В этих примерах анонимные функции передаются в `map` и `filter`.
+
+> Анонимные функции также известны как _лямбды_ (_lambdas_).
+
+Помимо передачи анонимных функций в `filter` и `map`, в них также можно передать _методы_:
+
+{% tabs fp-function-as-values-defined %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+// два метода
+def double(i: Int): Int = i * 2
+def underFive(i: Int): Boolean = i < 5
+
+// передача этих методов в filter и map
+val doubles = nums.filter(underFive).map(double)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Возможность обращаться с методами и функциями как со значениями — мощное свойство,
+предоставляемое языками функционального программирования.
+
+> Технически функция, которая принимает другую функцию в качестве входного параметра, известна как _функция высшего порядка_.
+> (Если вам нравится юмор, как кто-то однажды написал, это все равно, что сказать,
+> что класс, который принимает экземпляр другого класса в качестве параметра конструктора,
+> является классом высшего порядка.)
+
+
+## Функции, анонимные функции и методы
+
+В примерах выше анонимная функция это:
+
+{% tabs fp-anonymous-function-short %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+_ * 2
+```
+{% endtab %}
+
+{% endtabs %}
+
+Как было показано в обсуждении [функций высшего порядка][hofs], `_ * 2` - сокращенная версия синтаксиса:
+
+{% tabs fp-anonymous-function-full %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+(i: Int) => i * 2
+```
+{% endtab %}
+
+{% endtabs %}
+
+Такие функции называются “анонимными”, потому что им не присваивается определенное имя.
+Для того чтобы это имя задать, достаточно просто присвоить его переменной:
+
+{% tabs fp-function-assignement %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val double = (i: Int) => i * 2
+```
+{% endtab %}
+
+{% endtabs %}
+
+Теперь появилась именованная функция, назначенная переменной `double`.
+Можно использовать эту функцию так же, как используется метод:
+
+{% tabs fp-function-used-like-method %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+double(2) // 4
+```
+{% endtab %}
+
+{% endtabs %}
+
+В большинстве случаев не имеет значения, является ли `double` функцией или методом;
+Scala позволяет обращаться с ними одинаково.
+За кулисами технология Scala, которая позволяет обращаться с методами так же,
+как с функциями, известна как [Eta Expansion][eta].
+
+Эта способность беспрепятственно передавать функции в качестве переменных
+является отличительной чертой функциональных языков программирования, таких как Scala.
+И, как было видно на примерах `map` и `filter`,
+возможность передавать функции в другие функции помогает создавать код,
+который является кратким и при этом читабельным — _выразительным_.
+
+Вот еще несколько примеров:
+
+{% tabs fp-function-as-values-example %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+List("bob", "joe").map(_.toUpperCase) // List(BOB, JOE)
+List("bob", "joe").map(_.capitalize) // List(Bob, Joe)
+List("plum", "banana").map(_.length) // List(4, 6)
+
+val fruits = List("apple", "pear")
+fruits.map(_.toUpperCase) // List(APPLE, PEAR)
+fruits.flatMap(_.toUpperCase) // List(A, P, P, L, E, P, E, A, R)
+
+val nums = List(5, 1, 3, 11, 7)
+nums.map(_ * 2) // List(10, 2, 6, 22, 14)
+nums.filter(_ > 3) // List(5, 11, 7)
+nums.takeWhile(_ < 6) // List(5, 1, 3)
+nums.sortWith(_ < _) // List(1, 3, 5, 7, 11)
+nums.sortWith(_ > _) // List(11, 7, 5, 3, 1)
+
+nums.takeWhile(_ < 6).sortWith(_ < _) // List(1, 3, 5)
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+[hofs]: {% link _overviews/scala3-book/fun-hofs.md %}
+[eta]: {% link _overviews/scala3-book/fun-eta-expansion.md %}
diff --git a/_ru/scala3/book/fp-immutable-values.md b/_ru/scala3/book/fp-immutable-values.md
new file mode 100644
index 0000000000..53f63d0b26
--- /dev/null
+++ b/_ru/scala3/book/fp-immutable-values.md
@@ -0,0 +1,109 @@
+---
+layout: multipage-overview
+title: Неизменяемые значения
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе рассматривается использование неизменяемых значений в функциональном программировании.
+language: ru
+num: 43
+previous-page: fp-what-is-fp
+next-page: fp-pure-functions
+---
+
+В чистом функциональном программировании используются только неизменяемые значения.
+В Scala это означает:
+
+- все переменные создаются как поля `val`
+- используются только неизменяемые классы коллекций, такие как `List`, `Vector` и неизменяемые классы `Map` и `Set`
+
+Использование только неизменяемых переменных поднимает интересный вопрос: если все статично, как вообще что-то меняется?
+
+Когда дело доходит до использования коллекций, один из ответов заключается в том,
+что существующая коллекция не меняется; вместо этого функция применяется к коллекции, чтобы создать новую.
+Именно здесь вступают в действие функции высшего порядка, такие как `map` и `filter`.
+
+Например, представим, что есть список имен в нижнем регистре — `List[String]`,
+и необходимо найти все имена, начинающиеся с буквы `"j"`, чтобы затем сделать первые буквы заглавными.
+В ФП код будет выглядеть так:
+
+{% tabs fp-list %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val a = List("jane", "jon", "mary", "joe")
+val b = a.filter(_.startsWith("j"))
+ .map(_.capitalize)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Как показано, исходный список `a` не меняется.
+Вместо этого к `a` применяется функция фильтрации и преобразования, чтобы создать новую коллекцию,
+и результат присваивается неизменяемой переменной `b`.
+
+Точно так же в ФП не используются классы с изменяемыми параметрами конструктора `var`.
+В ФП создание такого класса не привествуется:
+
+{% tabs fp--class-variables %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+// не стоит этого делать в ФП
+class Person(var firstName: String, var lastName: String)
+ --- ---
+```
+{% endtab %}
+
+{% endtabs %}
+
+Вместо этого обычно создаются `case` классы, чьи параметры конструктора по умолчанию неизменяемые (`val`):
+
+{% tabs fp-immutable-case-class %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+case class Person(firstName: String, lastName: String)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Теперь можно создать экземпляр `Person` как поле `val`:
+
+{% tabs fp-case-class-creation %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val reginald = Person("Reginald", "Dwight")
+```
+{% endtab %}
+
+{% endtabs %}
+
+Затем, при необходимости внести изменения в данные, используется метод `copy`,
+который поставляется с `case` классом, чтобы “обновлять данные через создание копии”,
+например так:
+
+{% tabs fp-case-class-copy %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+val elton = reginald.copy(
+ firstName = "Elton", // обновить имя
+ lastName = "John" // обновить фамилию
+)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Существуют множество других приёмов работы с неизменяемыми коллекциями и переменными.
+
+> В зависимости от задач вместо `case` классов можно создавать перечисления, trait-ы или классы.
+> Для более подробной информации см. главу [“Моделирование данных”][modeling].
+
+
+[modeling]: {% link _overviews/scala3-book/domain-modeling-intro.md %}
diff --git a/_ru/scala3/book/fp-intro.md b/_ru/scala3/book/fp-intro.md
new file mode 100644
index 0000000000..5c9b3f5fad
--- /dev/null
+++ b/_ru/scala3/book/fp-intro.md
@@ -0,0 +1,30 @@
+---
+layout: multipage-overview
+title: Функциональное программирование
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: В этой главе представлено введение в функциональное программирование в Scala 3.
+language: ru
+num: 41
+previous-page: collections-summary
+next-page: fp-what-is-fp
+---
+
+Scala позволяет писать код в стиле объектно-ориентированного программирования (ООП),
+в стиле функционального программирования (ФП), а также в гибридном стиле, используя оба подхода в комбинации.
+По словам Martin Odersky,
+сущность Scala — это слияние функционального и объектно-ориентированного программирования в типизированной среде:
+
+- Функции для логики
+- Объекты для модульности
+
+В этой главе предполагается, что вы знакомы с ООП и менее знакомы с ФП,
+поэтому в ней представлено краткое введение в несколько основных концепций функционального программирования:
+
+- Что такое функциональное программирование?
+- Неизменяемые значения
+- Чистые функции
+- Функции — это значения
+- Функциональная обработка ошибок
diff --git a/_ru/scala3/book/fp-pure-functions.md b/_ru/scala3/book/fp-pure-functions.md
new file mode 100644
index 0000000000..47a277a858
--- /dev/null
+++ b/_ru/scala3/book/fp-pure-functions.md
@@ -0,0 +1,153 @@
+---
+layout: multipage-overview
+title: Чистые функции
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе рассматривается использование чистых функций в функциональном программировании.
+language: ru
+num: 44
+previous-page: fp-immutable-values
+next-page: fp-functions-are-values
+---
+
+
+Еще одна концепция, которую Scala предлагает для помощи в написании функционального кода, — это возможность писать чистые функции.
+_Чистая функция_ (_pure function_) может быть определена следующим образом:
+
+- функция `f` является чистой, если при одних и тех же входных данных `x` она всегда возвращает один и тот же результат `f(x)`
+- результат функции зависит _только_ от входных данных и её реализации
+- чистые функции только вычисляют результат, ничего не меняя за пределами этих функций
+
+Из этого следует:
+
+- чистая функция не изменяет свои входные параметры
+- она не мутирует какое-либо скрытое состояние
+- у неё нет “черных ходов”: он не читает данные из внешнего мира (включая консоль, веб-сервисы, базы данных, файлы и т.д.)
+ и не записывает данные вовне
+
+В результате этого определения каждый раз, когда вызывается чистая функция с одним и тем же входным значением (значениями),
+всегда будет выдаваться один и тот же результат.
+Например, можно вызывать функцию `double` бесконечное число раз с входным значением `2`, и всегда получать результат `4`.
+
+
+## Примеры чистых функций
+
+Учитывая это определение, методы в пакете `scala.math._` являются чистыми функциями:
+
+- `abs`
+- `ceil`
+- `max`
+
+Эти методы `String` также являются чистыми функциями:
+
+- `isEmpty`
+- `length`
+- `substring`
+
+Большинство методов в классах коллекций Scala также работают как чистые функции,
+включая `drop`, `filter`, `map` и многие другие.
+
+> В Scala _функции_ и _методы_ почти полностью взаимозаменяемы,
+> поэтому, хотя здесь используется общепринятый отраслевой термин “чистая функция”,
+> этот термин можно использовать как для описания функций, так и методов.
+> Как методы могут использоваться подобно функциям описано в главе [Eta расширение][eta].
+
+
+## Примеры “грязных” функций
+
+И наоборот, следующие функции “_грязные_” (_impure_), потому что они нарушают определение pure function:
+
+- `println` — методы, взаимодействующие с консолью, файлами, базами данных, веб-сервисами и т.д., “грязные”
+- `currentTimeMillis` — все методы, связанные с датой и временем, “грязные”,
+ потому что их вывод зависит от чего-то другого, кроме входных параметров
+- `sys.error` — методы генерации исключений “грязные”, потому что они не “просто возвращают результат”
+
+“Грязные” функции часто делают одно из следующего:
+
+- читают из скрытого состояния, т.е. обращаются к параметрам и данным,
+ не переданным в функцию явным образом в качестве входных параметров
+- запись в скрытое состояние
+- изменяют заданные им параметры или изменяют скрытые переменные, например, поля в содержащем их классе
+- выполняют какой-либо ввод-вывод с внешним миром
+
+> В общем, следует остерегаться функций с возвращаемым типом `Unit`.
+> Поскольку эти функции ничего не возвращают, логически единственная причина, по которой они когда-либо вызываются, -
+> это достижение какого-то побочного эффекта.
+> Как следствие, часто использование этих функций является “грязным”.
+
+
+## Но грязные функции все же необходимы ...
+
+Конечно, приложение не очень полезно, если оно не может читать или писать во внешний мир, поэтому рекомендуется следующее:
+
+> Напишите ядро вашего приложения, используя только “чистые” функции,
+> а затем напишите “грязную” “оболочку” вокруг этого ядра для взаимодействия с внешним миром.
+> Как кто-то однажды сказал, это все равно, что положить слой нечистой глазури на чистый торт.
+
+Важно отметить, что есть способы сделать “нечистое” взаимодействие с внешним миром более “чистым”.
+Например, можно услышать об использовании `IO` монады для обработки ввода-вывода.
+Эти темы выходят за рамки данного документа, поэтому для простоты можно думать,
+что ФП приложения имеют ядро из “чистых” функций,
+которые объединены с другими функциями для взаимодействия с внешним миром.
+
+
+## Написание “чистых” функций
+
+**Примечание**: в этом разделе для обозначения методов Scala часто используется общепринятый в отрасли термин “чистая функция”.
+
+Для написания чистых функций на Scala, достаточно писать их,
+используя синтаксис методов Scala (хотя также можно использовать и синтаксис функций Scala).
+Например, вот чистая функция, которая удваивает заданное ей входное значение:
+
+{% tabs fp-pure-function %}
+
+{% tab 'Scala 2 и 3' %}
+```scala
+def double(i: Int): Int = i * 2
+```
+{% endtab %}
+
+{% endtabs %}
+
+Вот чистая функция, которая вычисляет сумму списка целых чисел с использованием рекурсии:
+
+{% tabs fp-pure-recursive-function class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+```scala
+def sum(xs: List[Int]): Int = xs match {
+ case Nil => 0
+ case head :: tail => head + sum(tail)
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+def sum(xs: List[Int]): Int = xs match
+ case Nil => 0
+ case head :: tail => head + sum(tail)
+```
+{% endtab %}
+
+{% endtabs %}
+
+Вышеописанные функции соответствуют определению “чистых”.
+
+
+## Ключевые моменты
+
+Первым ключевым моментом этого раздела является определение чистой функции:
+
+> _Чистая функция_ — это функция, которая зависит только от своих объявленных входных данных
+> и своей реализации для получения результата.
+> Она только вычисляет свой результат, не завися от внешнего мира и не изменяя его.
+
+Второй ключевой момент заключается в том, что каждое реальное приложение взаимодействует с внешним миром.
+Таким образом, упрощенный способ представления о функциональных программах состоит в том,
+что они состоят из ядра чистых функций, которые обернуты другими функциями, взаимодействующими с внешним миром.
+
+
+[eta]: {% link _overviews/scala3-book/fun-eta-expansion.md %}
diff --git a/_ru/scala3/book/fp-summary.md b/_ru/scala3/book/fp-summary.md
new file mode 100644
index 0000000000..0e18a20356
--- /dev/null
+++ b/_ru/scala3/book/fp-summary.md
@@ -0,0 +1,31 @@
+---
+layout: multipage-overview
+title: Обзор
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: Этот раздел суммирует предыдущие разделы функционального программирования.
+language: ru
+num: 47
+previous-page: fp-functional-error-handling
+next-page: types-introduction
+---
+
+
+В этой главе представлено общее введение в функциональное программирование на Scala.
+Охвачены следующие темы:
+
+- Что такое функциональное программирование?
+- Неизменяемые значения
+- Чистые функции
+- Функции — это значения
+- Функциональная обработка ошибок
+
+Как уже упоминалось, функциональное программирование — обширная тема,
+поэтому все, что мы можем сделать в этой книге, — это коснуться перечисленных вводных понятий.
+Дополнительные сведения см. [в справочной документации][reference].
+
+
+[reference]: {{ site.scala3ref }}/overview.html
+
diff --git a/_ru/scala3/book/fp-what-is-fp.md b/_ru/scala3/book/fp-what-is-fp.md
new file mode 100644
index 0000000000..8b624b5415
--- /dev/null
+++ b/_ru/scala3/book/fp-what-is-fp.md
@@ -0,0 +1,48 @@
+---
+layout: multipage-overview
+title: Что такое функциональное программирование?
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: Этот раздел дает ответ на вопрос, что такое функциональное программирование?
+language: ru
+num: 42
+previous-page: fp-intro
+next-page: fp-immutable-values
+---
+
+
+[Wikipedia](https://ru.wikipedia.org/wiki/%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)
+определяет _функциональное программирование_ следующим образом:
+
+
+
+Функциональное программирование — парадигма программирования,
+в которой процесс вычисления трактуется как вычисление значений функций в математическом понимании последних.
+Функциональное программирование предполагает обходиться вычислением результатов функций от исходных данных
+и результатов других функций, и не предполагает явного хранения состояния программы.
+Соответственно, не предполагает оно и изменяемость этого состояния.
+
+
+
+В функциональном программировании функции рассматриваются как “граждане первого класса”,
+что означает, что они могут быть привязаны к именам (включая локальные идентификаторы),
+передаваться в качестве аргументов и возвращаться из других функций, как и любой другой тип данных.
+Это позволяет писать программы в декларативном и составном стиле, где небольшие функции объединяются модульным образом.
+
+
+
+Также полезно знать, что опытные функциональные программисты рассматривают свой код математически,
+что объединение чистых функций вместе похоже на объединение ряда алгебраических уравнений.
+
+Когда пишется функциональный код, вы чувствуете себя математиком, и как только понимаете парадигму,
+то хотите писать только чистые функции, которые всегда возвращают _значения_, а не исключения или null,
+чтобы можно было комбинировать чистые функции вместе.
+Ощущение, что вы пишете математические уравнения (выражения), является движущим желанием,
+заставляющим использовать _только_ чистые функции и неизменяемые значения -
+это то, что используется в алгебре и других формах математики.
+
+Функциональное программирование - это большая тема, и нет простого способа сжать её всю в одну главу.
+В следующих разделах будет представлен обзор основных тем и показаны некоторые инструменты,
+предоставляемые Scala для написания функционального кода.
diff --git a/_ru/scala3/book/fun-anonymous-functions.md b/_ru/scala3/book/fun-anonymous-functions.md
new file mode 100644
index 0000000000..98b7158e8f
--- /dev/null
+++ b/_ru/scala3/book/fun-anonymous-functions.md
@@ -0,0 +1,214 @@
+---
+layout: multipage-overview
+title: Анонимные функции
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице показано, как использовать анонимные функции в Scala, включая примеры с функциями map и filter класса List.
+language: ru
+num: 29
+previous-page: fun-intro
+next-page: fun-function-variables
+---
+
+Анонимная функция, также известная как _лямбда_, представляет собой блок кода,
+который передается в качестве аргумента функции высшего порядка.
+Википедия определяет [анонимную функцию](https://en.wikipedia.org/wiki/Anonymous_function)
+как “определение функции, не привязанное к идентификатору”.
+
+Например, возьмем коллекцию:
+
+{% tabs fun-anonymous-1 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val ints = List(1, 2, 3)
+```
+{% endtab %}
+{% endtabs %}
+
+Можно создать новый список, удвоив каждый элемент в целых числах, используя метод `map` класса `List`
+и свою пользовательскую анонимную функцию:
+
+{% tabs fun-anonymous-2 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val doubledInts = ints.map(_ * 2) // List(2, 4, 6)
+```
+{% endtab %}
+{% endtabs %}
+
+Как видно из комментария, `doubleInts` содержит список `List(2, 4, 6)`.
+В этом примере анонимной функцией является часть кода:
+
+{% tabs fun-anonymous-3 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+_ * 2
+```
+{% endtab %}
+{% endtabs %}
+
+Это сокращенный способ сказать: “Умножить данный элемент на 2”.
+
+## Более длинные формы
+
+Когда вы освоитесь со Scala, то будете постоянно использовать эту форму для написания анонимных функций,
+использующих одну переменную в одном месте функции.
+Но при желании можете также написать их, используя более длинные формы,
+поэтому в дополнение к написанию этого кода:
+
+{% tabs fun-anonymous-4 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val doubledInts = ints.map(_ * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+вы также можете написать его, используя такие формы:
+
+{% tabs fun-anonymous-5 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val doubledInts = ints.map((i: Int) => i * 2)
+val doubledInts = ints.map((i) => i * 2)
+val doubledInts = ints.map(i => i * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+Все эти строки имеют одно и то же значение: удваивайте каждый элемент `ints`, чтобы создать новый список, `doubledInts`
+(синтаксис каждой формы объясняется ниже).
+
+Если вы знакомы с Java, вам будет полезно узнать, что эти примеры `map` эквивалентны следующему Java коду:
+
+{% tabs fun-anonymous-5-b %}
+{% tab 'Java' %}
+```java
+List ints = List.of(1, 2, 3);
+List doubledInts = ints.stream()
+ .map(i -> i * 2)
+ .collect(Collectors.toList());
+```
+{% endtab %}
+{% endtabs %}
+
+## Сокращение анонимных функций
+
+Если необходимо явно указать анонимную функцию, можно использовать следующую длинную форму:
+
+{% tabs fun-anonymous-6 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val doubledInts = ints.map((i: Int) => i * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+Анонимная функция в этом выражении такова:
+
+{% tabs fun-anonymous-7 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+(i: Int) => i * 2
+```
+{% endtab %}
+{% endtabs %}
+
+Если незнаком данный синтаксис, то можно воспринимать символ `=>` как преобразователь,
+потому что выражение _преобразует_ список параметров в левой части символа (переменная `Int` с именем `i`)
+в новый результат, используя алгоритм справа от символа `=>`
+(в данном случае выражение, которое удваивает значение `Int`).
+
+
+### Сокращение выражения
+
+Эту длинную форму можно сократить, как будет показано в следующих шагах.
+Во-первых, вот снова самая длинная и явная форма:
+
+{% tabs fun-anonymous-8 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val doubledInts = ints.map((i: Int) => i * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+Поскольку компилятор Scala может сделать вывод из данных в `ints` о том, что `i` - это `Int`,
+`Int` объявление можно удалить:
+
+{% tabs fun-anonymous-9 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val doubledInts = ints.map((i) => i * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+Поскольку есть только один аргумент, круглые скобки вокруг параметра `i` не нужны:
+
+{% tabs fun-anonymous-10 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val doubledInts = ints.map(i => i * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+Поскольку Scala позволяет использовать символ `_` вместо имени переменной,
+когда параметр появляется в функции только один раз, код можно упростить еще больше:
+
+{% tabs fun-anonymous-11 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val doubledInts = ints.map(_ * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+### Ещё короче
+
+В других примерах можно еще больше упростить анонимные функции.
+Например, начиная с самой явной формы, можно распечатать каждый элемент в `ints`,
+используя эту анонимную функцию с методом `foreach` класса `List`:
+
+{% tabs fun-anonymous-12 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+ints.foreach((i: Int) => println(i))
+```
+{% endtab %}
+{% endtabs %}
+
+Как и раньше, объявление `Int` не требуется, а поскольку аргумент всего один, скобки вокруг `i` не нужны:
+
+{% tabs fun-anonymous-13 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+ints.foreach(i => println(i))
+```
+{% endtab %}
+{% endtabs %}
+
+Поскольку `i` используется в теле функции только один раз, выражение можно еще больше упростить с помощью символа `_`:
+
+{% tabs fun-anonymous-14 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+ints.foreach(println(_))
+```
+{% endtab %}
+{% endtabs %}
+
+Наконец, если анонимная функция состоит из одного вызова метода с одним аргументом,
+нет необходимости явно называть и указывать аргумент,
+можно написать только имя метода (здесь, `println`):
+
+{% tabs fun-anonymous-15 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+ints.foreach(println)
+```
+{% endtab %}
+{% endtabs %}
diff --git a/_ru/scala3/book/fun-eta-expansion.md b/_ru/scala3/book/fun-eta-expansion.md
new file mode 100644
index 0000000000..1cbbc3255a
--- /dev/null
+++ b/_ru/scala3/book/fun-eta-expansion.md
@@ -0,0 +1,92 @@
+---
+layout: multipage-overview
+title: Eta расширение
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице обсуждается Eta Expansion, технология Scala, которая автоматически и прозрачно преобразует методы в функции.
+language: ru
+num: 31
+previous-page: fun-function-variables
+next-page: fun-hofs
+---
+
+
+Если посмотреть на Scaladoc для метода `map` в классах коллекций Scala,
+то можно увидеть, что метод определен для приема _функции_:
+
+```scala
+def map[B](f: (A) => B): List[B]
+ -----------
+```
+
+Действительно, в Scaladoc сказано: “`f` — это _функция_, применяемая к каждому элементу”.
+Но, несмотря на это, каким-то образом в `map` можно передать _метод_, и он все еще работает:
+
+```scala
+def times10(i: Int) = i * 10 // метод
+List(1, 2, 3).map(times10) // List(10,20,30)
+```
+
+Как это работает? Как можно передать _метод_ в `map`, который ожидает _функцию_?
+
+Технология, стоящая за этим, известна как _Eta Expansion_.
+Она преобразует выражение _типа метода_ в эквивалентное выражение _типа функции_, и делает это легко и незаметно.
+
+
+## Различия между методами и функциями
+
+Исторически _методы_ были частью определения класса, хотя в Scala 3 методы могут быть вне классов,
+такие как [определения верхнего уровня][toplevel] и [методы расширения][extension].
+
+В отличие от методов, _функции_ сами по себе являются полноценными объектами, что делает их объектами первого класса.
+
+Их синтаксис также отличается.
+В этом примере показано, как задать метод и функцию, которые выполняют одну и ту же задачу,
+определяя, является ли заданное целое число четным:
+
+```scala
+def isEvenMethod(i: Int) = i % 2 == 0 // метод
+val isEvenFunction = (i: Int) => i % 2 == 0 // функция
+```
+
+Функция действительно является объектом, поэтому ее можно использовать так же,
+как и любую другую переменную, например, помещая в список:
+
+```scala
+val functions = List(isEvenFunction)
+```
+
+И наоборот, технически метод не является объектом, поэтому в Scala 2 метод нельзя было поместить в `List`,
+по крайней мере, напрямую, как показано в этом примере:
+
+```scala
+// В этом примере показано сообщение об ошибке в Scala 2
+val methods = List(isEvenMethod)
+ ^
+error: missing argument list for method isEvenMethod
+Unapplied methods are only converted to functions when a function type is expected.
+You can make this conversion explicit by writing `isEvenMethod _` or `isEvenMethod(_)` instead of `isEvenMethod`.
+```
+
+Как показано в этом сообщении об ошибке, в Scala 2 существует ручной способ преобразования метода в функцию,
+но важной частью для Scala 3 является то, что технология Eta Expansion улучшена,
+поэтому теперь, когда попытаться использовать метод в качестве переменной,
+он просто работает — не нужно самостоятельно выполнять ручное преобразование:
+
+```scala
+val functions = List(isEvenFunction) // работает
+val methods = List(isEvenMethod) // работает
+```
+
+Для целей этой вводной книги важно знать следующее:
+
+- Eta Expansion — технология Scala, позволяющая использовать методы так же, как и функции
+- Технология была улучшена в Scala 3, чтобы быть почти полностью бесшовной
+
+Дополнительные сведения о том, как это работает, см. на [странице Eta Expansion][eta_expansion] в справочной документации.
+
+[eta_expansion]: {{ site.scala3ref }}/changed-features/eta-expansion.html
+[extension]: {% link _overviews/scala3-book/ca-extension-methods.md %}
+[toplevel]: {% link _overviews/scala3-book/taste-toplevel-definitions.md %}
diff --git a/_ru/scala3/book/fun-function-variables.md b/_ru/scala3/book/fun-function-variables.md
new file mode 100644
index 0000000000..667d4e7c30
--- /dev/null
+++ b/_ru/scala3/book/fun-function-variables.md
@@ -0,0 +1,172 @@
+---
+layout: multipage-overview
+title: Параметры функции
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице показано, как использовать параметры функции в Scala.
+language: ru
+num: 30
+previous-page: fun-anonymous-functions
+next-page: fun-eta-expansion
+---
+
+
+Вернемся к примеру из предыдущего раздела:
+
+{% tabs fun-function-variables-1 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val doubledInts = ints.map((i: Int) => i * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+Анонимной функцией является следующая часть:
+
+{% tabs fun-function-variables-2 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+(i: Int) => i * 2
+```
+{% endtab %}
+{% endtabs %}
+
+Причина, по которой она называется _анонимной_ (_anonymous_), заключается в том,
+что она не присваивается переменной и, следовательно, не имеет имени.
+
+Однако анонимная функция, также известная как _функциональный литерал_ (_function literal_),
+может быть назначена переменной для создания _функциональной переменной_ (_function variable_):
+
+{% tabs fun-function-variables-3 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val double = (i: Int) => i * 2
+```
+{% endtab %}
+{% endtabs %}
+
+Код выше создает функциональную переменную с именем `double`.
+В этом выражении исходный литерал функции находится справа от символа `=`:
+
+{% tabs fun-function-variables-4 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val double = (i: Int) => i * 2
+ -----------------
+```
+{% endtab %}
+{% endtabs %}
+
+, а новое имя переменной - слева:
+
+{% tabs fun-function-variables-5 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val double = (i: Int) => i * 2
+ ------
+```
+{% endtab %}
+{% endtabs %}
+
+список параметров функции подчеркнут:
+
+{% tabs fun-function-variables-6 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val double = (i: Int) => i * 2
+ --------
+```
+{% endtab %}
+{% endtabs %}
+
+Как и список параметров для метода, список параметров функции означает,
+что функция `double` принимает один параметр с типом `Int` и именем `i`.
+Как можно видеть ниже, `double` имеет тип `Int => Int`,
+что означает, что он принимает один параметр `Int` и возвращает `Int`:
+
+{% tabs fun-function-variables-7 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+scala> val double = (i: Int) => i * 2
+val double: Int => Int = ...
+```
+{% endtab %}
+{% endtabs %}
+
+
+### Вызов функции
+
+Функция `double` может быть вызвана так:
+
+{% tabs fun-function-variables-8 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val x = double(2) // 4
+```
+{% endtab %}
+{% endtabs %}
+
+`double` также можно передать в вызов `map`:
+
+{% tabs fun-function-variables-9 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+List(1, 2, 3).map(double) // List(2, 4, 6)
+```
+{% endtab %}
+{% endtabs %}
+
+Кроме того, когда есть другие функции типа `Int => Int`:
+
+{% tabs fun-function-variables-10 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val triple = (i: Int) => i * 3
+```
+{% endtab %}
+{% endtabs %}
+
+можно сохранить их в `List` или `Map`:
+
+{% tabs fun-function-variables-11 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val functionList = List(double, triple)
+
+val functionMap = Map(
+ "2x" -> double,
+ "3x" -> triple
+)
+```
+{% endtab %}
+{% endtabs %}
+
+Если вы вставите эти выражения в REPL, то увидите, что они имеют следующие типы:
+
+{% tabs fun-function-variables-12 %}
+{% tab 'Scala 2 и 3' %}
+````
+// список, содержащий функции типа `Int => Int`
+functionList: List[Int => Int]
+
+// Map, ключи которой имеют тип `String`,
+// а значения имеют тип `Int => Int`
+functionMap: Map[String, Int => Int]
+````
+{% endtab %}
+{% endtabs %}
+
+
+
+## Ключевые моменты
+
+Ключевыми моментами здесь являются:
+
+- чтобы создать функциональную переменную, достаточно присвоить имя переменной функциональному литералу
+- когда есть функция, с ней можно обращаться как с любой другой переменной, то есть как со `String` или `Int` переменной
+
+А благодаря улучшенной функциональности [Eta Expansion][eta_expansion] в Scala 3 с _методами_ можно обращаться точно так же.
+
+[eta_expansion]: {% link _overviews/scala3-book/fun-eta-expansion.md %}
diff --git a/_ru/scala3/book/fun-hofs.md b/_ru/scala3/book/fun-hofs.md
new file mode 100644
index 0000000000..805f243533
--- /dev/null
+++ b/_ru/scala3/book/fun-hofs.md
@@ -0,0 +1,389 @@
+---
+layout: multipage-overview
+title: Функции высшего порядка
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице показано, как создавать и использовать функции высшего порядка в Scala.
+language: ru
+num: 32
+previous-page: fun-eta-expansion
+next-page: fun-write-map-function
+---
+
+
+Функция высшего порядка (HOF - higher-order function) часто определяется как функция, которая
+
+- принимает другие функции в качестве входных параметров или
+- возвращает функцию в качестве результата.
+
+В Scala HOF возможны, потому что функции являются объектами первого класса.
+
+В качестве важного примечания: хотя в этом документе используется общепринятый термин “функция высшего порядка”,
+в Scala эта фраза применима как к методам, так и к функциям.
+Благодаря [технологии Eta Expansion][eta_expansion] их, как правило, можно использовать в одних и тех же местах.
+
+
+## От потребителя к разработчику
+
+В примерах, приведенных ранее в документации, было видно, как _пользоваться_ методами,
+которые принимают другие функции в качестве входных параметров, например, `map` и `filter`.
+
+В следующих разделах будет показано, как _создавать_ HOF, в том числе:
+
+- как писать методы, принимающие функции в качестве входных параметров
+- как возвращать функции из методов
+
+В процессе будет видно:
+
+- синтаксис, который используется для определения входных параметров функции
+- как вызвать функцию, если есть на нее ссылка
+
+В качестве полезного побочного эффекта, как только синтаксис станет привычным,
+его можно начать использовать для определения параметров функций, анонимных функций и функциональных переменных,
+а также станет легче читать Scaladoc для функций высшего порядка.
+
+
+## Понимание Scaladoc метода filter
+
+Чтобы понять, как работают функции высшего порядка, рассмотрим пример:
+определим, какой тип функций принимает `filter`, взглянув на его Scaladoc.
+Вот определение `filter` в классе `List[A]`:
+
+{% tabs filter-definition %}
+{% tab 'Scala 2 и 3' %}
+```scala
+def filter(p: A => Boolean): List[A]
+```
+{% endtab %}
+{% endtabs %}
+
+Это определение указывает на то, что `filter` - метод, который принимает параметр функции с именем `p`.
+По соглашению, `p` обозначает _предикат_, который представляет собой просто функцию, возвращающую `Boolean`.
+Таким образом, `filter` принимает предикат `p` в качестве входного параметра и возвращает `List[A]`,
+где `A` - тип, содержащийся в списке; если `filter` вызывается для `List[Int]`, то `A` - это тип `Int`.
+
+На данный момент, если не учитывать назначение метода `filter`,
+все, что известно, так это то, что алгоритм каким-то образом использует предикат `p` для создания и возврата `List[A]`.
+
+Если посмотреть конкретно на параметр функции `p`:
+
+```scala
+p: A => Boolean
+```
+
+, то эта часть описания `filter` означает, что любая передаваемая функция
+должна принимать тип `A` в качестве входного параметра и возвращать `Boolean`.
+Итак, если список представляет собой список `List[Int]`,
+то можно заменить универсальный тип `A` на `Int` и прочитать эту подпись следующим образом:
+
+```scala
+p: Int => Boolean
+```
+
+Поскольку `isEven` имеет такой же тип — преобразует входное значение `Int` в результирующее `Boolean` —
+его можно использовать с `filter`.
+
+
+## Написание методов, которые принимают параметры функции
+
+Рассмотрим пример написания методов, которые принимают функции в качестве входных параметров.
+
+**Примечание:** для определенности, будем называть код, который пишется, _методом_,
+а код, принимаемый в качестве входного параметра, — _функцией_.
+
+### Пример
+
+Чтобы создать метод, который принимает функцию в качестве параметра, необходимо:
+
+1. в списке параметров метода определить сигнатуру принимаемой функции
+2. использовать эту функцию внутри метода
+
+Чтобы продемонстрировать это, вот метод, который принимает входной параметр с именем `f`, где `f` — функция:
+
+
+{% tabs sayHello-definition %}
+{% tab 'Scala 2 и 3' %}
+```scala
+def sayHello(f: () => Unit): Unit = f()
+```
+{% endtab %}
+{% endtabs %}
+
+Эта часть кода — _сигнатура типа (type signature)_ — утверждает, что `f` является функцией,
+и определяет типы функций, которые будет принимать метод `sayHello`:
+
+```scala
+f: () => Unit
+```
+
+Как это работает:
+
+- `f` — имя входного параметра функции.
+ Аналогично тому, как параметр `String` обычно называется `s` или параметр `Int` - `i`
+- сигнатура типа `f` определяет _тип_ функций, которые будет принимать метод
+- часть `()` подписи `f` (слева от символа `=>`) указывает на то, что `f` не принимает входных параметров
+- часть сигнатуры `Unit` (справа от символа `=>`) указывает на то, что функция `f` не должна возвращать осмысленный результат
+- в теле метода `sayHello` (справа от символа `=`) оператор `f()` вызывает переданную функцию
+
+Теперь, когда `sayHello` определен, создадим функцию, соответствующую сигнатуре `f`, чтобы ее можно было проверить.
+Следующая функция не принимает входных параметров и ничего не возвращает, поэтому она соответствует сигнатуре типа `f`:
+
+{% tabs helloJoe-definition %}
+{% tab 'Scala 2 и 3' %}
+```scala
+def helloJoe(): Unit = println("Hello, Joe")
+```
+{% endtab %}
+{% endtabs %}
+
+
+Поскольку сигнатуры типов совпадают, можно передать `helloJoe` в `sayHello`:
+
+{% tabs sayHello-usage %}
+{% tab 'Scala 2 и 3' %}
+```scala
+sayHello(helloJoe) // печатает "Hello, Joe"
+```
+{% endtab %}
+{% endtabs %}
+
+Если вы никогда этого не делали раньше, поздравляем:
+был определен метод с именем `sayHello`, который принимает функцию в качестве входного параметра,
+а затем вызывает эту функцию в теле своего метода.
+
+
+### sayHello может принимать разные функции
+
+Важно знать, что преимущество этого подхода заключается не в том,
+что `sayHello` может принимать одну функцию в качестве входного параметра;
+преимущество в том, что `sayHello` может принимать любую функцию, соответствующую сигнатуре `f`.
+Например, поскольку следующая функция не принимает входных параметров и ничего не возвращает, она также работает с `sayHello`:
+
+{% tabs bonjourJulien-definition %}
+{% tab 'Scala 2 и 3' %}
+```scala
+def bonjourJulien(): Unit = println("Bonjour, Julien")
+```
+{% endtab %}
+{% endtabs %}
+
+Вот что выводится в REPL:
+
+{% tabs bonjourJulien-usage %}
+{% tab 'Scala 2 и 3' %}
+````
+scala> sayHello(bonjourJulien)
+Bonjour, Julien
+````
+{% endtab %}
+{% endtabs %}
+
+Это отличный старт.
+Рассмотрим ещё несколько примеров того, как определять сигнатуры различных типов для параметров функции.
+
+
+## Общий синтаксис для определения входных параметров функции
+
+В методе:
+
+{% tabs sayHello-definition-2 %}
+{% tab 'Scala 2 и 3' %}
+```scala
+def sayHello(f: () => Unit): Unit
+```
+{% endtab %}
+{% endtabs %}
+
+сигнатурой типа для `f` является:
+
+```scala
+() => Unit
+```
+
+Это сигнатура означает “функцию, которая не принимает входных параметров и не возвращает ничего значимого (`Unit`)”.
+
+Вот сигнатура функции, которая принимает параметр `String` и возвращает `Int`:
+
+```scala
+f: String => Int
+```
+
+Какие функции принимают строку и возвращают целое число?
+Например, такие, как “длина строки” и контрольная сумма.
+
+Эта функция принимает два параметра `Int` и возвращает `Int`:
+
+```scala
+f: (Int, Int) => Int
+```
+
+Какие функции соответствуют данной сигнатуре?
+
+Любая функция, которая принимает два входных параметра `Int` и возвращает `Int`,
+соответствует этой сигнатуре, поэтому все “функции” ниже (точнее, методы) подходят:
+
+{% tabs add-sub-mul-definitions %}
+{% tab 'Scala 2 и 3' %}
+```scala
+def add(a: Int, b: Int): Int = a + b
+def subtract(a: Int, b: Int): Int = a - b
+def multiply(a: Int, b: Int): Int = a * b
+```
+{% endtab %}
+{% endtabs %}
+
+Из примеров выше можно сделать вывод, что общий синтаксис сигнатуры функций такой:
+
+```scala
+variableName: (parameterTypes ...) => returnType
+```
+
+> Поскольку функциональное программирование похоже на создание и объединение ряда алгебраических уравнений,
+> обычно _много думают_ о типах при разработке функций и приложений.
+> Можно сказать, что “думают типами”.
+
+
+## Параметр функции вместе с другими параметрами
+
+Чтобы HOFs стали действительно полезными, им также нужны некоторые данные для работы.
+Для класса, подобного `List`, в его методе `map` уже есть данные для работы: элементы в `List`.
+Но для автономного приложения, у которого нет собственных данных,
+метод также должен принимать в качестве других входных параметров данные.
+
+Рассмотрим пример метода с именем `executeNTimes`, который имеет два входных параметра: функцию и `Int`:
+
+{% tabs executeNTimes-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+def executeNTimes(f: () => Unit, n: Int): Unit =
+ for (i <- 1 to n) f()
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+def executeNTimes(f: () => Unit, n: Int): Unit =
+ for i <- 1 to n do f()
+```
+{% endtab %}
+{% endtabs %}
+
+Как видно из кода, `executeNTimes` выполняет функцию `f` `n` раз.
+Поскольку простой цикл `for`, подобный этому, не имеет возвращаемого значения, `executeNTimes` возвращает `Unit`.
+
+Чтобы протестировать `executeNTimes`, определим метод, соответствующий сигнатуре `f`:
+
+{% tabs helloWorld-definition %}
+{% tab 'Scala 2 и 3' %}
+```scala
+// тип метода - `() => Unit`
+def helloWorld(): Unit = println("Hello, world")
+```
+{% endtab %}
+{% endtabs %}
+
+Затем передадим этот метод в `executeNTimes` вместе с `Int`:
+
+{% tabs helloWorld-usage %}
+{% tab 'Scala 2 и 3' %}
+```
+scala> executeNTimes(helloWorld, 3)
+Hello, world
+Hello, world
+Hello, world
+```
+{% endtab %}
+{% endtabs %}
+
+
+Великолепно.
+Метод `executeNTimes` трижды выполняет функцию `helloWorld`.
+
+
+### Столько параметров, сколько необходимо
+
+Методы могут усложняться по мере необходимости.
+Например, этот метод принимает функцию типа `(Int, Int) => Int` вместе с двумя входными параметрами:
+
+{% tabs executeAndPrint-definition %}
+{% tab 'Scala 2 и 3' %}
+```scala
+def executeAndPrint(f: (Int, Int) => Int, i: Int, j: Int): Unit =
+ println(f(i, j))
+```
+{% endtab %}
+{% endtabs %}
+
+
+Поскольку методы `sum` и `multiply` соответствуют сигнатуре `f`,
+их можно передать в `executeAndPrint` вместе с двумя значениями `Int`:
+
+{% tabs executeAndPrint-usage %}
+{% tab 'Scala 2 и 3' %}
+```scala
+def sum(x: Int, y: Int) = x + y
+def multiply(x: Int, y: Int) = x * y
+
+executeAndPrint(sum, 3, 11) // печатает 14
+executeAndPrint(multiply, 3, 9) // печатает 27
+```
+{% endtab %}
+{% endtabs %}
+
+
+## Согласованность подписи типа функции
+
+Самое замечательное в изучении сигнатур типов функций Scala заключается в том,
+что синтаксис, используемый для определения входных параметров функции, —
+это тот же синтаксис, что используется для написания литералов функций.
+
+Например, если необходимо написать функцию, вычисляющую сумму двух целых чисел, её можно было бы написать так:
+
+{% tabs f-val-definition %}
+{% tab 'Scala 2 и 3' %}
+```scala
+val f: (Int, Int) => Int = (a, b) => a + b
+```
+{% endtab %}
+{% endtabs %}
+
+Этот код состоит из сигнатуры типа:
+
+````
+val f: (Int, Int) => Int = (a, b) => a + b
+ -----------------
+````
+
+входных параметров:
+
+````
+val f: (Int, Int) => Int = (a, b) => a + b
+ ------
+````
+
+и тела функции:
+
+````
+val f: (Int, Int) => Int = (a, b) => a + b
+ -----
+````
+
+Согласованность Scala состоит в том, что тип функции:
+
+````
+val f: (Int, Int) => Int = (a, b) => a + b
+ -----------------
+````
+
+совпадает с сигнатурой типа, используемого для определения входного параметра функции:
+
+````
+def executeAndPrint(f: (Int, Int) => Int, ...
+ -----------------
+````
+
+По мере освоения этого синтаксиса, становится привычным его использование для определения параметров функций,
+анонимных функций и функциональных переменных, а также становится легче читать Scaladoc для функций высшего порядка.
+
+[eta_expansion]: {% link _overviews/scala3-book/fun-eta-expansion.md %}
diff --git a/_ru/scala3/book/fun-intro.md b/_ru/scala3/book/fun-intro.md
new file mode 100644
index 0000000000..01d2080096
--- /dev/null
+++ b/_ru/scala3/book/fun-intro.md
@@ -0,0 +1,17 @@
+---
+layout: multipage-overview
+title: Функции
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: В этой главе рассматриваются темы, связанные с функциями в Scala 3.
+language: ru
+num: 28
+previous-page: methods-summary
+next-page: fun-anonymous-functions
+---
+
+Если в предыдущей главе были представлены Scala _методы_, то в этой главе мы углубимся в _функции_.
+Рассматриваемые темы включают анонимные функции, функциональные переменные и функции высшего порядка (HOF),
+в том числе способы создания собственных HOF.
diff --git a/_ru/scala3/book/fun-summary.md b/_ru/scala3/book/fun-summary.md
new file mode 100644
index 0000000000..20391f5af9
--- /dev/null
+++ b/_ru/scala3/book/fun-summary.md
@@ -0,0 +1,41 @@
+---
+layout: multipage-overview
+title: Обзор
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице представлен обзор предыдущего раздела 'Функции'.
+language: ru
+num: 35
+previous-page: fun-write-method-returns-function
+next-page: packaging-imports
+---
+
+Это была длинная глава, поэтому давайте рассмотрим ключевые моменты, которые мы прошли.
+
+Функция высшего порядка (HOF) часто определяется как функция,
+которая принимает другие функции в качестве входных параметров или возвращает функцию в качестве своего значения.
+В Scala это возможно, потому что функции являются объектами первого класса.
+
+Двигаясь по разделам, сначала вы узнали:
+
+- Как писать анонимные функции в виде небольших фрагментов кода.
+- Как передать их десяткам HOF (методов) в классах коллекций, т.е. таким методам, как `filter`, `map` и т.д.
+- Как с помощью этих небольших фрагментов кода и мощных HOF создавать множество функций с помощью небольшого кода.
+
+Изучив анонимные функции и HOF, вы узнали:
+
+- Функциональные переменные — это просто анонимные функции, привязанные к переменной.
+
+Увидев, как быть потребителем HOF, вы увидели, как стать создателем HOF.
+В частности, вы узнали:
+
+- Как писать методы, принимающие функции в качестве входных параметров
+- Как вернуть функцию из метода
+
+Полезным побочным эффектом этой главы является то,
+что вы увидели много примеров того, как объявлять сигнатуры типов для функций.
+Преимущество этого заключается в том, что вы используете один и тот же синтаксис
+для определения параметров функций, анонимных функций и функциональных переменных,
+а также становится легче читать Scaladoc для функций высшего порядка, таких как `map`, `filter` и другие.
diff --git a/_ru/scala3/book/fun-write-map-function.md b/_ru/scala3/book/fun-write-map-function.md
new file mode 100644
index 0000000000..f7b6a0f63e
--- /dev/null
+++ b/_ru/scala3/book/fun-write-map-function.md
@@ -0,0 +1,141 @@
+---
+layout: multipage-overview
+title: Собственный map
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице описано, как создать свой собственный метод map
+language: ru
+num: 33
+previous-page: fun-hofs
+next-page: fun-write-method-returns-function
+---
+
+
+Теперь, когда известно, как писать собственные функции высшего порядка, рассмотрим более реальный пример.
+
+Представим, что у класса `List` нет метода `map`, и есть необходимость его написать.
+Первым шагом при создании функций является точное определение проблемы.
+Сосредоточившись только на `List[Int]`, получаем:
+
+> Необходимо написать метод `map`, который можно использовать для применения функции к каждому элементу в `List[Int]`,
+> возвращая преобразованные элементы в виде нового списка.
+
+Учитывая это утверждение, начнем писать сигнатуру метода.
+Во-первых, известно, что функция должна приниматься в качестве параметра,
+и эта функция должна преобразовать `Int` в какой-то общий тип `A`, поэтому получаем:
+
+{% tabs map-accept-func-definition %}
+{% tab 'Scala 2 и 3' %}
+```scala
+def map(f: (Int) => A)
+```
+{% endtab %}
+{% endtabs %}
+
+Синтаксис использования универсального типа требует объявления этого символа типа перед списком параметров,
+поэтому добавляем объявление типа:
+
+{% tabs map-type-symbol-definition %}
+{% tab 'Scala 2 и 3' %}
+```scala
+def map[A](f: (Int) => A)
+```
+{% endtab %}
+{% endtabs %}
+
+Далее известно, что `map` также должен принимать `List[Int]`:
+
+{% tabs map-list-int-param-definition %}
+{% tab 'Scala 2 и 3' %}
+```scala
+def map[A](f: (Int) => A, xs: List[Int])
+```
+{% endtab %}
+{% endtabs %}
+
+Наконец, также известно, что `map` возвращает преобразованный список, содержащий элементы универсального типа `A`:
+
+{% tabs map-with-return-type-definition %}
+{% tab 'Scala 2 и 3' %}
+```scala
+def map[A](f: (Int) => A, xs: List[Int]): List[A] = ???
+```
+{% endtab %}
+{% endtabs %}
+
+Теперь все, что нужно сделать, это написать тело метода.
+Метод `map` применяет заданную им функцию к каждому элементу в заданном списке для создания нового преобразованного списка.
+Один из способов сделать это - использовать выражение `for`:
+
+{% tabs for-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+for (x <- xs) yield f(x)
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+for x <- xs yield f(x)
+```
+{% endtab %}
+{% endtabs %}
+
+`for` выражения зачастую делают код удивительно простым, и в данном случае - это все тело метода.
+
+Объединив `for` с сигнатурой метода, получим автономный метод `map`, который работает с `List[Int]`:
+
+{% tabs map-function class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+def map[A](f: (Int) => A, xs: List[Int]): List[A] =
+ for (x <- xs) yield f(x)
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+def map[A](f: (Int) => A, xs: List[Int]): List[A] =
+ for x <- xs yield f(x)
+```
+{% endtab %}
+{% endtabs %}
+
+
+### Обобщим метод map
+
+Обратим внимание, что выражение `for` не делает ничего, что зависит от типа `Int` внутри списка.
+Следовательно, можно заменить `Int` в сигнатуре типа параметром универсального типа `B`:
+
+{% tabs map-function-full-generic class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+def map[A, B](f: (B) => A, xs: List[B]): List[A] =
+ for (x <- xs) yield f(x)
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+def map[A, B](f: (B) => A, xs: List[B]): List[A] =
+ for x <- xs yield f(x)
+```
+{% endtab %}
+{% endtabs %}
+
+Получился метод `map`, который работает с любым списком.
+
+Демонстрация работы получившегося `map`:
+
+{% tabs map-use-example %}
+{% tab 'Scala 2 и 3' %}
+```scala
+def double(i : Int): Int = i * 2
+map(double, List(1, 2, 3)) // List(2, 4, 6)
+
+def strlen(s: String): Int = s.length
+map(strlen, List("a", "bb", "ccc")) // List(1, 2, 3)
+```
+{% endtab %}
+{% endtabs %}
+
+Теперь, когда рассмотрены методы, принимающие функции в качестве входных параметров, перейдем к методам, возвращающим функции.
diff --git a/_ru/scala3/book/fun-write-method-returns-function.md b/_ru/scala3/book/fun-write-method-returns-function.md
new file mode 100644
index 0000000000..a2bb66c69c
--- /dev/null
+++ b/_ru/scala3/book/fun-write-method-returns-function.md
@@ -0,0 +1,176 @@
+---
+layout: multipage-overview
+title: Создание метода, возвращающего функцию
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице показано, как создавать методы, возвращающие функции, в Scala.
+language: ru
+num: 34
+previous-page: fun-write-map-function
+next-page: fun-summary
+---
+
+
+Благодаря согласованности Scala написание метода, возвращающего функцию, похоже на то, что было описано в предыдущих разделах.
+Например, представьте, что вы хотите написать метод `greet`, возвращающий функцию.
+Еще раз начнем с постановки проблемы:
+
+> Необходимо создать метод greet, возвращающий функцию.
+> Эта функция должна принимать строковый параметр и печатать его с помощью `println`.
+> Начнем с простого шага: `greet` не принимает никаких входных параметров, а просто создает функцию и возвращает её.
+
+Учитывая это утверждение, можно начать создавать `greet`.
+Известно, что это будет метод:
+
+```scala
+def greet()
+```
+
+Также известно, что этот метод должен возвращать функцию, которая (a) принимает параметр `String` и
+(b) печатает эту строку с помощью `println`.
+
+Следовательно, эта функция имеет тип `String => Unit`:
+
+```scala
+def greet(): String => Unit = ???
+ ----------------
+```
+
+Теперь нужно просто создать тело метода.
+Известно, что метод должен возвращать функцию, и эта функция принимает `String` и печатает ее.
+Эта анонимная функция соответствует следующему описанию:
+
+```scala
+(name: String) => println(s"Hello, $name")
+```
+
+Теперь вы просто возвращаете эту функцию из метода:
+
+```scala
+// метод, который возвращает функцию
+def greet(): String => Unit =
+ (name: String) => println(s"Hello, $name")
+```
+
+Поскольку этот метод возвращает функцию, вы получаете функцию, вызывая `greet()`.
+Это хороший шаг для проверки в REPL, потому что он проверяет тип новой функции:
+
+````
+scala> val greetFunction = greet()
+val greetFunction: String => Unit = Lambda....
+ -----------------------------
+````
+
+Теперь можно вызвать `greetFunction`:
+
+```scala
+greetFunction("Joe") // печатает "Hello, Joe"
+```
+
+Поздравляем, вы только что создали метод, возвращающий функцию, а затем запустили её.
+
+
+## Доработка метода
+
+Метод `greet` был бы более полезным, если бы была возможность задавать приветствие.
+Например, передать его в качестве параметра методу `greet` и использовать внутри `println`:
+
+```scala
+def greet(theGreeting: String): String => Unit =
+ (name: String) => println(s"$theGreeting, $name")
+```
+
+Теперь, при вызове этого метода, процесс становится более гибким, потому что приветствие можно изменить.
+Вот как это выглядит, когда создается функция из этого метода:
+
+````
+scala> val sayHello = greet("Hello")
+val sayHello: String => Unit = Lambda.....
+ ------------------------
+````
+
+Выходные данные подписи типа показывают, что `sayHello` — это функция,
+которая принимает входной параметр `String` и возвращает `Unit` (ничего).
+Так что теперь, при передаче `sayHello` строки, печатается приветствие:
+
+```scala
+sayHello("Joe") // печатает "Hello, Joe"
+```
+
+Приветствие можно менять для создания новых функций:
+
+```scala
+val sayCiao = greet("Ciao")
+val sayHola = greet("Hola")
+
+sayCiao("Isabella") // печатает "Ciao, Isabella"
+sayHola("Carlos") // печатает "Hola, Carlos"
+```
+
+
+## Более реалистичный пример
+
+Этот метод может быть еще более полезным, когда возвращает одну из многих возможных функций,
+например, фабрику пользовательских функций.
+
+Например, представим, что необходимо написать метод, который возвращает функции, приветствующие людей на разных языках.
+Ограничим это функциями, которые приветствуют на английском или французском языках,
+в зависимости от параметра, переданного в метод.
+
+Созданный метод должен: (a) принимать “желаемый язык” в качестве входных данных
+и (b) возвращать функцию в качестве результата.
+Кроме того, поскольку эта функция печатает заданную строку, известно, что она имеет тип `String => Unit`.
+С помощью этой информации сигнатура метода должна выглядеть так:
+
+```scala
+def createGreetingFunction(desiredLanguage: String): String => Unit = ???
+```
+
+Далее, поскольку возвращаемые функции, берут строку и печатают ее,
+можно прикинуть две анонимные функции для английского и французского языков:
+
+```scala
+(name: String) => println(s"Hello, $name")
+(name: String) => println(s"Bonjour, $name")
+```
+
+Для большей читабельности дадим этим анонимным функциям имена и назначим двум переменным:
+
+```scala
+val englishGreeting = (name: String) => println(s"Hello, $name")
+val frenchGreeting = (name: String) => println(s"Bonjour, $name")
+```
+
+Теперь все, что осталось, это (a) вернуть `englishGreeting`, если `desiredLanguage` — английский,
+и (b) вернуть `frenchGreeting`, если `desiredLanguage` — французский.
+Один из способов сделать это - выражение `match`:
+
+```scala
+def createGreetingFunction(desiredLanguage: String): String => Unit =
+ val englishGreeting = (name: String) => println(s"Hello, $name")
+ val frenchGreeting = (name: String) => println(s"Bonjour, $name")
+ desiredLanguage match
+ case "english" => englishGreeting
+ case "french" => frenchGreeting
+```
+
+И это последний метод.
+Обратите внимание, что возврат значения функции из метода ничем не отличается от возврата строкового или целочисленного значения.
+
+Вот как `createGreetingFunction` создает функцию приветствия на французском языке:
+
+```scala
+val greetInFrench = createGreetingFunction("french")
+greetInFrench("Jonathan") // печатает "Bonjour, Jonathan"
+```
+
+И вот как - на английском:
+
+```scala
+val greetInEnglish = createGreetingFunction("english")
+greetInEnglish("Joe") // печатает "Hello, Joe"
+```
+
+Если вам понятен этот код — поздравляю — теперь вы знаете, как писать методы, возвращающие функции.
diff --git a/_ru/scala3/book/interacting-with-java.md b/_ru/scala3/book/interacting-with-java.md
new file mode 100644
index 0000000000..86f3268d46
--- /dev/null
+++ b/_ru/scala3/book/interacting-with-java.md
@@ -0,0 +1,560 @@
+---
+layout: multipage-overview
+title: Взаимодействие с Java
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: На этой странице показано, как код Scala может взаимодействовать с Java и как код Java может взаимодействовать с кодом Scala.
+language: ru
+num: 72
+previous-page: tools-worksheets
+next-page:
+---
+
+## Введение
+
+В этом разделе рассматривается, как использовать код Java в Scala и, наоборот, как использовать код Scala в Java.
+
+В целом, использование Java-кода в Scala довольно простое.
+Есть лишь несколько моментов,
+когда может появиться желание использовать утилиты Scala для преобразования концепций Java в Scala,
+в том числе:
+
+- Классы коллекций Java
+- Java класс `Optional`
+
+Аналогично, если вы пишете код Java и хотите использовать концепции Scala,
+вам потребуется преобразовать коллекции Scala и Scala класс `Option`.
+
+В следующих разделах демонстрируются наиболее распространенные преобразования, которые вам могут понадобиться:
+
+- Как использовать коллекции Java в Scala
+- Как использовать Java `Optional` в Scala
+- Расширение Java интерфейсов в Scala
+- Как использовать коллекции Scala в Java
+- Как использовать Scala `Option` в Java
+- Как использовать трейты Scala в Java
+- Как обрабатывать методы Scala, которые вызывают исключения в коде Java
+- Как использовать vararg-параметры Scala в Java
+- Создание альтернативных имен для использования методов Scala в Java
+
+> Обратите внимание: примеры Java в этом разделе предполагают, что вы используете Java 11 или более позднюю версию.
+
+## Как использовать коллекции Java в Scala
+
+Когда вы пишете код на Scala, а API либо требует, либо создает класс коллекции Java (из пакета `java.util`),
+тогда допустимо напрямую использовать или создавать коллекцию, как в Java.
+
+Однако для идиоматического использования в Scala, например, для циклов `for` по коллекции
+или для применения функций высшего порядка, таких как `map` и `filter`,
+вы можете создать прокси, который будет вести себя как коллекция Scala.
+
+Вот пример того, как это работает.
+Учитывая следующий API, который возвращает `java.util.List[String]`:
+
+{% tabs foo-definition %}
+{% tab Java %}
+
+```java
+public interface Foo {
+ static java.util.List getStrings() {
+ return List.of("a", "b", "c");
+ }
+}
+```
+
+{% endtab %}
+{% endtabs %}
+
+Вы можете преобразовать этот Java список в Scala `Seq`,
+используя утилиты преобразования из Scala объекта `scala.jdk.CollectionConverters`:
+
+{% tabs foo-usage class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+import scala.jdk.CollectionConverters._
+import scala.collection.mutable
+
+def testList() = {
+ println("Using a Java List in Scala")
+ val javaList: java.util.List[String] = Foo.getStrings()
+ val scalaSeq: mutable.Seq[String] = javaList.asScala
+ for (s <- scalaSeq) println(s)
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+import scala.jdk.CollectionConverters.*
+import scala.collection.mutable
+
+def testList() =
+ println("Using a Java List in Scala")
+ val javaList: java.util.List[String] = Foo.getStrings()
+ val scalaSeq: mutable.Seq[String] = javaList.asScala
+ for s <- scalaSeq do println(s)
+```
+
+{% endtab %}
+{% endtabs %}
+
+В приведенном выше коде создается оболочка `javaList.asScala`,
+которая адаптирует `java.util.List` к коллекции Scala `mutable.Seq`.
+
+## Как использовать Java `Optional` в Scala
+
+Когда вы взаимодействуете с API, который использует класс `java.util.Optional` в коде Scala,
+его можно создавать и использовать, как в Java.
+
+Однако для идиоматического использования в Scala, например использования в `for`,
+вы можете преобразовать его в Scala `Option`.
+
+Чтобы продемонстрировать это, вот Java API, который возвращает значение типа `Optional[String]`:
+
+{% tabs bar-definition %}
+{% tab Java %}
+
+```java
+public interface Bar {
+ static java.util.Optional optionalString() {
+ return Optional.of("hello");
+ }
+}
+```
+
+{% endtab %}
+{% endtabs %}
+
+Сначала импортируйте всё из объекта `scala.jdk.OptionConverters`,
+а затем используйте метод `toScala` для преобразования `Optional` значения в Scala `Option`:
+
+{% tabs bar-usage class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+import java.util.Optional
+import scala.jdk.OptionConverters._
+
+val javaOptString: Optional[String] = Bar.optionalString
+val scalaOptString: Option[String] = javaOptString.toScala
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+import java.util.Optional
+import scala.jdk.OptionConverters.*
+
+val javaOptString: Optional[String] = Bar.optionalString
+val scalaOptString: Option[String] = javaOptString.toScala
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Расширение Java интерфейсов в Scala
+
+Если вам нужно использовать Java интерфейсы в коде Scala, расширяйте их так, как если бы они были трейтами Scala.
+Например, учитывая эти три Java интерфейса:
+
+{% tabs animal-definition %}
+{% tab Java %}
+
+```java
+public interface Animal {
+ void speak();
+}
+
+public interface Wagging {
+ void wag();
+}
+
+public interface Running {
+ // an implemented method
+ default void run() {
+ System.out.println("I’m running");
+ }
+}
+```
+
+{% endtab %}
+{% endtabs %}
+
+вы можете создать класс `Dog` в Scala так же, как если бы вы использовали трейты.
+Поскольку у `run` есть реализация по умолчанию, вам нужно реализовать только методы `speak` и `wag`:
+
+{% tabs animal-usage class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+class Dog extends Animal with Wagging with Running {
+ def speak = println("Woof")
+ def wag = println("Tail is wagging")
+}
+
+def useJavaInterfaceInScala = {
+ val d = new Dog()
+ d.speak
+ d.wag
+ d.run
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+class Dog extends Animal, Wagging, Running:
+ def speak = println("Woof")
+ def wag = println("Tail is wagging")
+
+def useJavaInterfaceInScala =
+ val d = Dog()
+ d.speak
+ d.wag
+ d.run
+```
+
+{% endtab %}
+{% endtabs %}
+
+Также обратите внимание, что в Scala методы Java, определенные с пустыми списками параметров,
+можно вызывать либо так же, как в Java, `.wag()`,
+либо вы можете отказаться от использования круглых скобок `.wag`.
+
+## Как использовать коллекции Scala в Java
+
+Если вам нужно использовать класс коллекции Scala в своем Java-коде,
+используйте методы Scala объекта `scala.jdk.javaapi.CollectionConverters` в своем Java-коде,
+для корректной работы конверсии.
+
+Например, предположим, что Scala API возвращает `List[String]`, как следующем примере:
+
+{% tabs baz-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+object Baz {
+ val strings: List[String] = List("a", "b", "c")
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+object Baz:
+ val strings: List[String] = List("a", "b", "c")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Вы можете получить доступ к Scala `List` в Java-коде следующим образом:
+
+{% tabs baz-usage %}
+{% tab Java %}
+
+```java
+import scala.jdk.javaapi.CollectionConverters;
+
+// получить доступ к методу `strings` с помощью `Baz.strings()`
+scala.collection.immutable.List xs = Baz.strings();
+
+java.util.List listOfStrings = CollectionConverters.asJava(xs);
+
+for (String s: listOfStrings) {
+ System.out.println(s);
+}
+```
+
+{% endtab %}
+{% endtabs %}
+
+Этот код можно сократить, но показаны полные шаги, чтобы продемонстрировать, как работает процесс.
+Обязательно обратите внимание, что хотя `Baz` имеет поле с именем `strings`,
+в Java оно отображается как метод, поэтому его следует вызывать в круглых скобках `.strings()`.
+
+## Как использовать Scala `Option` в Java
+
+Если вам нужно использовать Scala `Option` в коде Java,
+вы можете преобразовать значение `Option` в значение Java `Optional`,
+используя метод `toJava` объекта Scala `scala.jdk.javaapi.OptionConverters`.
+
+Например, предположим, что Scala API возвращает `Option[String]`, как следующем примере:
+
+{% tabs qux-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+object Qux {
+ val optString: Option[String] = Option("hello")
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+object Qux:
+ val optString: Option[String] = Option("hello")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Затем вы можете получить доступ к Scala `Option` в своем Java-коде следующим образом:
+
+{% tabs qux-usage %}
+{% tab Java %}
+
+```java
+import java.util.Optional;
+import scala.Option;
+import scala.jdk.javaapi.OptionConverters;
+
+Option scalaOptString = Qux.optString();
+Optional javaOptString = OptionConverters.toJava(scalaOptString);
+```
+
+{% endtab %}
+{% endtabs %}
+
+Этот код можно сократить, но показаны полные шаги, чтобы продемонстрировать, как работает процесс.
+Обязательно обратите внимание, что хотя `Qux` имеет поле с именем `optString`,
+в Java оно отображается как метод, поэтому его следует вызывать в круглых скобках `.optString()`.
+
+## Как использовать трейты Scala в Java
+
+Начиная с Java 8, вы можете использовать трейт Scala точно так же, как Java интерфейс,
+даже если этот трейт реализует методы.
+Например, учитывая эти два трейта Scala, один с реализованным методом, а другой только с интерфейсом:
+
+{% tabs scala-trait-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait ScalaAddTrait {
+ def sum(x: Int, y: Int) = x + y // реализован
+}
+
+trait ScalaMultiplyTrait {
+ def multiply(x: Int, y: Int): Int // абстрактный
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+trait ScalaAddTrait:
+ def sum(x: Int, y: Int) = x + y // реализован
+
+trait ScalaMultiplyTrait:
+ def multiply(x: Int, y: Int): Int // абстрактный
+```
+
+{% endtab %}
+{% endtabs %}
+
+Класс Java может реализовать оба этих интерфейса и определить метод `multiply`:
+
+{% tabs scala-trait-usage %}
+{% tab Java %}
+
+```java
+class JavaMath implements ScalaAddTrait, ScalaMultiplyTrait {
+ public int multiply(int a, int b) {
+ return a * b;
+ }
+}
+
+JavaMath jm = new JavaMath();
+System.out.println(jm.sum(3,4)); // 7
+System.out.println(jm.multiply(3,4)); // 12
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Как обрабатывать методы Scala, которые вызывают исключения в коде Java
+
+Когда вы пишете код на Scala, используя идиомы программирования Scala,
+вы никогда не напишете метод, который генерирует исключение.
+Но если по какой-то причине у вас есть метод Scala, который генерирует исключение,
+и вы хотите, чтобы разработчики Java могли использовать этот метод,
+добавьте аннотацию `@throws` к вашему методу Scala,
+чтобы Java потребители знали, какие исключения он может генерировать.
+
+Например, следующий Scala метод `exceptionThrower` аннотирован, чтобы объявить, что он выдает `Exception`:
+
+{% tabs except-throw-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+object SExceptionThrower {
+ @throws[Exception]
+ def exceptionThrower =
+ throw new Exception("Idiomatic Scala methods don’t throw exceptions")
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+object SExceptionThrower:
+ @throws[Exception]
+ def exceptionThrower =
+ throw Exception("Idiomatic Scala methods don’t throw exceptions")
+```
+
+{% endtab %}
+{% endtabs %}
+
+В результате вам придется обрабатывать исключение в своем Java-коде.
+Например, этот код не скомпилируется из-за необработанного исключения:
+
+{% tabs except-throw-usage %}
+{% tab Java %}
+
+```java
+// не скомпилируется, потому что исключение не обработано
+public class ScalaExceptionsInJava {
+ public static void main(String[] args) {
+ SExceptionThrower.exceptionThrower();
+ }
+}
+```
+
+{% endtab %}
+{% endtabs %}
+
+Компилятор выдает следующую ошибку:
+
+```plain
+[error] ScalaExceptionsInJava: unreported exception java.lang.Exception;
+ must be caught or declared to be thrown
+[error] SExceptionThrower.exceptionThrower()
+```
+
+Хорошо — это то, что вы хотите: аннотация сообщает компилятору Java, что `exceptionThrower` может выдать исключение.
+Теперь, когда вы пишете код на Java, вы должны обрабатывать исключение с помощью блока `try`
+или объявлять, что ваш Java метод генерирует исключение.
+
+И наоборот, если вы укажите аннотацию Scala метода `exceptionThrower`, код Java _будет скомпилирован_.
+Вероятно, это не то, что вам нужно, поскольку Java код может не учитывать метод Scala, выдающий исключение.
+
+## Как использовать vararg-параметры Scala в Java
+
+Если метод Scala имеет неопределенное количество параметров и вы хотите использовать этот метод в Java,
+отметьте Scala метод аннотацией `@varargs`.
+Например, метод `printAll` в этом Scala классе объявляет vararg-поле `String*`:
+
+{% tabs vararg-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+import scala.annotation.varargs
+
+object VarargsPrinter {
+ @varargs def printAll(args: String*): Unit = args.foreach(println)
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+import scala.annotation.varargs
+
+object VarargsPrinter:
+ @varargs def printAll(args: String*): Unit = args.foreach(println)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Поскольку `printAll` объявлен с аннотацией `@varargs`, его можно вызвать из Java программы
+с переменным количеством параметров, как показано в этом примере:
+
+{% tabs vararg-usage %}
+{% tab Java %}
+
+```java
+public class JVarargs {
+ public static void main(String[] args) {
+ VarargsPrinter.printAll("Hello", "world");
+ }
+}
+```
+
+{% endtab %}
+{% endtabs %}
+
+Запуск кода приводит к следующему выводу:
+
+```plain
+Hello
+world
+```
+
+## Создание альтернативных имен для использования методов Scala в Java
+
+В Scala вы можете создать имя метода, используя символический знак:
+
+{% tabs add-definition %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+def +(a: Int, b: Int) = a + b
+```
+
+{% endtab %}
+{% endtabs %}
+
+Такое имя метода корректно работать в Java не будет,
+но в Scala вы можете предоставить "альтернативное" имя метода с аннотацией `targetName`,
+которая будет именем метода при использовании из Java:
+
+{% tabs add-2-definition class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+import scala.annotation.targetName
+
+object Adder {
+ @targetName("add") def +(a: Int, b: Int) = a + b
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+import scala.annotation.targetName
+
+object Adder:
+ @targetName("add") def +(a: Int, b: Int) = a + b
+```
+
+{% endtab %}
+{% endtabs %}
+
+Теперь в вашем Java-коде вы можете использовать псевдоним метода `add`:
+
+{% tabs add-2-usage %}
+{% tab Java %}
+
+```java
+int x = Adder.add(1,1);
+System.out.printf("x = %d\n", x);
+```
+
+{% endtab %}
+{% endtabs %}
diff --git a/_ru/scala3/book/introduction.md b/_ru/scala3/book/introduction.md
new file mode 100644
index 0000000000..ae23a36516
--- /dev/null
+++ b/_ru/scala3/book/introduction.md
@@ -0,0 +1,38 @@
+---
+layout: multipage-overview
+title: Введение
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: На этой странице начинается обзорная документация по языку Scala 3.
+language: ru
+num: 1
+previous-page:
+next-page: scala-features
+---
+
+Добро пожаловать в книгу по Scala 3.
+Цель этой книги — предоставить неформальное введение в язык Scala.
+Она относительно легко затрагивает все темы Scala.
+Если в какой-то момент во время чтения этой книги вы захотите получить дополнительную информацию о конкретной функции,
+можете воспользоваться ссылкой на нашу [Справочную документацию][reference],
+в которой более подробно рассматриваются многие новые функции языка Scala.
+
+
+ Если вас интересует заархивированное издание книги для Scala 2,
+доступ к нему можно получить здесь.
+В настоящее время мы находимся в процессе слияния двух книг, и вы можете нам помочь.
+
+
+В этой книге мы надеемся продемонстрировать, что Scala — это красивый, выразительный язык программирования с чистым современным синтаксисом,
+который поддерживает и функциональное программирование (ФП), и объектно-ориентированное программирование (ООП),
+а также обеспечивает безопасную статическую систему типов.
+Синтаксис, грамматика и функции Scala были переосмыслены, открыто обсуждались и были обновлены в 2020 году,
+чтобы стать яснее и проще для понимания, чем когда-либо прежде.
+
+Книга начинается с беглого обзора возможностей Scala в [разделе “Почувствуй Scala”][taste].
+После этого обзора в следующих разделах содержится более подробная информация о рассмотренных языковых функциях.
+
+[reference]: {{ site.scala3ref }}/overview.html
+[taste]: {% link _overviews/scala3-book/taste-intro.md %}
diff --git a/_ru/scala3/book/methods-intro.md b/_ru/scala3/book/methods-intro.md
new file mode 100644
index 0000000000..de34fc1166
--- /dev/null
+++ b/_ru/scala3/book/methods-intro.md
@@ -0,0 +1,22 @@
+---
+layout: multipage-overview
+title: Методы
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: В этой главе представлены методы в Scala 3.
+language: ru
+num: 24
+previous-page: domain-modeling-fp
+next-page: methods-most
+---
+
+
+В Scala 2 _методы_ могут быть определены внутри классов, трейтов, объектов, `case` классов и `case` объектов.
+Но стало еще лучше: в Scala 3 они также могут быть определены вне любой из этих конструкций;
+мы говорим, что это определения "верхнего уровня", поскольку они не вложены в другое определение.
+Короче говоря, теперь методы можно определять где угодно.
+
+Многие особенности методов демонстрируются в следующем разделе.
+Поскольку `main` методы требуют немного больше пояснений, они описаны в одном из следующих разделов отдельно.
diff --git a/_ru/scala3/book/methods-main-methods.md b/_ru/scala3/book/methods-main-methods.md
new file mode 100644
index 0000000000..cd6342216a
--- /dev/null
+++ b/_ru/scala3/book/methods-main-methods.md
@@ -0,0 +1,205 @@
+---
+layout: multipage-overview
+title: Main методы в Scala 3
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице описывается, как основные методы и аннотация @main работают в Scala 3.
+language: ru
+num: 26
+previous-page: methods-most
+next-page: methods-summary
+---
+
+
Написание однострочных программ только в Scala 3
+
+Scala 3 предлагает следующий способ определения программ, которые можно вызывать из командной строки:
+добавление аннотации `@main` к методу превращает его в точку входа исполняемой программы:
+
+{% tabs method_1 %}
+{% tab 'Только в Scala 3' for=method_1 %}
+
+```scala
+@main def hello() = println("Hello, World")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Для запуска программы достаточно сохранить эту строку кода в файле с именем, например, _Hello.scala_
+(имя файла необязательно должно совпадать с именем метода) и запустить с помощью `scala`:
+
+```bash
+$ scala Hello.scala
+Hello, World
+```
+
+Аннотированный метод `@main` может быть написан либо на верхнем уровне (как показано),
+либо внутри статически доступного объекта.
+В любом случае имя программы - это имя метода без каких-либо префиксов объектов.
+
+Узнайте больше об аннотации `@main`, прочитав следующие разделы или посмотрев это видео:
+
+
+
+
+
+### Аргументы командной строки
+
+Метод `@main` может обрабатывать аргументы командной строки с различными типами.
+Например, данный метод `@main`, который принимает параметры `Int`, `String` и дополнительные строковые параметры:
+
+{% tabs method_2 %}
+{% tab 'Только в Scala 3' for=method_2 %}
+
+```scala
+@main def happyBirthday(age: Int, name: String, others: String*) =
+ val suffix = (age % 100) match
+ case 11 | 12 | 13 => "th"
+ case _ => (age % 10) match
+ case 1 => "st"
+ case 2 => "nd"
+ case 3 => "rd"
+ case _ => "th"
+
+ val sb = StringBuilder(s"Happy $age$suffix birthday, $name")
+ for other <- others do sb.append(" and ").append(other)
+ println(sb.toString)
+```
+
+{% endtab %}
+{% endtabs %}
+
+После компиляции кода создается основная программа с именем `happyBirthday`, которая вызывается следующим образом:
+
+```
+$ scala happyBirthday 23 Lisa Peter
+Happy 23rd Birthday, Lisa and Peter!
+```
+
+Как показано, метод `@main` может иметь произвольное количество параметров.
+Для каждого типа параметра должен существовать [given экземпляр][given]
+класса типа `scala.util.CommandLineParser.FromString`, который преобразует аргумент из `String` в требуемый тип параметра.
+Также, как показано, список параметров основного метода может заканчиваться повторяющимся параметром типа `String*`,
+который принимает все оставшиеся аргументы, указанные в командной строке.
+
+Программа, реализованная с помощью метода `@main`, проверяет,
+что в командной строке достаточно аргументов для заполнения всех параметров,
+и что строки аргументов могут быть преобразованы в требуемые типы.
+Если проверка завершается неудачей, программа завершается с сообщением об ошибке:
+
+```
+$ scala happyBirthday 22
+Illegal command line after first argument: more arguments expected
+
+$ scala happyBirthday sixty Fred
+Illegal command line: java.lang.NumberFormatException: For input string: "sixty"
+```
+
+## Пользовательские типы как параметры
+
+Как упоминалось выше, компилятор ищет заданный экземпляр класса типов `scala.util.CommandLineParser.FromString`
+для типа аргумента. Например, предположим, что у вас есть собственный тип `Color`,
+который вы хотите использовать в качестве параметра.
+Вы можете сделать это, как показано ниже:
+
+{% tabs method_3 %}
+{% tab 'Только в Scala 3' for=method_3 %}
+
+```scala
+enum Color:
+ case Red, Green, Blue
+
+given ComamndLineParser.FromString[Color] with
+ def fromString(value: String): Color = Color.valueOf(value)
+
+@main def run(color: Color): Unit =
+ println(s"The color is ${color.toString}")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Это работает одинаково для ваших собственных пользовательских типов в вашей программе,
+а также для типов, которые можно использовать из другой библиотеки.
+
+## Детали
+
+Компилятор Scala генерирует программу из `@main` метода `f` следующим образом:
+
+- он создает класс с именем `f` в пакете, где был найден метод `@main`.
+- класс имеет статический метод `main` с обычной сигнатурой Java `main` метода:
+ принимает `Array[String]` в качестве аргумента и возвращает `Unit`.
+- сгенерированный `main` метод вызывает метод `f` с аргументами,
+ преобразованными с помощью методов в объекте `scala.util.CommandLineParser.FromString`.
+
+Например, приведенный выше метод `happyBirthday` генерирует дополнительный код, эквивалентный следующему классу:
+
+{% tabs method_4 %}
+{% tab 'Только в Scala 3' for=method_4 %}
+
+```scala
+final class happyBirthday {
+ import scala.util.{CommandLineParser as CLP}
+ def main(args: Array[String]): Unit =
+ try
+ happyBirthday(
+ CLP.parseArgument[Int](args, 0),
+ CLP.parseArgument[String](args, 1),
+ CLP.parseRemainingArguments[String](args, 2)*)
+ catch {
+ case error: CLP.ParseError => CLP.showError(error)
+ }
+}
+```
+
+> Примечание: В этом сгенерированном коде модификатор `` выражает,
+> что `main` метод генерируется как статический метод класса `happyBirthday`.
+> Эта функция недоступна для пользовательских программ в Scala.
+> Вместо неё обычные “статические” члены генерируются в Scala с использованием `object`.
+
+{% endtab %}
+{% endtabs %}
+
+## Обратная совместимость со Scala 2
+
+`@main` методы — это рекомендуемый способ создания программ, вызываемых из командной строки в Scala 3.
+Они заменяют предыдущий подход, который заключался в создании `object`, расширяющего класс `App`:
+
+Прежняя функциональность `App`, основанная на "волшебном" `DelayedInit trait`, больше недоступна.
+`App` все еще существует в ограниченной форме, но не поддерживает аргументы командной строки и будет объявлен устаревшим в будущем.
+
+Если программам необходимо выполнять перекрестную сборку между Scala 2 и Scala 3,
+вместо этого рекомендуется использовать `object` с явным методом `main` и одним аргументом `Array[String]`:
+
+{% tabs method_5 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+object happyBirthday {
+ private def happyBirthday(age: Int, name: String, others: String*) = {
+ ... // тоже, что и раньше
+ }
+ def main(args: Array[String]): Unit =
+ happyBirthday(args(0).toInt, args(1), args.drop(2).toIndexedSeq:_*)
+}
+```
+
+> обратите внимание, что здесь мы используем `:_*` для передачи переменного числа аргументов,
+> который остается в Scala 3 для обратной совместимости.
+
+{% endtab %}
+{% endtabs %}
+
+Если вы поместите этот код в файл с именем _happyBirthday.scala_, то сможете скомпилировать его с `scalac`
+и запустить с помощью `scala`, как показывалось ранее:
+
+```bash
+$ scalac happyBirthday.scala
+
+$ scala happyBirthday 23 Lisa Peter
+Happy 23rd Birthday, Lisa and Peter!
+```
+
+[given]: {% link _overviews/scala3-book/ca-context-parameters.md %}
diff --git a/_ru/scala3/book/methods-most.md b/_ru/scala3/book/methods-most.md
new file mode 100644
index 0000000000..b3d8f6ed81
--- /dev/null
+++ b/_ru/scala3/book/methods-most.md
@@ -0,0 +1,712 @@
+---
+layout: multipage-overview
+title: Особенности методов
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлены методы Scala 3, включая main методы, методы расширения и многое другое.
+language: ru
+num: 25
+previous-page: methods-intro
+next-page: methods-main-methods
+---
+
+В этом разделе представлены различные аспекты определения и вызова методов в Scala 3.
+
+## Определение методов
+
+В Scala методы обладают множеством особенностей, в том числе:
+
+- Generic (типовые) параметры
+- Значения параметров по умолчанию
+- Несколько групп параметров
+- Контекстные параметры
+- Параметры по имени
+- и другие…
+
+Некоторые из этих функций демонстрируются в этом разделе, но когда вы определяете “простой” метод,
+который не использует эти функции, синтаксис выглядит следующим образом:
+
+{% tabs method_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_1 %}
+
+```scala
+def methodName(param1: Type1, param2: Type2): ReturnType = {
+ // тело метода
+ // находится здесь
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_1 %}
+
+```scala
+def methodName(param1: Type1, param2: Type2): ReturnType =
+ // тело метода
+ // находится здесь
+end methodName // опционально
+```
+
+{% endtab %}
+{% endtabs %}
+
+В этом синтаксисе:
+
+- ключевое слово `def` используется для определения метода
+- для наименования методов согласно стандартам Scala используется camel case convention
+- у параметров метода необходимо всегда указывать тип
+- возвращаемый тип метода указывать необязательно
+- методы могут состоять как только из одной строки, так и из нескольких строк
+- метку окончания метода `end methodName` указывать необязательно, её рекомендуется указывать только для длинных методов
+
+Вот два примера однострочного метода с именем `add`, который принимает два входных параметра `Int`.
+Первая версия явно показывает возвращаемый тип метода - `Int`, а вторая - нет:
+
+{% tabs method_2 %}
+{% tab 'Scala 2 и 3' for=method_2 %}
+
+```scala
+def add(a: Int, b: Int): Int = a + b
+def add(a: Int, b: Int) = a + b
+```
+
+{% endtab %}
+{% endtabs %}
+
+У публичных методов рекомендуется всегда указывать тип возвращаемого значения.
+Объявление возвращаемого типа может упростить его понимание при просмотре кода другого человека
+или своего кода спустя некоторое время.
+
+## Вызов методов
+
+Вызов методов прост:
+
+{% tabs method_3 %}
+{% tab 'Scala 2 и 3' for=method_3 %}
+
+```scala
+val x = add(1, 2) // 3
+```
+
+{% endtab %}
+{% endtabs %}
+
+Коллекции Scala имеют десятки встроенных методов.
+Эти примеры показывают, как их вызывать:
+
+{% tabs method_4 %}
+{% tab 'Scala 2 и 3' for=method_4 %}
+
+```scala
+val x = List(1, 2, 3)
+
+x.size // 3
+x.contains(1) // true
+x.map(_ * 10) // List(10, 20, 30)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Внимание:
+
+- `size` не принимает аргументов и возвращает количество элементов в списке
+- метод `contains` принимает один аргумент — значение для поиска
+- `map` принимает один аргумент - функцию; в данном случае в него передается анонимная функция
+
+## Многострочные методы
+
+Если метод длиннее одной строки, начинайте тело метода со второй строки с отступом вправо:
+
+{% tabs method_5 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_5 %}
+
+```scala
+def addThenDouble(a: Int, b: Int): Int = {
+ // представим, что это тело метода требует несколько строк
+ val sum = a + b
+ sum * 2
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_5 %}
+
+```scala
+def addThenDouble(a: Int, b: Int): Int =
+ // представим, что это тело метода требует несколько строк
+ val sum = a + b
+ sum * 2
+```
+
+{% endtab %}
+{% endtabs %}
+
+В этом методе:
+
+- `sum` — неизменяемая локальная переменная; к ней нельзя получить доступ вне метода
+- последняя строка удваивает значение `sum` - именно это значение возвращается из метода
+
+Когда вы вставите этот код в REPL, то увидите, что он работает как требовалось:
+
+{% tabs method_6 %}
+{% tab 'Scala 2 и 3' for=method_6 %}
+
+```scala
+scala> addThenDouble(1, 1)
+res0: Int = 4
+```
+
+{% endtab %}
+{% endtabs %}
+
+Обратите внимание, что нет необходимости в операторе `return` в конце метода.
+Поскольку почти все в Scala является _выражением_ — то это означает,
+что каждая строка кода возвращает (или _вычисляет_) значение — нет необходимости использовать `return`.
+
+Это видно на примере того же метода, но в более сжатой форме:
+
+{% tabs method_7 %}
+{% tab 'Scala 2 и 3' for=method_7 %}
+
+```scala
+def addThenDouble(a: Int, b: Int): Int = (a + b) * 2
+```
+
+{% endtab %}
+{% endtabs %}
+
+В теле метода можно использовать все возможности Scala:
+
+- `if`/`else` выражения
+- `match` выражения
+- циклы `while`
+- циклы `for` и `for` выражения
+- присвоение переменных
+- вызовы других методов
+- определения других методов
+
+В качестве ещё одного примера многострочного метода,
+`getStackTraceAsString` преобразует свой входной параметр `Throwable` в правильно отформатированную строку:
+
+{% tabs method_8 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_8 %}
+
+```scala
+def getStackTraceAsString(t: Throwable): String = {
+ val sw = new StringWriter()
+ t.printStackTrace(new PrintWriter(sw))
+ sw.toString
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_8 %}
+
+```scala
+def getStackTraceAsString(t: Throwable): String =
+ val sw = StringWriter()
+ t.printStackTrace(PrintWriter(sw))
+ sw.toString
+```
+
+{% endtab %}
+{% endtabs %}
+
+В этом методе:
+
+- в первой строке переменная `sw` принимает значение нового экземпляра `StringWriter`
+- вторая строка сохраняет содержимое трассировки стека в `StringWriter`
+- третья строка возвращает строковое представление трассировки стека
+
+## Значения параметров по умолчанию
+
+Параметры метода могут иметь значения по умолчанию.
+В этом примере для параметров `timeout` и `protocol` заданы значения по умолчанию:
+
+{% tabs method_9 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_9 %}
+
+```scala
+def makeConnection(timeout: Int = 5_000, protocol: String = "http") = {
+ println(f"timeout = ${timeout}%d, protocol = ${protocol}%s")
+ // здесь ещё какой-то код ...
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_9 %}
+
+```scala
+def makeConnection(timeout: Int = 5_000, protocol: String = "http") =
+ println(f"timeout = ${timeout}%d, protocol = ${protocol}%s")
+ // здесь ещё какой-то код ...
+```
+
+{% endtab %}
+{% endtabs %}
+
+Поскольку параметры имеют значения по умолчанию, метод можно вызвать следующими способами:
+
+{% tabs method_10 %}
+{% tab 'Scala 2 и 3' for=method_10 %}
+
+```scala
+makeConnection() // timeout = 5000, protocol = http
+makeConnection(2_000) // timeout = 2000, protocol = http
+makeConnection(3_000, "https") // timeout = 3000, protocol = https
+```
+
+{% endtab %}
+{% endtabs %}
+
+Вот несколько ключевых моментов об этих примерах:
+
+- В первом примере аргументы не предоставляются, поэтому метод использует значения параметров по умолчанию: `5_000` и `http`
+- Во втором примере для параметра `timeout` указывается значение `2_000`,
+ поэтому оно используется вместе со значением по умолчанию для `protocol`
+- В третьем примере значения указаны для обоих параметров, поэтому используются они.
+
+Обратите внимание, что при использовании значений параметров по умолчанию потребителю кажется,
+что он может работать с тремя разными переопределенными методами.
+
+## Именованные параметры
+
+При желании вы также можете использовать имена параметров метода при его вызове.
+Например, `makeConnection` может также вызываться следующими способами:
+
+{% tabs method_11 %}
+{% tab 'Scala 2 и 3' for=method_11 %}
+
+```scala
+makeConnection(timeout=10_000)
+makeConnection(protocol="https")
+makeConnection(timeout=10_000, protocol="https")
+makeConnection(protocol="https", timeout=10_000)
+```
+
+{% endtab %}
+{% endtabs %}
+
+В некоторых фреймворках именованные параметры используются постоянно.
+Они также очень полезны, когда несколько параметров метода имеют один и тот же тип:
+
+{% tabs method_12 %}
+{% tab 'Scala 2 и 3' for=method_12 %}
+
+```scala
+engage(true, true, true, false)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Без помощи IDE этот код может быть трудночитаемым, но так он становится намного понятнее и очевиднее:
+
+{% tabs method_13 %}
+{% tab 'Scala 2 и 3' for=method_13 %}
+
+```scala
+engage(
+ speedIsSet = true,
+ directionIsSet = true,
+ picardSaidMakeItSo = true,
+ turnedOffParkingBrake = false
+)
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Рекомендации о методах, которые не принимают параметров
+
+Когда метод не принимает параметров, говорят, что он имеет _arity_ уровень 0 (_arity-0_).
+Аналогично, если метод принимает один параметр - это метод с _arity-1_.
+
+Когда создаются методы _arity-0_:
+
+- если метод выполняет побочные эффекты, такие как вызов `println`, метод объявляется с пустыми скобками.
+- если метод не выполняет побочных эффектов, например, получение размера коллекции,
+ что аналогично доступу к полю в коллекции, круглые скобки опускаются.
+
+Например, этот метод выполняет побочный эффект, поэтому он объявлен с пустыми скобками:
+
+{% tabs method_14 %}
+{% tab 'Scala 2 и 3' for=method_14 %}
+
+```scala
+def speak() = println("hi")
+```
+
+{% endtab %}
+{% endtabs %}
+
+При вызове метода нужно обязательно указывать круглые скобки, если он был объявлен с ними:
+
+{% tabs method_15 %}
+{% tab 'Scala 2 и 3' for=method_15 %}
+
+```scala
+speak // ошибка: "method speak must be called with () argument"
+speak() // печатает "hi"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Хотя это всего лишь соглашение, его соблюдение значительно улучшает читаемость кода:
+с первого взгляда становится понятно, что метод с arity-0 имеет побочные эффекты.
+
+## Использование `if` в качестве тела метода
+
+Поскольку выражения `if`/`else` возвращают значение, их можно использовать в качестве тела метода.
+Вот метод с именем `isTruthy`, реализующий Perl-определения `true` и `false`:
+
+{% tabs method_16 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_16 %}
+
+```scala
+def isTruthy(a: Any) = {
+ if (a == 0 || a == "" || a == false)
+ false
+ else
+ true
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_16 %}
+
+```scala
+def isTruthy(a: Any) =
+ if a == 0 || a == "" || a == false then
+ false
+ else
+ true
+```
+
+{% endtab %}
+{% endtabs %}
+
+Примеры показывают, как работает метод:
+
+{% tabs method_17 %}
+{% tab 'Scala 2 и 3' for=method_17 %}
+
+```scala
+isTruthy(0) // false
+isTruthy("") // false
+isTruthy("hi") // true
+isTruthy(1.0) // true
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Использование `match` в качестве тела метода
+
+Довольно часто в качестве тела метода используются `match`-выражения.
+Вот еще одна версия `isTruthy`, написанная с `match` выражением:
+
+{% tabs method_18 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_18 %}
+
+```scala
+def isTruthy(a: Any) = a match {
+ case 0 | "" | false => false
+ case _ => true
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_18 %}
+
+```scala
+def isTruthy(a: Matchable) = a match
+ case 0 | "" | false => false
+ case _ => true
+```
+
+> Этот метод работает точно так же, как и предыдущий, в котором использовалось выражение `if`/`else`.
+> Вместо `Any` в качестве типа параметра используется `Matchable`, чтобы принять любое значение,
+> поддерживающее сопоставление с образцом (pattern matching).
+
+> См. дополнительную информацию о trait `Matchable` в [Справочной документации][reference_matchable].
+
+[reference_matchable]: {{ site.scala3ref }}/other-new-features/matchable.html
+{% endtab %}
+{% endtabs %}
+
+## Контроль видимости методов в классах
+
+В классах, объектах, trait-ах и enum-ах методы Scala по умолчанию общедоступны,
+поэтому созданный здесь экземпляр `Dog` может получить доступ к методу `speak`:
+
+{% tabs method_19 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_19 %}
+
+```scala
+class Dog {
+ def speak() = println("Woof")
+}
+
+val d = new Dog
+d.speak() // печатает "Woof"
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_19 %}
+
+```scala
+class Dog:
+ def speak() = println("Woof")
+
+val d = new Dog
+d.speak() // печатает "Woof"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Также методы можно помечать как `private`.
+Это делает их закрытыми в текущем классе, поэтому их нельзя вызвать или переопределить в подклассах:
+
+{% tabs method_20 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_20 %}
+```scala
+class Animal {
+ private def breathe() = println("I’m breathing")
+}
+
+class Cat extends Animal {
+ // этот метод не скомпилируется
+ override def breathe() = println("Yo, I’m totally breathing")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_20 %}
+
+```scala
+class Animal:
+ private def breathe() = println("I’m breathing")
+
+class Cat extends Animal:
+ // этот метод не скомпилируется
+ override def breathe() = println("Yo, I’m totally breathing")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Если необходимо сделать метод закрытым в текущем классе, но разрешить подклассам вызывать или переопределять его,
+метод помечается как `protected`, как показано в примере с методом `speak`:
+
+{% tabs method_21 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_21 %}
+
+```scala
+class Animal {
+ private def breathe() = println("I’m breathing")
+ def walk() = {
+ breathe()
+ println("I’m walking")
+ }
+ protected def speak() = println("Hello?")
+}
+
+class Cat extends Animal {
+ override def speak() = println("Meow")
+}
+
+val cat = new Cat
+cat.walk()
+cat.speak()
+cat.breathe() // не скомпилируется, потому что private
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_21 %}
+
+```scala
+class Animal:
+ private def breathe() = println("I’m breathing")
+ def walk() =
+ breathe()
+ println("I’m walking")
+ protected def speak() = println("Hello?")
+
+class Cat extends Animal:
+ override def speak() = println("Meow")
+
+val cat = new Cat
+cat.walk()
+cat.speak()
+cat.breathe() // не скомпилируется, потому что private
+```
+
+{% endtab %}
+{% endtabs %}
+
+Настройка `protected` означает:
+
+- к методу (или полю) могут обращаться другие экземпляры того же класса
+- метод (или поле) не виден в текущем пакете
+- он доступен для подклассов
+
+## Методы в объектах
+
+Ранее было показано, что trait-ы и классы могут иметь методы.
+Ключевое слово `object` используется для создания одноэлементного класса, и объект также может содержать методы.
+Это хороший способ сгруппировать набор “служебных” методов.
+Например, этот объект содержит набор методов, которые работают со строками:
+
+{% tabs method_22 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_22 %}
+
+```scala
+object StringUtils {
+
+ /**
+ * Returns a string that is the same as the input string, but
+ * truncated to the specified length.
+ */
+ def truncate(s: String, length: Int): String = s.take(length)
+
+ /**
+ * Returns true if the string contains only letters and numbers.
+ */
+ def lettersAndNumbersOnly_?(s: String): Boolean =
+ s.matches("[a-zA-Z0-9]+")
+
+ /**
+ * Returns true if the given string contains any whitespace
+ * at all. Assumes that `s` is not null.
+ */
+ def containsWhitespace(s: String): Boolean =
+ s.matches(".*\\s.*")
+
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=method_22 %}
+
+```scala
+object StringUtils:
+
+ /**
+ * Returns a string that is the same as the input string, but
+ * truncated to the specified length.
+ */
+ def truncate(s: String, length: Int): String = s.take(length)
+
+ /**
+ * Returns true if the string contains only letters and numbers.
+ */
+ def lettersAndNumbersOnly_?(s: String): Boolean =
+ s.matches("[a-zA-Z0-9]+")
+
+ /**
+ * Returns true if the given string contains any whitespace
+ * at all. Assumes that `s` is not null.
+ */
+ def containsWhitespace(s: String): Boolean =
+ s.matches(".*\\s.*")
+
+end StringUtils
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Методы расширения
+
+Есть много ситуаций, когда необходимо добавить функциональность к закрытым классам.
+Например, представьте, что у вас есть класс `Circle`, но вы не можете изменить его исходный код.
+Это может быть определено в сторонней библиотеке так:
+
+{% tabs method_23 %}
+{% tab 'Scala 2 и 3' for=method_23 %}
+
+```scala
+case class Circle(x: Double, y: Double, radius: Double)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Если вы хотите добавить методы в этот класс, то можете определить их как методы расширения, например:
+
+{% tabs method_24 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_24 %}
+
+```scala
+implicit class CircleOps(c: Circle) {
+ def circumference: Double = c.radius * math.Pi * 2
+ def diameter: Double = c.radius * 2
+ def area: Double = math.Pi * c.radius * c.radius
+}
+```
+В Scala 2 используйте `implicit class`, подробности [здесь](/overviews/core/implicit-classes.html).
+
+{% endtab %}
+{% tab 'Scala 3' for=method_24 %}
+
+```scala
+extension (c: Circle)
+ def circumference: Double = c.radius * math.Pi * 2
+ def diameter: Double = c.radius * 2
+ def area: Double = math.Pi * c.radius * c.radius
+```
+В Scala 3 используйте новую конструкцию `extension`.
+Дополнительные сведения см. [в главах этой книги][extension] или [в справочнике по Scala 3][reference-ext].
+
+[reference-ext]: {{ site.scala3ref }}/contextual/extension-methods.html
+[extension]: {% link _overviews/scala3-book/ca-extension-methods.md %}
+{% endtab %}
+{% endtabs %}
+
+Теперь, когда у вас есть экземпляр `Circle` с именем `aCircle`,
+то вы можете вызывать эти методы следующим образом:
+
+{% tabs method_25 %}
+{% tab 'Scala 2 и 3' for=method_25 %}
+
+```scala
+aCircle.circumference
+aCircle.diameter
+aCircle.area
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Дальнейшее изучение
+
+Есть много чего, что можно узнать о методах, в том числе:
+
+- Вызов методов в суперклассах
+- Определение и использование параметров по имени
+- Написание метода, который принимает параметр функции
+- Создание встроенных методов
+- Обработка исключений
+- Использование входных параметров vararg
+- Написание методов с несколькими группами параметров (частично применяемые функции).
+- Создание методов с параметрами универсального типа.
+
+Дополнительные сведения об этих функциях см. в других главах этой книги.
+
+[reference_extension_methods]: {{ site.scala3ref }}/contextual/extension-methods.html
+[reference_matchable]: {{ site.scala3ref }}/other-new-features/matchable.html
diff --git a/_ru/scala3/book/methods-summary.md b/_ru/scala3/book/methods-summary.md
new file mode 100644
index 0000000000..029c4de687
--- /dev/null
+++ b/_ru/scala3/book/methods-summary.md
@@ -0,0 +1,30 @@
+---
+layout: multipage-overview
+title: Обзор
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: Эта страница подводит итог предыдущим разделам о методах в Scala 3.
+language: ru
+num: 27
+previous-page: methods-main-methods
+next-page: fun-intro
+---
+
+
+Есть ещё много чего, что можно узнать о методах, в том числе:
+
+- Вызов методов в суперклассах
+- Определение и использование параметров по имени
+- Создание метода, который принимает функцию в качестве параметра
+- Создание встроенных (_inline_) методов
+- Обработка исключений
+- Использование переменного числа входных параметров
+- Создание методов с несколькими группами параметров (частично применяемые функции)
+- Создание методов с параметрами универсального типа
+
+Дополнительные сведения об этих функциях доступны в [справочной документации][reference].
+
+
+[reference]: {{ site.scala3ref }}/overview.html
diff --git a/_ru/scala3/book/packaging-imports.md b/_ru/scala3/book/packaging-imports.md
new file mode 100644
index 0000000000..49b5da759d
--- /dev/null
+++ b/_ru/scala3/book/packaging-imports.md
@@ -0,0 +1,418 @@
+---
+layout: multipage-overview
+title: Пакеты и импорт
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: Обсуждение использования пакетов и импорта для организации кода, создания связанных модулей кода, управления областью действия и предотвращения конфликтов пространств имен.
+language: ru
+num: 36
+previous-page: fun-summary
+next-page: collections-intro
+---
+
+
+Scala использует _packages_ для создания пространств имен, которые позволяют модульно разбивать программы.
+Scala поддерживает стиль именования пакетов, используемый в Java, а также нотацию пространства имен “фигурные скобки”,
+используемую такими языками, как C++ и C#.
+
+Подход Scala к импорту похож на Java, но более гибкий.
+С помощью Scala можно:
+
+- импортировать пакеты, классы, объекты, trait-ы и методы
+- размещать операторы импорта в любом месте
+- скрывать и переименовывать участников при импорте
+
+Эти особенности демонстрируются в следующих примерах.
+
+
+## Создание пакета
+
+Пакеты создаются путем объявления одного или нескольких имен пакетов в начале файла Scala.
+Например, если ваше доменное имя _acme.com_ и вы работаете с пакетом _model_ приложения с именем _myapp_,
+объявление пакета выглядит следующим образом:
+
+```scala
+package com.acme.myapp.model
+
+class Person ...
+```
+
+По соглашению все имена пакетов должны быть строчными,
+а формальным соглашением об именах является _\.\.\.\_.
+
+Хотя это и не обязательно, имена пакетов обычно совпадают с именами иерархии каталогов.
+Поэтому, если следовать этому соглашению, класс `Person` в этом проекте будет найден
+в файле _MyApp/src/main/scala/com/acme/myapp/model/Person.scala_.
+
+
+### Использование нескольких пакетов в одном файле
+
+Показанный выше синтаксис применяется ко всему исходному файлу:
+все определения в файле `Person.scala` принадлежат пакету `com.acme.myapp.model`
+в соответствии с предложением `package` в начале файла.
+
+В качестве альтернативы можно написать `package`, которые применяются только к содержащимся в них определениям:
+
+```scala
+package users:
+
+ package administrators: // полное имя пакета - users.administrators
+ class AdminUser // полное имя класса - users.administrators.AdminUser
+
+ package normalusers: // полное имя пакета - users.normalusers
+ class NormalUser // полное имя класса - users.normalusers.NormalUser
+```
+
+Обратите внимание, что за именами пакетов следует двоеточие, а определения внутри пакета имеют отступ.
+
+Преимущество этого подхода заключается в том, что он допускает вложение пакетов
+и обеспечивает более очевидный контроль над областью видимости и инкапсуляцией, особенно в пределах одного файла.
+
+
+## Операторы импорта
+
+Операторы импорта используются для доступа к сущностям в других пакетах.
+Операторы импорта делятся на две основные категории:
+
+- импорт классов, трейтов, объектов, функций и методов
+- импорт `given` предложений
+
+Первая категория операторов импорта аналогична тому, что использует Java,
+с немного другим синтаксисом, обеспечивающим большую гибкость.
+Пример:
+
+````
+import users.* // импортируется все из пакета `users`
+import users.User // импортируется только класс `User`
+import users.{User, UserPreferences} // импортируются только два члена пакета
+import users.{UserPreferences as UPrefs} // переименование импортированного члена
+````
+
+Эти примеры предназначены для того, чтобы дать представление о том, как работает первая категория операторов `import`.
+Более подробно они объясняются в следующих подразделах.
+
+Операторы импорта также используются для импорта `given` экземпляров в область видимости.
+Они обсуждаются в конце этой главы.
+
+> import не требуется для доступа к членам одного и того же пакета.
+
+
+### Импорт одного или нескольких членов
+
+В Scala импортировать один элемент из пакета можно следующим образом:
+
+```scala
+import scala.concurrent.Future
+```
+
+несколько:
+
+```scala
+import scala.concurrent.Future
+import scala.concurrent.Promise
+import scala.concurrent.blocking
+```
+
+При импорте нескольких элементов их можно импортировать более лаконично:
+
+```scala
+import scala.concurrent.{Future, Promise, blocking}
+```
+
+Если необходимо импортировать все из пакета _scala.concurrent_, используется такой синтаксис:
+
+```scala
+import scala.concurrent.*
+```
+
+
+### Переименование элементов при импорте
+
+Иногда необходимо переименовать объекты при их импорте, чтобы избежать конфликтов имен.
+Например, если нужно использовать Scala класс `List` вместе с `java.util.List`,
+то можно переименовать `java.util.List` при импорте:
+
+```scala
+import java.util.{List as JavaList}
+```
+
+Теперь имя `JavaList` можно использовать для ссылки на класс `java.util.List`
+и использовать `List` для ссылки на Scala класс `List`.
+
+Также можно переименовывать несколько элементов одновременно, используя следующий синтаксис:
+
+```scala
+import java.util.{Date as JDate, HashMap as JHashMap, *}
+```
+
+В этой строке кода говорится следующее: “Переименуйте классы `Date` и `HashMap`, как показано,
+и импортируйте все остальное из пакета `java.util`, не переименовывая”.
+
+
+### Скрытие членов при импорте
+
+При импорте часть объектов можно _скрывать_.
+Следующий оператор импорта скрывает класс `java.util.Random`,
+в то время как все остальное в пакете `java.util` импортируется:
+
+```scala
+import java.util.{Random as _, *}
+```
+
+Если попытаться получить доступ к классу `Random`, то выдается ошибка,
+но есть доступ ко всем остальным членам пакета `java.util`:
+
+```scala
+val r = new Random // не скомпилируется
+new ArrayList // доступ есть
+```
+
+#### Скрытие нескольких элементов
+
+Чтобы скрыть в import несколько элементов, их можно перечислить перед использованием постановочного знака:
+
+```scala
+scala> import java.util.{List as _, Map as _, Set as _, *}
+```
+
+Перечисленные классы скрыты, но можно использовать все остальное в _java.util_:
+
+```scala
+scala> new ArrayList[String]
+val res0: java.util.ArrayList[String] = []
+```
+
+Поскольку эти Java классы скрыты, можно использовать классы Scala `List`, `Set` и `Map` без конфликта имен:
+
+```scala
+scala> val a = List(1, 2, 3)
+val a: List[Int] = List(1, 2, 3)
+
+scala> val b = Set(1, 2, 3)
+val b: Set[Int] = Set(1, 2, 3)
+
+scala> val c = Map(1 -> 1, 2 -> 2)
+val c: Map[Int, Int] = Map(1 -> 1, 2 -> 2)
+```
+
+
+### Импорт можно использовать в любом месте
+
+В Scala операторы `import` могут быть объявлены где угодно.
+Их можно использовать в верхней части файла исходного кода:
+
+```scala
+package foo
+
+import scala.util.Random
+
+class ClassA:
+ def printRandom(): Unit =
+ val r = new Random // класс Random здесь доступен
+ // ещё код...
+```
+
+Также операторы `import` можно использовать ближе к тому месту, где они необходимы:
+
+```scala
+package foo
+
+class ClassA:
+ import scala.util.Random // внутри ClassA
+ def printRandom(): Unit =
+ val r = new Random
+ // ещё код...
+
+class ClassB:
+ // класс Random здесь невидим
+ val r = new Random // этот код не скомпилится
+```
+
+
+### “Статический” импорт
+
+Если необходимо импортировать элементы способом, аналогичным подходу “статического импорта” в Java,
+то есть для того, чтобы напрямую обращаться к членам класса, не добавляя к ним префикс с именем класса,
+используется следующий подход.
+
+Синтаксис для импорта всех статических членов Java класса `Math`:
+
+```scala
+import java.lang.Math.*
+```
+
+Теперь можно получить доступ к статическим методам класса `Math`,
+таким как `sin` и `cos`, без необходимости предварять их именем класса:
+
+```scala
+import java.lang.Math.*
+
+val a = sin(0) // 0.0
+val b = cos(PI) // -1.0
+```
+
+
+### Пакеты, импортированные по умолчанию
+
+Два пакета неявно импортируются во все файлы исходного кода:
+
+- `java.lang.*`
+- `scala.*`
+
+Члены object `Predef` также импортируются по умолчанию.
+
+> Например, такие классы, как `List`, `Vector`, `Map` и т.д. можно использовать явно, не импортируя их -
+> они доступны, потому что определены в object `Predef`
+
+
+### Обработка конфликтов имен
+
+Если необходимо импортировать что-то из корня проекта и возникает конфликт имен,
+достаточно просто добавить к имени пакета префикс `_root_`:
+
+```
+package accounts
+
+import _root_.accounts.*
+```
+
+
+## Импорт экземпляров `given`
+
+Как будет показано в главе [“Контекстные абстракции”][contextual],
+для импорта экземпляров `given` используется специальная форма оператора `import`.
+Базовая форма показана в этом примере:
+
+```scala
+object A:
+ class TC
+ given tc: TC
+ def f(using TC) = ???
+
+object B:
+ import A.* // импорт всех non-given членов
+ import A.given // импорт экземпляров given
+```
+
+В этом коде предложение `import A.*` объекта `B` импортирует все элементы `A`, _кроме_ `given` экземпляра `tc`.
+И наоборот, второй импорт, `import A.given`, импортирует _только_ `given` экземпляр.
+Два предложения импорта также могут быть объединены в одно:
+
+```scala
+object B:
+ import A.{given, *}
+```
+
+### Обсуждение
+
+Селектор с подстановочным знаком `*` помещает в область видимости все определения, кроме `given`,
+тогда как селектор выше помещает в область действия все данные, включая те, которые являются результатом расширений.
+
+Эти правила имеют два основных преимущества:
+
+- более понятно, откуда берутся данные given.
+ В частности, невозможно скрыть импортированные given в длинном списке других импортируемых подстановочных знаков.
+- есть возможность импортировать все given, не импортируя ничего другого.
+ Это особенно важно, поскольку given могут быть анонимными, поэтому обычное использование именованного импорта нецелесообразно.
+
+
+### Импорт по типу
+
+Поскольку given-ы могут быть анонимными, не всегда практично импортировать их по имени,
+и вместо этого обычно используется импорт подстановочных знаков.
+_Импорт по типу_ предоставляет собой более конкретную альтернативу импорту с подстановочными знаками,
+делая понятным то, что импортируется.
+
+```scala
+import A.{given TC}
+```
+
+Этот код импортирует из `A` любой `given` тип, соответствующий `TC`.
+Импорт данных нескольких типов `T1,...,Tn` выражается несколькими `given` селекторами:
+
+```scala
+import A.{given T1, ..., given Tn}
+```
+
+Импорт всех `given` экземпляров параметризованного типа достигается аргументами с подстановочными знаками.
+Например, есть такой `объект`:
+
+```scala
+object Instances:
+ given intOrd: Ordering[Int]
+ given listOrd[T: Ordering]: Ordering[List[T]]
+ given ec: ExecutionContext = ...
+ given im: Monoid[Int]
+```
+
+Оператор `import` ниже импортирует экземпляры `intOrd`, `listOrd` и `ec`, но пропускает экземпляр `im`,
+поскольку он не соответствует ни одному из указанных шаблонов:
+
+```scala
+import Instances.{given Ordering[?], given ExecutionContext}
+```
+
+Импорт по типу можно смешивать с импортом по имени.
+Если оба присутствуют в предложении import, импорт по типу идет последним.
+Например, это предложение импорта импортирует `im`, `intOrd` и `listOrd`, но не включает `ec`:
+
+```scala
+import Instances.{im, given Ordering[?]}
+```
+
+
+### Пример
+
+В качестве конкретного примера представим, что у нас есть объект `MonthConversions`,
+который содержит два определения `given`:
+
+```scala
+object MonthConversions:
+ trait MonthConverter[A]:
+ def convert(a: A): String
+
+ given intMonthConverter: MonthConverter[Int] with
+ def convert(i: Int): String =
+ i match
+ case 1 => "January"
+ case 2 => "February"
+ // остальные случаи здесь ...
+
+ given stringMonthConverter: MonthConverter[String] with
+ def convert(s: String): String =
+ s match
+ case "jan" => "January"
+ case "feb" => "February"
+ // остальные случаи здесь ...
+```
+
+Чтобы импортировать эти given-ы в текущую область, используем два оператора `import`:
+
+```scala
+import MonthConversions.*
+import MonthConversions.{given MonthConverter[?]}
+```
+
+Теперь создаем метод, использующий эти экземпляры:
+
+```scala
+def genericMonthConverter[A](a: A)(using monthConverter: MonthConverter[A]): String =
+ monthConverter.convert(a)
+```
+
+Вызов метода:
+
+```scala
+@main def main =
+ println(genericMonthConverter(1)) // January
+ println(genericMonthConverter("jan")) // January
+```
+
+Как уже упоминалось ранее, одно из ключевых преимуществ синтаксиса “import given” состоит в том,
+чтобы прояснить, откуда берутся данные в области действия,
+и в `import` операторах выше ясно, что данные поступают из объекта `MonthConversions`.
+
+
+[contextual]: {% link _overviews/scala3-book/ca-contextual-abstractions-intro.md %}
diff --git a/_ru/scala3/book/scala-features.md b/_ru/scala3/book/scala-features.md
new file mode 100644
index 0000000000..5a0f3b50e5
--- /dev/null
+++ b/_ru/scala3/book/scala-features.md
@@ -0,0 +1,485 @@
+---
+layout: multipage-overview
+title: Возможности Scala
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: На этой странице рассматриваются основные возможности языка программирования Scala.
+language: ru
+num: 2
+previous-page: introduction
+next-page: why-scala-3
+---
+
+
+Название _Scala_ происходит от слова _scalable_, и в соответствии с этим названием язык Scala используется для
+поддержки загруженных веб-сайтов и анализа огромных наборов данных.
+В этом разделе представлены функции, которые делают Scala масштабируемым языком.
+Эти функции разделены на три раздела:
+
+- Функции высокоуровневого языка программирования
+- Функции низкоуровневого языка программирования
+- Особенности экосистемы Scala
+
+
+
+## Высокоуровневые функции
+
+Глядя на Scala с пресловутого “вида с высоты 30 000 фунтов”, вы можете сделать о нем следующие утверждения:
+
+- Это высокоуровневый язык программирования
+- Он имеет краткий, читаемый синтаксис
+- Он статически типизирован (но кажется динамичным)
+- Имеет выразительную систему типов
+- Это язык функционального программирования (ФП)
+- Это язык объектно-ориентированного программирования (ООП)
+- Он поддерживает слияние ФП и ООП
+- Контекстные абстракции обеспечивают понятный способ реализации _вывода терминов_ (_term inference_)
+- Он работает на JVM (и в браузере)
+- Беспрепятственно взаимодействует с Java кодом
+- Он используется для серверных приложений (включая микросервисы), приложений для работы с большими данными, а также может использоваться в браузере с помощью Scala.js
+
+Эти функции кратко рассматриваются в следующих разделах.
+
+
+### Высокоуровневый язык
+
+Scala считается высокоуровневым языком как минимум по двум причинам.
+Во-первых, подобно Java и многим другим современным языкам, вы не имеете дело с низкоуровневыми понятиями,
+такими как указатели и управление памятью.
+
+Во-вторых, с использованием лямбда-выражений и функций высшего порядка вы пишете свой код на очень высоком уровне.
+Как говорится в функциональном программировании, в Scala вы пишете то, _что_ хотите, а не то, _как_ этого добиться.
+То есть мы не пишем императивный код вот так:
+
+{% tabs scala-features-1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=scala-features-1 %}
+```scala
+import scala.collection.mutable.ListBuffer
+
+def double(ints: List[Int]): List[Int] = {
+ val buffer = new ListBuffer[Int]()
+ for (i <- ints) {
+ buffer += i * 2
+ }
+ buffer.toList
+}
+
+val oldNumbers = List(1, 2, 3)
+val newNumbers = double(oldNumbers)
+```
+{% endtab %}
+{% tab 'Scala 3' for=scala-features-1 %}
+```scala
+import scala.collection.mutable.ListBuffer
+
+def double(ints: List[Int]): List[Int] =
+ val buffer = new ListBuffer[Int]()
+ for i <- ints do
+ buffer += i * 2
+ buffer.toList
+
+val oldNumbers = List(1, 2, 3)
+val newNumbers = double(oldNumbers)
+```
+{% endtab %}
+{% endtabs %}
+
+Этот код шаг за шагом указывает компилятору, что делать.
+Вместо этого мы пишем высокоуровневый функциональный код, используя функции высшего порядка и лямбда-выражения,
+подобные этому, для вычисления того же результата:
+
+{% tabs scala-features-2 %}
+{% tab 'Scala 2 и 3' for=scala-features-2 %}
+```scala
+val newNumbers = oldNumbers.map(_ * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+
+Как видите, этот код намного лаконичнее, его легче читать и легче поддерживать.
+
+
+### Лаконичный синтаксис
+
+Scala имеет краткий, удобочитаемый синтаксис.
+Например, переменные создаются лаконично, а их типы понятны:
+
+{% tabs scala-features-3 %}
+{% tab 'Scala 2 и 3' for=scala-features-3 %}
+```scala
+val nums = List(1,2,3)
+val p = Person("Martin", "Odersky")
+```
+{% endtab %}
+{% endtabs %}
+
+
+Функции высшего порядка и лямбда-выражения делают код кратким и удобочитаемым:
+
+{% tabs scala-features-4 %}
+{% tab 'Scala 2 и 3' for=scala-features-4 %}
+```scala
+nums.map(i => i * 2) // длинная форма
+nums.map(_ * 2) // краткая форма
+
+nums.filter(i => i > 1)
+nums.filter(_ > 1)
+```
+{% endtab %}
+{% endtabs %}
+
+Трэйты, классы и методы определяются с помощью простого и легкого синтаксиса:
+
+{% tabs scala-features-5 class=tabs-scala-version %}
+{% tab 'Scala 2' for=scala-features-5 %}
+```scala mdoc
+trait Animal {
+ def speak(): Unit
+}
+
+trait HasTail {
+ def wagTail(): Unit
+}
+
+class Dog extends Animal with HasTail {
+ def speak(): Unit = println("Woof")
+ def wagTail(): Unit = println("⎞⎜⎛ ⎞⎜⎛")
+}
+```
+{% endtab %}
+{% tab 'Scala 3' for=scala-features-5 %}
+```scala
+trait Animal:
+ def speak(): Unit
+
+trait HasTail:
+ def wagTail(): Unit
+
+class Dog extends Animal, HasTail:
+ def speak(): Unit = println("Woof")
+ def wagTail(): Unit = println("⎞⎜⎛ ⎞⎜⎛")
+```
+{% endtab %}
+{% endtabs %}
+
+
+Исследования показали, что время, которое разработчик тратит на _чтение_ и _написание_ кода, составляет как минимум 10:1,
+поэтому важно писать краткий и читабельный код.
+
+
+### Ощущение динамики
+
+Scala — это язык со статической типизацией, но благодаря своим возможностям вывода типов он кажется динамичным.
+Все эти выражения выглядят как языки с динамической типизацией, такие как Python или Ruby, но это все Scala:
+
+{% tabs scala-features-6 class=tabs-scala-version %}
+{% tab 'Scala 2' for=scala-features-6 %}
+```scala
+val s = "Hello"
+val p = Person("Al", "Pacino")
+val sum = nums.reduceLeft(_ + _)
+val y = for (i <- nums) yield i * 2
+val z = nums
+ .filter(_ > 100)
+ .filter(_ < 10_000)
+ .map(_ * 2)
+```
+{% endtab %}
+{% tab 'Scala 3' for=scala-features-6 %}
+```scala
+val s = "Hello"
+val p = Person("Al", "Pacino")
+val sum = nums.reduceLeft(_ + _)
+val y = for i <- nums yield i * 2
+val z = nums
+ .filter(_ > 100)
+ .filter(_ < 10_000)
+ .map(_ * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+
+Как утверждает Heather Miller, Scala считается [сильным языком со статической типизацией](https://heather.miller.am/blog/types-in-scala.html),
+и вы получаете все преимущества статических типов:
+
+- Корректность: вы обнаруживаете большинство ошибок во время компиляции
+- Отличная поддержка IDE
+ - Надежное автодополнение кода
+ - Отлов ошибок во время компиляции означает отлов ошибок по мере написания
+ - Простой и надежный рефакторинг
+- Вы можете уверенно рефакторить свой код
+- Объявления типов методов сообщают читателям, что делает метод, и помогают служить документацией
+- Масштабируемость и удобство обслуживания: типы помогают обеспечить корректность в произвольно больших приложениях и командах разработчиков
+- Строгая типизация в сочетании с превосходным выводом типов позволяет использовать такие механизмы, как [контекстная абстракция]({{ site.scala3ref }}/contextual), которая позволяет вам опускать шаблонный код. Часто этот шаблонный код может быть выведен компилятором на основе определений типов и заданного контекста.
+
+
+### Выразительная система типов
+
+Система типов в Scala во время компиляции обеспечивает безопасное и согласованное использование абстракций.
+В частности, система типов поддерживает:
+
+- [Выводимые типы]({% link _overviews/scala3-book/types-inferred.md %})
+- [Generic классы]({% link _overviews/scala3-book/types-generics.md %})
+- [Аннотации вариантности]({% link _overviews/scala3-book/types-variance.md %})
+- [Верхняя](/tour/upper-type-bounds.html) и [нижняя](/tour/lower-type-bounds.html) границы типов
+- [Полиморфные методы](/tour/polymorphic-methods.html)
+- [Типы пересечения]({% link _overviews/scala3-book/types-intersection.md %})
+- [Типы объединения]({% link _overviews/scala3-book/types-union.md %})
+- [Лямбда-типы]({{ site.scala3ref }}/new-types/type-lambdas.html)
+- [Экземпляры `given` и предложения `using`]({% link _overviews/scala3-book/ca-context-parameters.md %})
+- [Методы расширения]({% link _overviews/scala3-book/ca-extension-methods.md %})
+- [Типовые классы]({% link _overviews/scala3-book/ca-type-classes.md %})
+- [Многостороннее равенство]({% link _overviews/scala3-book/ca-multiversal-equality.md %})
+- [Псевдонимы непрозрачного типа]({% link _overviews/scala3-book/types-opaque-types.md %})
+- [Открытые классы]({{ site.scala3ref }}/other-new-features/open-classes.html)
+- [Типы соответствия]({{ site.scala3ref }}/new-types/match-types.html)
+- [Зависимые типы функций]({{ site.scala3ref }}/new-types/dependent-function-types.html)
+- [Полиморфные функциональные типы]({{ site.scala3ref }}/new-types/polymorphic-function-types.html)
+- [Контекстные границы]({{ site.scala3ref }}/contextual/context-bounds.html)
+- [Контекстные функции]({{ site.scala3ref }}/contextual/context-functions.html)
+- [Внутренние классы](/tour/inner-classes.html) и [элементы абстрактного типа](/tour/abstract-type-members.html) как элементы объекта
+
+В сочетании эти функции обеспечивают мощную основу для безопасного повторного использования программных абстракций
+и для безопасного расширения программного обеспечения.
+
+
+### Язык функционального программирования
+
+Scala — это язык функционального программирования (ФП), что означает:
+
+- Функции — это значения, и их можно передавать, как и любое другое значение
+- Напрямую поддерживаются функции высшего порядка
+- Встроенные лямбда
+- Все в Scala — это выражение, возвращающее значение
+- Синтаксически легко использовать неизменяемые переменные, и их использование приветствуется
+- В стандартной библиотеке языка содержится множество неизменяемых классов коллекций
+- Эти классы коллекций поставляются с десятками функциональных методов: они не изменяют коллекцию, вместо этого возвращая обновленную копию данных
+
+
+### Объектно-ориентированный язык
+
+Scala — это язык объектно-ориентированного программирования (ООП).
+Каждое значение — это экземпляр класса, а каждый “оператор” — это метод.
+
+В Scala все типы наследуются от класса верхнего уровня `Any`, чьими непосредственными дочерними элементами являются `AnyVal` (_типы значений_, такие как `Int` и `Boolean`) и `AnyRef` (_ссылочные типы_, как в Java).
+Это означает, что различие в Java между примитивными и упакованными типами (например, `int` против `Integer`) отсутствует в Scala.
+Упаковка и распаковка полностью прозрачны для пользователя.
+
+
+### Поддерживает слияние ФП/ООП
+
+
+Суть Scala заключается в слиянии функционального программирования и объектно-ориентированного программирования в типизированной среде:
+
+- Функции для логики
+- Объекты для модульности
+
+[Как заявил Мартин Одерски](https://jaxenter.com/current-state-scala-odersky-interview-129495.html), “Scala был разработан, чтобы показать, что слияние функционального и объектно-ориентированного программирования возможно и практично”.
+
+
+### Вывод терминов стал более понятным
+
+После Haskell Scala был вторым популярным языком, в котором была некоторая форма неявных (_implicits_) выражений.
+В Scala 3 эти концепции были полностью переосмыслены и реализованы более четко.
+
+Основная идея заключается в _выводе терминов_: на основе заданного, компилятор синтезирует “канонический” термин, который имеет этот тип.
+В Scala параметр контекста напрямую ведет к выводимому термину аргумента, который также может быть записан явно.
+
+Примеры использования этой концепции включают реализацию [типовых классов]({% link _overviews/scala3-book/ca-type-classes.md %}),
+установление контекста, внедрение зависимостей, выражение возможностей, вычисление новых типов и доказательство отношений между ними.
+
+Scala 3 делает этот процесс более понятным, чем когда-либо прежде.
+О контекстных абстракциях можно прочесть в [Справочной документации]({{ site.scala3ref }}/contextual).
+
+
+### Клиент & сервер
+
+Код Scala работает на виртуальной машине Java (JVM), поэтому вы получаете все ее преимущества:
+
+- Безопасность
+- Производительность
+- Управление памятью
+- Портативность и независимость от платформы
+- Возможность использовать множество существующих Java и JVM библиотек
+
+Помимо работы на JVM, Scala также работает в браузере с помощью Scala.js (и сторонних инструментов с открытым исходным кодом для интеграции популярных библиотек JavaScript), а собственные исполняемые файлы могут быть созданы с помощью Scala Native и GraalVM.
+
+
+### Беспрепятственное взаимодействие с Java
+
+Вы можете использовать Java классы и библиотеки в своих приложениях Scala, а также код Scala в приложениях Java.
+Что касается второго пункта, большие библиотеки, такие как [Akka](https://akka.io) и [Play Framework](https://www.playframework.com) написаны на Scala и могут использоваться в приложениях Java.
+
+Что касается первого пункта, классы и библиотеки Java используются в приложениях Scala каждый день.
+Например, в Scala вы можете читать файлы с помощью `BufferedReader` и `FileReader` из Java:
+
+{% tabs scala-features-7 %}
+{% tab 'Scala 2 и 3' for=scala-features-7 %}
+```scala
+import java.io.*
+val br = BufferedReader(FileReader(filename))
+// чтение файла в `br` ...
+```
+{% endtab %}
+{% endtabs %}
+
+Использование Java-кода в Scala, как правило, не вызывает затруднений.
+
+В Scala также можно использовать коллекции Java, и если вы хотите использовать с ними богатый набор методов классов коллекций Scala,
+то можете преобразовать их с помощью всего нескольких строк кода:
+
+{% tabs scala-features-8 %}
+{% tab 'Scala 2 и 3' for=scala-features-8 %}
+```scala
+import scala.jdk.CollectionConverters.*
+val scalaList: Seq[Integer] = JavaClass.getJavaList().asScala.toSeq
+```
+{% endtab %}
+{% endtabs %}
+
+
+### Богатство библиотек
+
+Как будет видно в третьем разделе этой страницы, библиотеки и фреймворки Scala, подобные нижеследующим,
+были написаны для поддержки загруженных веб-сайтов и работы с огромными наборами данных:
+
+1. [Play Framework](https://www.playframework.com) — это легкая, без сохранения состояния, удобная для web, удобная для разработчиков архитектура для создания масштабируемых приложений
+2. [Apache Spark](https://spark.apache.org) — это унифицированный аналитический механизм для обработки больших данных со встроенными модулями для потоковой передачи, SQL, машинного обучения и обработки графиков
+
+В [списке Awesome Scala](https://github.com/lauris/awesome-scala) представлены десятки дополнительных инструментов
+с открытым исходным кодом, созданных разработчиками для создания приложений Scala.
+
+В дополнение к программированию на стороне сервера, [Scala.js](https://www.scala-js.org) представляет собой
+строго типизированную замену для написания JavaScript со сторонними библиотеками с открытым исходным кодом,
+которые включают инструменты для интеграции с библиотекой Facebook React, jQuery и т.д.
+
+
+## Функции низкоуровневого языка
+
+Хотя в предыдущем разделе были рассмотрены высокоуровневые функции Scala, интересно отметить,
+что на высоком уровне вы можете делать одни и те же утверждения как о Scala 2, так и о Scala 3.
+Десять лет назад Scala начиналась с прочного фундамента желаемых функций, и вы увидите в этом разделе,
+что в Scala 3 эти преимущества были улучшены.
+
+С точки зрения деталей “на уровне моря” — то есть функций языка, которые программисты используют каждый день —
+Scala 3 имеет значительные преимущества по сравнению со Scala 2:
+
+- Возможность более лаконично создавать алгебраические типы данных (ADT) с перечислениями
+- Еще более лаконичный и читаемый синтаксис:
+ - Синтаксис “тихой” структуры управления легче читать
+ - Опциональные фигурные скобки
+ - Меньшее количество символов в коде создает меньше визуального шума, что упрощает его чтение
+ - Ключевое слово `new` обычно больше не требуется при создании экземпляров класса
+ - Формальность объектов пакета была заменена более простыми определениями “верхнего уровня”
+- Более понятная грамматика:
+ - Несколько различных вариантов использования ключевого слова `implicit` были удалены; это использование заменено более очевидными ключевыми словами, такими как `given`, `using`, и `extension`, фокусирующихся на намерении, а не механизме (подробности см. в разделе [Givens][givens])
+ - [Методы расширения][extension] заменяют неявные классы более понятным и простым механизмом
+ - Добавление модификатора `open` для классов заставляет разработчика намеренно объявить, что класс открыт для модификации, тем самым ограничивая специальные расширения кодовой базы
+ - [Многостороннее равенство][multiversal] исключает бессмысленные сравнения с `==` и `!=` (т.е. попытки сравнить `Person` с `Planet`)
+ - Гораздо проще реализуются макросы
+ - Объединение и пересечение предлагают гибкий способ моделирования типов
+ - Параметры трейтов заменяют и упрощают ранние инициализаторы
+ - [Псевдонимы непрозрачных типов][opaque_types] заменяют большинство случаев использования классов значений, гарантируя при этом отсутствие упаковки
+ - Export предложения обеспечивают простой и общий способ выражения агрегации, который может заменить предыдущий шаблон фасада объектов пакета, наследуемых от классов
+ - Синтаксис procedure был удален, а синтаксис varargs - изменен, чтобы сделать язык более согласованным
+ - `@infix` аннотация делает очевидным желаемое применение метода
+ - Аннотация метода [`@targetName`]({{ site.scala3ref }}/other-new-features/targetName.html) определяет альтернативное имя метода, улучшая совместимость с Java и позволяя указывать псевдонимы для символических операторов
+
+Демонстрация всех этих функций заняла бы слишком много места, но перейдите по ссылкам в пунктах выше, чтобы увидеть эти функции в действии.
+Все эти функции подробно обсуждаются на страницах *New*, *Changed* и *Dropped* функций в [обзорной документации][reference].
+
+
+## Экосистема Scala
+
+
+У Scala динамичная экосистема с библиотеками и фреймворками под любые требования.
+[Список “Awesome Scala”](https://github.com/lauris/awesome-scala) содержит список сотен проектов с открытым исходным кодом,
+доступных разработчикам Scala, а [Scaladex](https://index.scala-lang.org) предоставляет доступный для поиска индекс библиотек Scala.
+Некоторые из наиболее известных библиотек перечислены ниже.
+
+
+
+### Web разработка
+
+- [Play Framework](https://www.playframework.com) следует модели Ruby on Rails, чтобы стать легкой, не сохраняющей состояния,
+ удобной для разработчиков и web архитектурой для высокомасштабируемых приложений
+- [Scalatra](https://scalatra.org) — небольшой высокопроизводительный асинхронный web framework, вдохновленный Sinatra
+- [Finatra](https://twitter.github.io/finatra) — это сервисы Scala, построенные на TwitterServer и Finagle
+- [Scala.js](https://www.scala-js.org) — это строго типизированная замена JavaScript, обеспечивающая более безопасный способ создания надежных интерфейсных web-приложений
+- [ScalaJs-React](https://github.com/japgolly/scalajs-react) поднимает библиотеку Facebook React на Scala.js и пытается сделать ее максимально безопасной для типов и удобной для Scala
+
+
+HTTP(S) библиотеки:
+
+- [Akka-http](https://akka.io)
+- [Finch](https://github.com/finagle/finch)
+- [Http4s](https://github.com/http4s/http4s)
+- [Sttp](https://github.com/softwaremill/sttp)
+
+JSON библиотеки:
+
+- [Argonaut](https://github.com/argonaut-io/argonaut)
+- [Circe](https://github.com/circe/circe)
+- [Json4s](https://github.com/json4s/json4s)
+- [Play-JSON](https://github.com/playframework/play-json)
+
+Сериализация:
+
+- [ScalaPB](https://github.com/scalapb/ScalaPB)
+
+### Наука и анализ данных:
+
+- [Algebird](https://github.com/twitter/algebird)
+- [Spire](https://github.com/typelevel/spire)
+- [Squants](https://github.com/typelevel/squants)
+
+
+### Большие данные
+
+- [Apache Spark](https://github.com/apache/spark)
+- [Apache Flink](https://github.com/apache/flink)
+
+
+### ИИ, машинное обучение
+
+- [BigDL](https://github.com/intel-analytics/BigDL) (Распределенная среда глубокого обучения для Apache Spark)
+- [TensorFlow Scala](https://github.com/eaplatanios/tensorflow_scala)
+
+
+### Функциональное программирование & Функциональное реактивное программирование
+
+ФП:
+
+- [Cats](https://github.com/typelevel/cats)
+- [Zio](https://github.com/zio/zio)
+
+Функциональное реактивное программирование (ФРП):
+
+- [fs2](https://github.com/typelevel/fs2)
+- [monix](https://github.com/monix/monix)
+
+
+### Инструменты сборки
+
+- [sbt](https://www.scala-sbt.org)
+- [Gradle](https://gradle.org)
+- [Mill](https://github.com/lihaoyi/mill)
+
+
+
+## Подведем итоги
+
+Как показано на этой странице, Scala обладает множеством замечательных функций высокоуровневого языка программирования,
+низкоуровневого языка программирования и богатой экосистемой разработчиков.
+
+
+[reference]: {{ site.scala3ref }}/overview.html
+[multiversal]: {% link _overviews/scala3-book/ca-multiversal-equality.md %}
+[extension]: {% link _overviews/scala3-book/ca-extension-methods.md %}
+[givens]: {% link _overviews/scala3-book/ca-context-parameters.md %}
+[opaque_types]: {% link _overviews/scala3-book/types-opaque-types.md %}
+
diff --git a/_ru/scala3/book/scala-tools.md b/_ru/scala3/book/scala-tools.md
new file mode 100644
index 0000000000..e58bfb2e64
--- /dev/null
+++ b/_ru/scala3/book/scala-tools.md
@@ -0,0 +1,18 @@
+---
+layout: multipage-overview
+title: Scala утилиты
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: В этой главе рассматриваются два широко используемых инструмента Scala sbt и ScalaTest.
+language: ru
+num: 69
+previous-page: concurrency
+next-page: tools-sbt
+---
+
+В этой главе представлены два способа написания и запуска программ в Scala:
+
+- создавая Scala проекты, возможно, содержащие несколько файлов, и определяя точку входа в программу,
+- путем взаимодействия с worksheet, который представляет собой программу, определенную в одном файле и выполняемую построчно.
diff --git a/_ru/scala3/book/string-interpolation.md b/_ru/scala3/book/string-interpolation.md
new file mode 100644
index 0000000000..9e37b526fa
--- /dev/null
+++ b/_ru/scala3/book/string-interpolation.md
@@ -0,0 +1,413 @@
+---
+layout: multipage-overview
+title: Интерполяция строк
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: На этой странице представлена дополнительная информация о создании строк и использовании интерполяции строк.
+language: ru
+num: 18
+previous-page: first-look-at-types
+next-page: control-structures
+---
+
+## Введение
+
+Интерполяция строк позволяет использовать внутри строк переменные.
+Например:
+
+{% tabs example-1 %}
+{% tab 'Scala 2 и 3' for=example-1 %}
+
+```scala
+val name = "James"
+val age = 30
+println(s"$name is $age years old") // "James is 30 years old"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Использование интерполяции строк заключается в том, что перед строковыми кавычками ставится символ `s`,
+а перед любыми именами переменных ставится символ `$`.
+
+### Другие интерполяторы
+
+То `s`, что вы помещаете перед строкой, является лишь одним из возможных интерполяторов, предоставляемых Scala.
+
+Scala по умолчанию предоставляет три метода интерполяции строк: `s`, `f` и `raw`.
+Кроме того, строковый интерполятор — это всего лишь специальный метод, и вы можете определить свой собственный.
+Например, некоторые библиотеки баз данных определяют интерполятор `sql`, возвращающий запрос к базе данных.
+
+## Интерполятор `s` (`s`-строки)
+
+Добавление `s` перед любым строковым литералом позволяет использовать переменные непосредственно в строке.
+Вы уже здесь видели пример:
+
+{% tabs example-2 %}
+{% tab 'Scala 2 и 3' for=example-2 %}
+
+```scala
+val name = "James"
+val age = 30
+println(s"$name is $age years old") // "James is 30 years old"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Здесь переменные `$name` и `$age` заменяются в строке результатами вызова `name.toString` и `age.toString` соответственно.
+`s`-строка будет иметь доступ ко всем переменным, в настоящее время находящимся в области видимости.
+
+Хотя это может показаться очевидным, важно здесь отметить,
+что интерполяция строк _не_ будет выполняться в обычных строковых литералах:
+
+{% tabs example-3 %}
+{% tab 'Scala 2 и 3' for=example-3 %}
+
+```scala
+val name = "James"
+val age = 30
+println("$name is $age years old") // "$name is $age years old"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Строковые интерполяторы также могут принимать произвольные выражения.
+Например:
+
+{% tabs example-4 %}
+{% tab 'Scala 2 и 3' for=example-4 %}
+
+```scala
+println(s"2 + 2 = ${2 + 2}") // "2 + 2 = 4"
+val x = -1
+println(s"x.abs = ${x.abs}") // "x.abs = 1"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Любое произвольное выражение может быть встроено в `${}`.
+
+Некоторые специальные символы необходимо экранировать при встраивании в строку.
+Чтобы указать символ "знак доллара", вы можете удвоить его `$$`, как показано ниже:
+
+{% tabs example-5 %}
+{% tab 'Scala 2 и 3' for=example-5 %}
+
+```scala
+println(s"New offers starting at $$14.99") // "New offers starting at $14.99"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Двойные кавычки также необходимо экранировать.
+Это можно сделать с помощью тройных кавычек, как показано ниже:
+
+{% tabs example-6 %}
+{% tab 'Scala 2 и 3' for=example-6 %}
+
+```scala
+println(s"""{"name":"James"}""") // `{"name":"James"}`
+```
+
+{% endtab %}
+{% endtabs %}
+
+Наконец, все многострочные строковые литералы также могут быть интерполированы.
+
+{% tabs example-7 %}
+{% tab 'Scala 2 и 3' for=example-7 %}
+
+```scala
+println(s"""name: "$name",
+ |age: $age""".stripMargin)
+```
+
+Строка будет напечатана следующим образом:
+
+```
+name: "James"
+age: 30
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Интерполятор `f` (`f`-строки)
+
+Добавление `f` к любому строковому литералу позволяет создавать простые отформатированные строки,
+аналогичные `printf` в других языках.
+При использовании интерполятора `f` за всеми ссылками на переменные должна следовать строка формата в стиле `printf`, например `%d`.
+Давайте посмотрим на пример:
+
+{% tabs example-8 %}
+{% tab 'Scala 2 и 3' for=example-8 %}
+
+```scala
+val height = 1.9d
+val name = "James"
+println(f"$name%s is $height%2.2f meters tall") // "James is 1.90 meters tall"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Интерполятор `f` типобезопасен.
+Если вы попытаетесь передать в строку формата, который работает только для целых чисел,
+значение `double`, компилятор выдаст ошибку. Например:
+
+{% tabs f-interpolator-error class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=f-interpolator-error %}
+
+```scala
+val height: Double = 1.9d
+
+scala> f"$height%4d"
+:9: error: type mismatch;
+ found : Double
+ required: Int
+ f"$height%4d"
+ ^
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=f-interpolator-error %}
+
+```scala
+val height: Double = 1.9d
+
+scala> f"$height%4d"
+-- Error: ----------------------------------------------------------------------
+1 |f"$height%4d"
+ | ^^^^^^
+ | Found: (height : Double), Required: Int, Long, Byte, Short, BigInt
+1 error found
+
+```
+
+{% endtab %}
+{% endtabs %}
+
+Интерполятор `f` использует утилиты форматирования строк, доступные в Java.
+Форматы, разрешенные после символа `%`, описаны в [Formatter javadoc][java-format-docs].
+Если после определения переменной нет символа `%`, предполагается форматирование `%s` (`String`).
+
+Наконец, как и в Java, используйте `%%` для получения буквенного символа `%` в итоговой строке:
+
+{% tabs literal-percent %}
+{% tab 'Scala 2 и 3' for=literal-percent %}
+
+```scala
+println(f"3/19 is less than 20%%") // "3/19 is less than 20%"
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Интерполятор `raw`
+
+Интерполятор `raw` похож на интерполятор `s`,
+за исключением того, что он не выполняет экранирование литералов внутри строки.
+Вот пример обработанной строки:
+
+{% tabs example-9 %}
+{% tab 'Scala 2 и 3' for=example-9 %}
+
+```scala
+scala> s"a\nb"
+res0: String =
+a
+b
+```
+
+{% endtab %}
+{% endtabs %}
+
+Здесь строковый интерполятор `s` заменил символы `\n` символом переноса строки.
+Интерполятор `raw` этого не делает.
+
+{% tabs example-10 %}
+{% tab 'Scala 2 и 3' for=example-10 %}
+
+```scala
+scala> raw"a\nb"
+res1: String = a\nb
+```
+
+{% endtab %}
+{% endtabs %}
+
+Интерполятор `raw` полезен тогда, когда вы хотите избежать преобразования таких выражений, как `\n`, в символ переноса строки.
+
+В дополнение к трем строковым интерполяторам пользователи могут определить свои собственные.
+
+## Расширенное использование
+
+Литерал `s"Hi $name"` анализируется Scala как _обрабатываемый_ строковый литерал.
+Это означает, что компилятор выполняет некоторую дополнительную работу с этим литералом.
+Особенности обработанных строк и интерполяции строк описаны в [SIP-11][sip-11].
+Вот краткий пример, который поможет проиллюстрировать, как они работают.
+
+### Пользовательские интерполяторы
+
+В Scala все обрабатываемые строковые литералы представляют собой простые преобразования кода.
+Каждый раз, когда компилятор встречает обрабатываемый строковый литерал вида:
+
+{% tabs example-11 %}
+{% tab 'Scala 2 и 3' for=example-11 %}
+
+```scala
+id"string content"
+```
+
+{% endtab %}
+{% endtabs %}
+
+он преобразует его в вызов метода (`id`) для экземпляра [StringContext](https://www.scala-lang.org/api/current/scala/StringContext.html).
+Этот метод также может быть доступен в неявной области видимости.
+Чтобы определить собственную интерполяцию строк, нужно создать неявный класс (Scala 2)
+или метод расширения (Scala 3), который добавляет новый метод для `StringContext`.
+
+В качестве простого примера предположим, что у нас есть простой класс `Point`
+и мы хотим создать собственный интерполятор, который преобразует `p"a,b"` в объект `Point`.
+
+{% tabs custom-interpolator-1 %}
+{% tab 'Scala 2 и 3' for=custom-interpolator-1 %}
+
+```scala
+case class Point(x: Double, y: Double)
+
+val pt = p"1,-2" // Point(1.0,-2.0)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Мы бы создали собственный интерполятор `p`,
+сначала внедрив расширение `StringContext`, например, так:
+
+{% tabs custom-interpolator-2 class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=custom-interpolator-2 %}
+
+```scala
+implicit class PointHelper(val sc: StringContext) extends AnyVal {
+ def p(args: Any*): Point = ???
+}
+```
+
+**Примечание**. Важно расширить `AnyVal` в Scala 2.x,
+чтобы предотвратить создание экземпляра класса во время выполнения при каждой интерполяции.
+Дополнительную информацию см. в документации по [value class]({% link _overviews/core/value-classes.md %}).
+
+{% endtab %}
+
+{% tab 'Scala 3' for=custom-interpolator-2 %}
+
+```scala
+extension (sc: StringContext)
+ def p(args: Any*): Point = ???
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+Как только это расширение окажется в области видимости и компилятор Scala обнаружит `p"some string"`,
+то превратит `some string` в токены String, а каждую встроенную переменную в аргументы выражения.
+
+Например, `p"1, $someVar"` превратится в:
+
+{% tabs extension-desugaring class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=extension-desugaring %}
+
+```scala
+new StringContext("1, ", "").p(someVar)
+```
+
+Затем неявный класс используется для перезаписи следующим образом:
+
+```scala
+new PointHelper(new StringContext("1, ", "")).p(someVar)
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=extension-desugaring %}
+
+```scala
+StringContext("1, ", "").p(someVar)
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+В результате каждый из фрагментов обработанной строки отображается в элементе `StringContext.parts`,
+а любые значения выражений в строке передаются в параметр метода `args`.
+
+### Пример реализации
+
+Простая реализация метода интерполяции для нашего `Point` может выглядеть примерно так, как показано ниже,
+хотя более детализированный метод может иметь более точный контроль
+над обработкой строки `parts` и выражения `args` вместо повторного использования интерполятора `s`.
+
+{% tabs naive-implementation class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=naive-implementation %}
+
+```scala
+implicit class PointHelper(val sc: StringContext) extends AnyVal {
+ def p(args: Double*): Point = {
+ // переиспользование интерполятора `s` и затем разбиение по ','
+ val pts = sc.s(args: _*).split(",", 2).map { _.toDoubleOption.getOrElse(0.0) }
+ Point(pts(0), pts(1))
+ }
+}
+
+val x=12.0
+
+p"1, -2" // Point(1.0, -2.0)
+p"${x/5}, $x" // Point(2.4, 12.0)
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=naive-implementation %}
+
+```scala
+extension (sc: StringContext)
+ def p(args: Double*): Point = {
+ // переиспользование интерполятора `s` и затем разбиение по ','
+ val pts = sc.s(args: _*).split(",", 2).map { _.toDoubleOption.getOrElse(0.0) }
+ Point(pts(0), pts(1))
+ }
+
+val x=12.0
+
+p"1, -2" // Point(1.0, -2.0)
+p"${x/5}, $x" // Point(2.4, 12.0)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Хотя строковые интерполяторы изначально использовались для создания нескольких строковых форм,
+использование пользовательских интерполяторов, как указано выше,
+может обеспечить более мощное синтаксическое сокращение,
+и сообщество уже использует этот синтаксис для таких вещей,
+как расширение цвета терминала ANSI, выполнение SQL-запросов,
+магические представления `$"identifier"` и многие другие.
+
+[java-format-docs]: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Formatter.html#detail
+
+[value-class]: {% link _overviews/core/value-classes.md %}
+[sip-11]: {% link _sips/sips/string-interpolation.md %}
diff --git a/_ru/scala3/book/taste-collections.md b/_ru/scala3/book/taste-collections.md
new file mode 100644
index 0000000000..672e5158af
--- /dev/null
+++ b/_ru/scala3/book/taste-collections.md
@@ -0,0 +1,161 @@
+---
+layout: multipage-overview
+title: Коллекции
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице представлен обзор основных коллекций в Scala 3.
+language: ru
+num: 13
+previous-page: taste-objects
+next-page: taste-contextual-abstractions
+---
+
+
+Библиотека Scala поставляется с богатым набором классов коллекций, и эти классы содержат множество методов.
+Классы коллекций доступны как в неизменяемой, так и в изменяемой форме.
+
+## Создание списков
+
+Чтобы дать вам представление о том, как они работают, вот несколько примеров, в которых используется класс `List`,
+являющийся неизменяемым классом связанного списка.
+В этих примерах показаны различные способы создания заполненного `List`:
+
+{% tabs collection_1 %}
+{% tab 'Scala 2 и 3' for=collection_1 %}
+
+```scala
+val a = List(1, 2, 3) // a: List[Int] = List(1, 2, 3)
+
+// методы Range
+val b = (1 to 5).toList // b: List[Int] = List(1, 2, 3, 4, 5)
+val c = (1 to 10 by 2).toList // c: List[Int] = List(1, 3, 5, 7, 9)
+val e = (1 until 5).toList // e: List[Int] = List(1, 2, 3, 4)
+val f = List.range(1, 5) // f: List[Int] = List(1, 2, 3, 4)
+val g = List.range(1, 10, 3) // g: List[Int] = List(1, 4, 7)
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Методы `List`
+
+В следующих примерах показаны некоторые методы, которые можно вызывать для заполненного списка.
+Обратите внимание, что все эти методы являются функциональными,
+а это означает, что они не изменяют коллекцию, на которой вызываются,
+а вместо этого возвращают новую коллекцию с обновленными элементами.
+Результат, возвращаемый каждым выражением, отображается в комментарии к каждой строке:
+
+{% tabs collection_2 %}
+{% tab 'Scala 2 и 3' for=collection_2 %}
+
+```scala
+// a sample list
+val a = List(10, 20, 30, 40, 10) // List(10, 20, 30, 40, 10)
+
+a.drop(2) // List(30, 40, 10)
+a.dropWhile(_ < 25) // List(30, 40, 10)
+a.filter(_ < 25) // List(10, 20, 10)
+a.slice(2,4) // List(30, 40)
+a.tail // List(20, 30, 40, 10)
+a.take(3) // List(10, 20, 30)
+a.takeWhile(_ < 30) // List(10, 20)
+
+// flatten
+val a = List(List(1,2), List(3,4))
+a.flatten // List(1, 2, 3, 4)
+
+// map, flatMap
+val nums = List("one", "two")
+nums.map(_.toUpperCase) // List("ONE", "TWO")
+nums.flatMap(_.toUpperCase) // List('O', 'N', 'E', 'T', 'W', 'O')
+```
+
+{% endtab %}
+{% endtabs %}
+
+Эти примеры показывают, как методы “foldLeft” и “reduceLeft” используются
+для суммирования значений в последовательности целых чисел:
+
+{% tabs collection_3 %}
+{% tab 'Scala 2 и 3' for=collection_3 %}
+
+```scala
+val firstTen = (1 to 10).toList // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+
+firstTen.reduceLeft(_ + _) // 55
+firstTen.foldLeft(100)(_ + _) // 155 (100 является “начальным” значением)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Для классов коллекций Scala доступно гораздо больше методов,
+и они продемонстрированы в главе ["Коллекции"][collections] и в [API документации][api].
+
+## Кортежи
+
+В Scala _кортеж_ (_tuple_) — это тип, позволяющий легко поместить набор различных типов в один и тот же контейнер.
+Например, используя данный case класс `Person`:
+
+{% tabs collection_4 %}
+{% tab 'Scala 2 и 3' for=collection_4 %}
+
+```scala
+case class Person(name: String)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Вот как вы создаете кортеж, который содержит `Int`, `String` и пользовательское значение `Person`:
+
+{% tabs collection_5 %}
+{% tab 'Scala 2 и 3' for=collection_5 %}
+
+```scala
+val t = (11, "eleven", Person("Eleven"))
+```
+
+{% endtab %}
+{% endtabs %}
+
+Когда у вас есть кортеж, вы можете получить доступ к его значениям, привязав их к переменным,
+или получить к ним доступ по номеру:
+
+{% tabs collection_6 %}
+{% tab 'Scala 2 и 3' for=collection_6 %}
+
+```scala
+t(0) // 11
+t(1) // "eleven"
+t(2) // Person("Eleven")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Вы также можете использовать этот метод _извлечения_, чтобы присвоить поля кортежа именам переменных:
+
+{% tabs collection_7 %}
+{% tab 'Scala 2 и 3' for=collection_7 %}
+
+```scala
+val (num, str, person) = t
+
+// в результате:
+// val num: Int = 11
+// val str: String = eleven
+// val person: Person = Person(Eleven)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Кортежи хороши в тех случаях, когда вы хотите поместить коллекцию разнородных типов в небольшую структуру, похожую на коллекцию.
+Дополнительные сведения о кортежах см. ["в справочной документации"][reference].
+
+[collections]: {% link _overviews/scala3-book/collections-intro.md %}
+[api]: https://scala-lang.org/api/3.x/
+[reference]: {{ site.scala3ref }}/overview.html
diff --git a/_ru/scala3/book/taste-contextual-abstractions.md b/_ru/scala3/book/taste-contextual-abstractions.md
new file mode 100644
index 0000000000..fea81bbb84
--- /dev/null
+++ b/_ru/scala3/book/taste-contextual-abstractions.md
@@ -0,0 +1,79 @@
+---
+layout: multipage-overview
+title: Контекстные абстракции
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлено введение в контекстные абстракции в Scala 3.
+language: ru
+num: 14
+previous-page: taste-collections
+next-page: taste-toplevel-definitions
+---
+
+
+При определенных обстоятельствах вы можете опустить некоторые параметры вызовов методов, которые считаются повторяющимися.
+
+Эти параметры называются _параметрами контекста_ (_Context Parameters_),
+поскольку они выводятся компилятором из контекста, окружающего вызов метода.
+
+Например, рассмотрим программу, которая сортирует список адресов по двум критериям:
+название города, а затем название улицы.
+
+{% tabs contextual_1 %}
+{% tab 'Scala 2 и 3' for=contextual_1 %}
+
+```scala
+val addresses: List[Address] = ...
+
+addresses.sortBy(address => (address.city, address.street))
+```
+
+{% endtab %}
+{% endtabs %}
+
+Метод `sortBy` принимает функцию, которая возвращает для каждого адреса значение, чтобы сравнить его с другими адресами.
+В этом случае мы передаем функцию, которая возвращает пару, содержащую название города и название улицы.
+
+Обратите внимание, что мы только указываем, _что_ сравнивать, но не _как_ выполнять сравнение.
+Откуда алгоритм сортировки знает, как сравнивать пары `String`?
+
+На самом деле метод `sortBy` принимает второй параметр — параметр контекста, который выводится компилятором.
+Его нет в приведенном выше примере, поскольку он предоставляется компилятором.
+
+Этот второй параметр реализует _способ_ сравнения.
+Его удобно опустить, потому что мы знаем, что `String`-и обычно сравниваются в лексикографическом порядке.
+
+Однако также возможно передать параметр явно:
+
+{% tabs contextual_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=contextual_2 %}
+
+```scala
+addresses.sortBy(address => (address.city, address.street))(Ordering.Tuple2(Ordering.String, Ordering.String))
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=contextual_2 %}
+
+```scala
+addresses.sortBy(address => (address.city, address.street))(using Ordering.Tuple2(Ordering.String, Ordering.String))
+```
+
+в Scala 3 `using` в списке аргументов сигнализирует `sortBy` о явной передаче параметра контекста, избегая двусмысленности.
+
+{% endtab %}
+{% endtabs %}
+
+В этом случае экземпляр `Ordering.Tuple2(Ordering.String, Ordering.String)` — это именно тот экземпляр,
+который в противном случае выводится компилятором.
+Другими словами, оба примера создают одну и ту же программу.
+
+_Контекстные абстракции_ используются, чтобы избежать повторения кода.
+Они помогают разработчикам писать фрагменты кода, которые являются расширяемыми и в то же время лаконичными.
+
+Дополнительные сведения см. в [главе "Контекстные абстракции"][contextual] этой книги, а также в [справочной документации][reference].
+
+[contextual]: {% link _overviews/scala3-book/ca-contextual-abstractions-intro.md %}
+[reference]: {{ site.scala3ref }}/overview.html
diff --git a/_ru/scala3/book/taste-control-structures.md b/_ru/scala3/book/taste-control-structures.md
new file mode 100644
index 0000000000..7da0940a4f
--- /dev/null
+++ b/_ru/scala3/book/taste-control-structures.md
@@ -0,0 +1,555 @@
+---
+layout: multipage-overview
+title: Структуры управления
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: Этот раздел демонстрирует структуры управления в Scala 3.
+language: ru
+num: 8
+previous-page: taste-vars-data-types
+next-page: taste-modeling
+---
+
+
+В Scala есть все структуры управления, которые вы найдете в других языках программирования,
+а также мощные `for` и `match` выражения:
+
+- `if`/`else`
+- `for` циклы и выражения
+- `match` выражения
+- `while` циклы
+- `try`/`catch`
+
+Эти структуры демонстрируются в следующих примерах.
+
+## `if`/`else`
+
+В Scala структура управления `if`/`else` похожа на аналогичные структуры в других языках.
+
+{% tabs if-else class=tabs-scala-version %}
+{% tab 'Scala 2' for=if-else %}
+
+```scala
+if (x < 0) {
+ println("negative")
+} else if (x == 0) {
+ println("zero")
+} else {
+ println("positive")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=if-else %}
+
+```scala
+if x < 0 then
+ println("negative")
+else if x == 0 then
+ println("zero")
+else
+ println("positive")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Обратите внимание, что это действительно _выражение_, а не _утверждение_.
+Это означает, что оно возвращает значение, поэтому вы можете присвоить результат переменной:
+
+{% tabs if-else-expression class=tabs-scala-version %}
+{% tab 'Scala 2' for=if-else-expression %}
+
+```scala
+val x = if (a < b) { a } else { b }
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=if-else-expression %}
+
+```scala
+val x = if a < b then a else b
+```
+
+{% endtab %}
+{% endtabs %}
+
+Как вы увидите в этой книге, _все_ управляющие структуры Scala могут использоваться как выражения.
+
+> Выражение возвращает результат, а утверждение — нет.
+> Утверждения обычно используются для их побочных эффектов, таких как использование `println` для печати на консоли.
+
+## `for` циклы и выражения
+
+Ключевое слово `for` используется для создания цикла `for`.
+В этом примере показано, как напечатать каждый элемент в `List`:
+
+{% tabs for-loop class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-loop %}
+
+```scala
+val ints = List(1, 2, 3, 4, 5)
+
+for (i <- ints) println(i)
+```
+
+> Код `i <- ints` называется _генератором_, а код, следующий за закрывающими скобками генератора, является _телом_ цикла.
+
+{% endtab %}
+
+{% tab 'Scala 3' for=for-loop %}
+
+```scala
+val ints = List(1, 2, 3, 4, 5)
+
+for i <- ints do println(i)
+```
+
+> Код `i <- ints` называется _генератором_, а код, следующий за ключевым словом `do`, является _телом_ цикла.
+
+{% endtab %}
+{% endtabs %}
+
+### Guards
+
+Вы также можете использовать одно или несколько `if` выражений внутри цикла `for`.
+Их называют _ограничители_ (_guards_).
+В этом примере выводятся все числа `ints`, большие `2`:
+
+{% tabs for-guards class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-guards %}
+
+```scala
+for (i <- ints if i > 2)
+ println(i)
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=for-guards %}
+
+```scala
+for
+ i <- ints
+ if i > 2
+do
+ println(i)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Вы можете использовать несколько генераторов и стражников.
+Этот цикл перебирает числа от `1` до `3`, и для каждого числа также перебирает символы от `a` до `c`.
+Однако у него также есть два стражника, поэтому оператор печати вызывается только тогда,
+когда `i` имеет значение `2` и `j` является символом `b`:
+
+{% tabs for-guards-multi class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-guards-multi %}
+
+```scala
+for {
+ i <- 1 to 3
+ j <- 'a' to 'c'
+ if i == 2
+ if j == 'b'
+} {
+ println(s"i = $i, j = $j") // печатает: "i = 2, j = b"
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=for-guards-multi %}
+
+```scala
+for
+ i <- 1 to 3
+ j <- 'a' to 'c'
+ if i == 2
+ if j == 'b'
+do
+ println(s"i = $i, j = $j") // печатает: "i = 2, j = b"
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Выражения `for`
+
+Ключевое слово `for` содержит в себе еще большую силу:
+когда вы используете ключевое слово `yield` вместо `do`, то создаете _выражения_ `for`,
+которые используются для вычислений и получения результатов.
+
+Несколько примеров демонстрируют это.
+Используя тот же список `ints`, что и в предыдущем примере, этот код создает новый список,
+в котором значение каждого элемента в новом списке в два раза превышает значение элементов в исходном:
+
+{% tabs for-expression_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-expression_1 %}
+
+````
+scala> val doubles = for (i <- ints) yield i * 2
+val doubles: List[Int] = List(2, 4, 6, 8, 10)
+````
+
+{% endtab %}
+
+{% tab 'Scala 3' for=for-expression_1 %}
+
+````
+scala> val doubles = for i <- ints yield i * 2
+val doubles: List[Int] = List(2, 4, 6, 8, 10)
+````
+
+{% endtab %}
+{% endtabs %}
+
+Синтаксис структуры управления Scala является гибким,
+и это `for` выражение может быть записано несколькими другими способами, в зависимости от ваших предпочтений:
+
+{% tabs for-expressioni_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-expressioni_2 %}
+
+```scala
+val doubles = for (i <- ints) yield i * 2
+val doubles = for (i <- ints) yield (i * 2)
+val doubles = for { i <- ints } yield (i * 2)
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=for-expressioni_2 %}
+
+```scala
+val doubles = for i <- ints yield i * 2 // стиль показан выше
+val doubles = for (i <- ints) yield i * 2
+val doubles = for (i <- ints) yield (i * 2)
+val doubles = for { i <- ints } yield (i * 2)
+```
+
+{% endtab %}
+{% endtabs %}
+
+В этом примере показано, как сделать первый символ в каждой строке списка заглавными:
+
+{% tabs for-expressioni_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-expressioni_3 %}
+
+```scala
+val names = List("chris", "ed", "maurice")
+val capNames = for (name <- names) yield name.capitalize
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=for-expressioni_3 %}
+
+```scala
+val names = List("chris", "ed", "maurice")
+val capNames = for name <- names yield name.capitalize
+```
+
+{% endtab %}
+{% endtabs %}
+
+Наконец, нижеследующее выражение `for` перебирает список строк
+и возвращает длину каждой строки, но только если эта длина больше `4`:
+
+{% tabs for-expressioni_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-expressioni_4 %}
+
+```scala
+val fruits = List("apple", "banana", "lime", "orange")
+
+val fruitLengths =
+ for (f <- fruits if f.length > 4) yield f.length
+
+// fruitLengths: List[Int] = List(5, 6, 6)
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=for-expressioni_4 %}
+
+```scala
+val fruits = List("apple", "banana", "lime", "orange")
+
+val fruitLengths = for
+ f <- fruits
+ if f.length > 4
+yield
+ // здесь можно использовать
+ // несколько строк кода
+ f.length
+
+// fruitLengths: List[Int] = List(5, 6, 6)
+```
+
+{% endtab %}
+{% endtabs %}
+
+`for` циклы и выражения более подробно рассматриваются в разделах этой книги ["Структуры управления"][control]
+и в [справочной документации]({{ site.scala3ref }}/other-new-features/control-syntax.html).
+
+## `match` выражения
+
+В Scala есть выражение `match`, которое в своем самом простом использовании похоже на `switch` оператор Java:
+
+{% tabs match class=tabs-scala-version %}
+{% tab 'Scala 2' for=match %}
+
+```scala
+val i = 1
+
+// позже в этом коде ...
+i match {
+ case 1 => println("one")
+ case 2 => println("two")
+ case _ => println("other")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=match %}
+
+```scala
+val i = 1
+
+// позже в этом коде ...
+i match
+ case 1 => println("one")
+ case 2 => println("two")
+ case _ => println("other")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Однако `match` на самом деле это выражение, означающее,
+что оно возвращает результат на основе совпадения с шаблоном, который вы можете привязать к переменной:
+
+{% tabs match-expression_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=match-expression_1 %}
+
+```scala
+val result = i match {
+ case 1 => "one"
+ case 2 => "two"
+ case _ => "other"
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=match-expression_1 %}
+
+```scala
+val result = i match
+ case 1 => "one"
+ case 2 => "two"
+ case _ => "other"
+```
+
+{% endtab %}
+{% endtabs %}
+
+`match` не ограничивается работой только с целочисленными значениями, его можно использовать с любым типом данных:
+
+{% tabs match-expression_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=match-expression_2 %}
+
+```scala
+val p = Person("Fred")
+
+// позже в этом коде ...
+p match {
+ case Person(name) if name == "Fred" =>
+ println(s"$name says, Yubba dubba doo")
+
+ case Person(name) if name == "Bam Bam" =>
+ println(s"$name says, Bam bam!")
+
+ case _ => println("Watch the Flintstones!")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=match-expression_2 %}
+
+```scala
+val p = Person("Fred")
+
+// позже в этом коде ...
+p match
+ case Person(name) if name == "Fred" =>
+ println(s"$name says, Yubba dubba doo")
+
+ case Person(name) if name == "Bam Bam" =>
+ println(s"$name says, Bam bam!")
+
+ case _ => println("Watch the Flintstones!")
+```
+
+{% endtab %}
+{% endtabs %}
+
+На самом деле `match` выражение можно использовать для проверки переменной на множестве различных типов шаблонов.
+В этом примере показано (а) как использовать `match` выражение в качестве тела метода и (б) как сопоставить все показанные различные типы:
+
+{% tabs match-expression_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=match-expression_3 %}
+
+```scala
+// getClassAsString - метод, принимающий один параметр любого типа.
+def getClassAsString(x: Any): String = x match {
+ case s: String => s"'$s' is a String"
+ case i: Int => "Int"
+ case d: Double => "Double"
+ case l: List[_] => "List"
+ case _ => "Unknown"
+}
+
+// примеры
+getClassAsString(1) // Int
+getClassAsString("hello") // 'hello' is a String
+getClassAsString(List(1, 2, 3)) // List
+```
+
+Поскольку метод `getClassAsString` принимает значение параметра типа `Any`, его можно разложить по любому шаблону.
+
+{% endtab %}
+{% tab 'Scala 3' for=match-expression_3 %}
+
+```scala
+// getClassAsString - метод, принимающий один параметр любого типа.
+def getClassAsString(x: Matchable): String = x match
+ case s: String => s"'$s' is a String"
+ case i: Int => "Int"
+ case d: Double => "Double"
+ case l: List[?] => "List"
+ case _ => "Unknown"
+
+// примеры
+getClassAsString(1) // Int
+getClassAsString("hello") // 'hello' is a String
+getClassAsString(List(1, 2, 3)) // List
+```
+
+Метод `getClassAsString` принимает в качестве параметра значение типа [Matchable]({{ site.scala3ref }}/other-new-features/matchable.html),
+которое может быть любым типом, поддерживающим сопоставление с образцом
+(некоторые типы не поддерживают сопоставление с образцом, поскольку это может нарушить инкапсуляцию).
+
+{% endtab %}
+{% endtabs %}
+
+Сопоставление с образцом в Scala гораздо _шире_.
+Шаблоны могут быть вложены друг в друга, результаты шаблонов могут быть связаны,
+а сопоставление шаблонов может даже определяться пользователем.
+Дополнительные сведения см. в примерах сопоставления с образцом в главе ["Структуры управления"][control].
+
+## `try`/`catch`/`finally`
+
+Структура управления Scala `try`/`catch`/`finally` позволяет перехватывать исключения.
+Она похожа на аналогичную структуру в Java, но её синтаксис соответствует `match` выражениям:
+
+{% tabs try class=tabs-scala-version %}
+{% tab 'Scala 2' for=try %}
+
+```scala
+try {
+ writeTextToFile(text)
+} catch {
+ case ioe: IOException => println("Got an IOException.")
+ case nfe: NumberFormatException => println("Got a NumberFormatException.")
+} finally {
+ println("Clean up your resources here.")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=try %}
+
+```scala
+try
+ writeTextToFile(text)
+catch
+ case ioe: IOException => println("Got an IOException.")
+ case nfe: NumberFormatException => println("Got a NumberFormatException.")
+finally
+ println("Clean up your resources here.")
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Циклы `while`
+
+В Scala также есть конструкция цикла `while`.
+Его однострочный синтаксис выглядит так:
+
+{% tabs while_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=while_1 %}
+
+```scala
+while (x >= 0) { x = f(x) }
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=while_1 %}
+
+```scala
+while x >= 0 do x = f(x)
+```
+Scala 3 по-прежнему поддерживает синтаксис Scala 2 для обратной совместимости.
+
+{% endtab %}
+{% endtabs %}
+
+Синтаксис `while` многострочного цикла выглядит следующим образом:
+
+{% tabs while_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=while_2 %}
+
+```scala
+var x = 1
+
+while (x < 3) {
+ println(x)
+ x += 1
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=while_2 %}
+
+```scala
+var x = 1
+
+while
+ x < 3
+do
+ println(x)
+ x += 1
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Пользовательские структуры управления
+
+Благодаря таким функциям, как параметры по имени, инфиксная нотация, плавные интерфейсы, необязательные круглые скобки,
+методы расширения и функции высшего порядка, вы также можете создавать свой собственный код,
+который работает так же, как управляющая структура.
+Вы узнаете об этом больше в разделе ["Структуры управления"][control].
+
+[control]: {% link _overviews/scala3-book/control-structures.md %}
diff --git a/_ru/scala3/book/taste-functions.md b/_ru/scala3/book/taste-functions.md
new file mode 100644
index 0000000000..f83da448e7
--- /dev/null
+++ b/_ru/scala3/book/taste-functions.md
@@ -0,0 +1,90 @@
+---
+layout: multipage-overview
+title: Функции первого класса
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице представлено введение в функции в Scala 3.
+language: ru
+num: 11
+previous-page: taste-methods
+next-page: taste-objects
+---
+
+Scala обладает большинством возможностей, которые вы ожидаете от функционального языка программирования, в том числе:
+
+- Lambdas (анонимные функции)
+- Функции высшего порядка (HOF)
+- Неизменяемые коллекции в стандартной библиотеке
+
+Лямбда-выражения, также известные как _анонимные функции_, играют важную роль в том, чтобы ваш код был кратким, но удобочитаемым.
+
+Метод `map` класса `List` является типичным примером функции высшего порядка —
+функции, которая принимает функцию в качестве параметра.
+
+Эти два примера эквивалентны и показывают, как умножить каждое число в списке на `2`, передав лямбда в метод `map`:
+
+
+{% tabs function_1 %}
+{% tab 'Scala 2 и 3' for=function_1 %}
+```scala
+val a = List(1, 2, 3).map(i => i * 2) // List(2,4,6)
+val b = List(1, 2, 3).map(_ * 2) // List(2,4,6)
+```
+{% endtab %}
+{% endtabs %}
+
+Примеры выше также эквивалентны следующему коду, в котором вместо лямбда используется метод `double`:
+
+
+{% tabs function_2 %}
+{% tab 'Scala 2 и 3' for=function_2 %}
+```scala
+def double(i: Int): Int = i * 2
+
+val a = List(1, 2, 3).map(i => double(i)) // List(2,4,6)
+val b = List(1, 2, 3).map(double) // List(2,4,6)
+```
+{% endtab %}
+{% endtabs %}
+
+> Если вы еще раньше не видели метод `map`, он применяет заданную функцию к каждому элементу в списке,
+> создавая новый список, содержащий результирующие значения.
+
+Передача лямбда-выражений функциям высшего порядка в классах коллекций (таких, как `List`) —
+это часть работы со Scala, которую вы будете делать каждый день.
+
+
+## Неизменяемые коллекции
+
+Когда вы работаете с неизменяемыми коллекциями, такими как `List`, `Vector`,
+а также с неизменяемыми классами `Map` и `Set`, важно знать,
+что эти функции не изменяют коллекцию, для которой они вызываются;
+вместо этого они возвращают новую коллекцию с обновленными данными.
+В результате также принято объединять их вместе в “свободном” стиле для решения проблем.
+
+Например, в этом примере показано, как отфильтровать коллекцию дважды,
+а затем умножить каждый элемент в оставшейся коллекции:
+
+
+{% tabs function_3 %}
+{% tab 'Scala 2 и 3' for=function_3 %}
+```scala
+// пример списка
+val nums = (1 to 10).toList // List(1,2,3,4,5,6,7,8,9,10)
+
+// методы могут быть сцеплены вместе
+val x = nums.filter(_ > 3)
+ .filter(_ < 7)
+ .map(_ * 10)
+
+// result: x == List(40, 50, 60)
+```
+{% endtab %}
+{% endtabs %}
+
+В дополнение к функциям высшего порядка, используемым в стандартной библиотеке,
+вы также можете [создавать свои собственные функции][higher-order].
+
+[higher-order]: {% link _overviews/scala3-book/fun-hofs.md %}
diff --git a/_ru/scala3/book/taste-hello-world.md b/_ru/scala3/book/taste-hello-world.md
new file mode 100644
index 0000000000..77442e43ca
--- /dev/null
+++ b/_ru/scala3/book/taste-hello-world.md
@@ -0,0 +1,205 @@
+---
+layout: multipage-overview
+title: Пример 'Hello, World!'
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом примере демонстрируется пример 'Hello, World!' на Scala 3.
+language: ru
+num: 5
+previous-page: taste-intro
+next-page: taste-repl
+---
+
+> **Подсказка**: в следующих примерах попробуйте выбрать предпочтительную для вас версию Scala.
+>
+
+## Ваша первая Scala-программа
+
+
+Пример “Hello, World!” на Scala выглядит следующим образом.
+Сначала поместите этот код в файл с именем _hello.scala_:
+
+
+{% tabs hello-world-demo class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=hello-world-demo %}
+```scala
+object hello {
+ def main(args: Array[String]) = {
+ println("Hello, World!")
+ }
+}
+```
+> В этом коде мы определили метод с именем `main` внутри Scala `object`-а с именем `hello`.
+> `object` в Scala похож на `class`, но определяет экземпляр singleton, который можно передать.
+> `main` принимает входной параметр с именем `args`, который должен иметь тип `Array[String]`
+> (`args` пока можно игнорировать).
+
+{% endtab %}
+
+{% tab 'Scala 3' for=hello-world-demo %}
+```scala
+@main def hello() = println("Hello, World!")
+```
+> В этом коде `hello` - это метод.
+> Он определяется с помощью `def` и объявляется в качестве основного метода с помощью аннотации `@main`.
+> Он выводит строку "Hello, World!" на стандартный вывод (STDOUT) с помощью метода `println`.
+
+{% endtab %}
+
+{% endtabs %}
+
+
+Затем скомпилируйте код с помощью `scalac`:
+
+```bash
+$ scalac hello.scala
+```
+
+Если вы переходите на Scala с Java: `scalac` похоже на `javac`, эта команда создает несколько файлов:
+
+
+{% tabs hello-world-outputs class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=hello-world-outputs %}
+```bash
+$ ls -1
+hello$.class
+hello.class
+hello.scala
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=hello-world-outputs %}
+```bash
+$ ls -1
+hello$package$.class
+hello$package.class
+hello$package.tasty
+hello.scala
+hello.class
+hello.tasty
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+Как и Java, файлы _.class_ представляют собой файлы байт-кода, и они готовы к запуску в JVM.
+
+Теперь вы можете запустить метод `hello` командой `scala`:
+
+```bash
+$ scala hello
+Hello, World!
+```
+
+Если запуск прошел успешно, поздравляем, вы только что скомпилировали и запустили свое первое приложение Scala.
+
+> Дополнительную информацию о sbt и других инструментах, упрощающих разработку на Scala, можно найти в главе [Инструменты Scala][scala_tools].
+
+## Запрос пользовательского ввода
+
+В нашем следующем примере давайте спросим имя пользователя, прежде чем приветствовать его!
+
+Есть несколько способов прочитать ввод из командной строки, но самый простой способ —
+использовать метод `readLine` из объекта _scala.io.StdIn_.
+Чтобы использовать этот метод, вам нужно сначала его импортировать, например:
+
+{% tabs import-readline %}
+{% tab 'Scala 2 и 3' for=import-readline %}
+```scala
+import scala.io.StdIn.readLine
+```
+{% endtab %}
+{% endtabs %}
+
+Чтобы продемонстрировать, как это работает, давайте создадим небольшой пример.
+Поместите этот исходный код в файл с именем _helloInteractive.scala_:
+
+
+{% tabs hello-world-interactive class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=hello-world-interactive %}
+```scala
+import scala.io.StdIn.readLine
+
+object helloInteractive {
+
+ def main(args: Array[String]) = {
+ println("Please enter your name:")
+ val name = readLine()
+
+ println("Hello, " + name + "!")
+ }
+
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=hello-world-interactive %}
+```scala
+import scala.io.StdIn.readLine
+
+@main def helloInteractive() =
+ println("Please enter your name:")
+ val name = readLine()
+
+ println("Hello, " + name + "!")
+```
+{% endtab %}
+
+{% endtabs %}
+
+
+В этом коде мы сохраняем результат из `readLine` в переменную с именем `name`,
+затем используем оператор над строками `+` для соединения `"Hello, "` с `name` и `"!"`, создавая одно единственное строковое значение.
+
+> Вы можете узнать больше об использовании val, прочитав главу [Переменные и типы данных](/scala3/book/taste-vars-data-types.html).
+
+Затем скомпилируйте код с помощью `scalac`:
+
+```bash
+$ scalac helloInteractive.scala
+```
+
+Затем запустите его с помощью `scala helloInteractive`. На этот раз программа сделает паузу после запроса вашего имени
+и подождет, пока вы не наберете имя и не нажмете клавишу возврата на клавиатуре.
+Выглядит это так:
+
+```bash
+$ scala helloInteractive
+Please enter your name:
+▌
+```
+
+Когда вы вводите свое имя в "приглашении", окончательное взаимодействие должно выглядеть так:
+
+```bash
+$ scala helloInteractive
+Please enter your name:
+Alvin Alexander
+Hello, Alvin Alexander!
+```
+
+### Примечание об импорте
+
+Как вы ранее видели, иногда определенные методы или другие типы определений, которые мы увидим позже, недоступны,
+если вы не используете подобное предложение `import`:
+
+{% tabs import-readline-2 %}
+{% tab 'Scala 2 и 3' for=import-readline-2 %}
+```scala
+import scala.io.StdIn.readLine
+```
+{% endtab %}
+{% endtabs %}
+
+Импорт помогает писать и распределять код несколькими способами:
+ - вы можете поместить код в несколько файлов, чтобы избежать беспорядка и облегчить навигацию в больших проектах.
+ - вы можете использовать библиотеку кода, возможно, написанную кем-то другим, которая имеет полезную функциональность.
+ - вы видите, откуда берется определенное определение (особенно если оно не было записано в текущем файле).
+
+[scala_tools]: {% link _overviews/scala3-book/scala-tools.md %}
diff --git a/_ru/scala3/book/taste-intro.md b/_ru/scala3/book/taste-intro.md
new file mode 100644
index 0000000000..58e15d8e22
--- /dev/null
+++ b/_ru/scala3/book/taste-intro.md
@@ -0,0 +1,31 @@
+---
+layout: multipage-overview
+title: Почувствуй Scala
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: В этой главе представлен общий обзор основных возможностей языка программирования Scala 3.
+language: ru
+num: 4
+previous-page: why-scala-3
+next-page: taste-hello-world
+---
+
+
+В этой главе представлен краткий обзор основных возможностей языка программирования Scala 3.
+После начального ознакомления остальная часть книги содержит более подробную информацию об описанных функциях,
+а [справочная документация][reference] содержит массу подробностей.
+
+## Настройка Скала
+
+На протяжении этой главы и остальной части книги мы рекомендуем вам пробовать примеры, скопировав их или набрав вручную.
+Инструменты, необходимые для работы с примерами на вашем компьютере, можно установить,
+следуя нашему [руководству для началы работы со Scala][get-started].
+
+> В качестве альтернативы вы можете запустить примеры в веб-браузере с помощью [Scastie](https://scastie.scala-lang.org),
+> полного онлайн-редактора и исполнителя кода для Scala.
+
+
+[reference]: {{ site.scala3ref }}/overview.html
+[get-started]: {% link _overviews/getting-started/install-scala.md %}
diff --git a/_ru/scala3/book/taste-methods.md b/_ru/scala3/book/taste-methods.md
new file mode 100644
index 0000000000..c881761826
--- /dev/null
+++ b/_ru/scala3/book/taste-methods.md
@@ -0,0 +1,167 @@
+---
+layout: multipage-overview
+title: Методы
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлено введение в определение и использование методов в Scala 3.
+language: ru
+num: 10
+previous-page: taste-modeling
+next-page: taste-functions
+---
+
+
+## Методы в Scala
+
+Классы Scala, case-классы, трейты, перечисления и объекты могут содержать методы.
+Синтаксис простого метода выглядит так:
+
+{% tabs method_1 %}
+{% tab 'Scala 2 и 3' for=method_1 %}
+```scala
+def methodName(param1: Type1, param2: Type2): ReturnType =
+ // тело метода
+ // находится здесь
+```
+{% endtab %}
+{% endtabs %}
+
+Вот несколько примеров:
+
+{% tabs method_2 %}
+{% tab 'Scala 2 и 3' for=method_2 %}
+```scala
+def sum(a: Int, b: Int): Int = a + b
+def concatenate(s1: String, s2: String): String = s1 + s2
+```
+{% endtab %}
+{% endtabs %}
+
+Вам не нужно объявлять возвращаемый тип метода, поэтому можно написать эти методы следующим образом, если хотите:
+
+{% tabs method_3 %}
+{% tab 'Scala 2 и 3' for=method_3 %}
+```scala
+def sum(a: Int, b: Int) = a + b
+def concatenate(s1: String, s2: String) = s1 + s2
+```
+{% endtab %}
+{% endtabs %}
+
+Вот как эти методы вызываются:
+
+{% tabs method_4 %}
+{% tab 'Scala 2 и 3' for=method_4 %}
+```scala
+val x = sum(1, 2)
+val y = concatenate("foo", "bar")
+```
+{% endtab %}
+{% endtabs %}
+
+Вот пример многострочного метода:
+
+{% tabs method_5 class=tabs-scala-version %}
+{% tab 'Scala 2' for=method_5 %}
+```scala
+def getStackTraceAsString(t: Throwable): String = {
+ val sw = new StringWriter
+ t.printStackTrace(new PrintWriter(sw))
+ sw.toString
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=method_5 %}
+```scala
+def getStackTraceAsString(t: Throwable): String =
+ val sw = new StringWriter
+ t.printStackTrace(new PrintWriter(sw))
+ sw.toString
+```
+{% endtab %}
+{% endtabs %}
+
+Параметры метода также могут иметь значения по умолчанию.
+В этом примере параметр `timeout` имеет значение по умолчанию `5000`:
+
+{% tabs method_6 %}
+{% tab 'Scala 2 и 3' for=method_6 %}
+```scala
+def makeConnection(url: String, timeout: Int = 5000): Unit =
+ println(s"url=$url, timeout=$timeout")
+```
+{% endtab %}
+{% endtabs %}
+
+Поскольку в объявлении метода указано значение по умолчанию для `timeout`, метод можно вызывать двумя способами:
+
+{% tabs method_7 %}
+{% tab 'Scala 2 и 3' for=method_7 %}
+```scala
+makeConnection("https://localhost") // url=http://localhost, timeout=5000
+makeConnection("https://localhost", 2500) // url=http://localhost, timeout=2500
+```
+{% endtab %}
+{% endtabs %}
+
+Scala также поддерживает использование _именованных параметров_ при вызове метода,
+поэтому вы можете вызвать этот метод, если хотите, вот так:
+
+{% tabs method_8 %}
+{% tab 'Scala 2 и 3' for=method_8 %}
+```scala
+makeConnection(
+ url = "https://localhost",
+ timeout = 2500
+)
+```
+{% endtab %}
+{% endtabs %}
+
+Именованные параметры особенно полезны, когда несколько параметров метода имеют один и тот же тип.
+Глядя на этот метод можно задаться вопросом,
+какие параметры установлены в `true` или `false`:
+
+{% tabs method_9 %}
+{% tab 'Scala 2 и 3' for=method_9 %}
+
+```scala
+engage(true, true, true, false)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Ключевое слово `extension` объявляет о намерении определить один или несколько методов расширения для параметра,
+заключенного в круглые скобки.
+Как показано в этом примере, параметр `s` типа `String` можно затем использовать в теле методов расширения.
+
+В следующем примере показано, как добавить метод `makeInt` в класс `String`.
+Здесь `makeInt` принимает параметр с именем `radix`.
+Код не учитывает возможные ошибки преобразования строки в целое число,
+но, опуская эту деталь, примеры показывают, как работают методы расширения:
+
+{% tabs extension %}
+{% tab 'Только в Scala 3' %}
+
+```scala
+extension (s: String)
+ def makeInt(radix: Int): Int = Integer.parseInt(s, radix)
+
+"1".makeInt(2) // Int = 1
+"10".makeInt(2) // Int = 2
+"100".makeInt(2) // Int = 4
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Смотрите также
+
+Методы Scala могут быть гораздо более мощными: они могут принимать параметры типа и параметры контекста.
+Методы подробно описаны в разделе ["Моделирование предметной области"][data-1].
+
+[data-1]: {% link _overviews/scala3-book/domain-modeling-tools.md %}
diff --git a/_ru/scala3/book/taste-modeling.md b/_ru/scala3/book/taste-modeling.md
new file mode 100644
index 0000000000..deede29e6a
--- /dev/null
+++ b/_ru/scala3/book/taste-modeling.md
@@ -0,0 +1,421 @@
+---
+layout: multipage-overview
+title: Моделирование данных
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлено введение в моделирование данных в Scala 3.
+language: ru
+num: 9
+previous-page: taste-control-structures
+next-page: taste-methods
+---
+
+
+Scala поддерживает как функциональное программирование (ФП), так и объектно-ориентированное программирование (ООП),
+а также слияние этих двух парадигм. В этом разделе представлен краткий обзор моделирования данных в ООП и ФП.
+
+## Моделирование данных в ООП
+
+При написании кода в стиле ООП двумя вашими основными инструментами для инкапсуляции данных будут _трейты_ и _классы_.
+
+### Трейты
+
+Трейты Scala можно использовать как простые интерфейсы,
+но они также могут содержать абстрактные и конкретные методы и поля, а также параметры, как и классы.
+Они предоставляют вам отличный способ организовать поведение в небольшие модульные блоки.
+Позже, когда вы захотите создать конкретные реализации атрибутов и поведения,
+классы и объекты могут расширять трейты, смешивая столько трейтов,
+сколько необходимо для достижения желаемого поведения.
+
+В качестве примера того, как использовать трейты в качестве интерфейсов,
+вот три трейта, которые определяют хорошо организованное и модульное поведение для животных, таких как собаки и кошки:
+
+{% tabs traits class=tabs-scala-version %}
+{% tab 'Scala 2' for=traits %}
+
+```scala
+trait Speaker {
+ def speak(): String // тело метода отсутствует, поэтому метод абстрактный
+}
+
+trait TailWagger {
+ def startTail(): Unit = println("tail is wagging")
+ def stopTail(): Unit = println("tail is stopped")
+}
+
+trait Runner {
+ def startRunning(): Unit = println("I’m running")
+ def stopRunning(): Unit = println("Stopped running")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=traits %}
+
+```scala
+trait Speaker:
+ def speak(): String // тело метода отсутствует, поэтому метод абстрактный
+
+trait TailWagger:
+ def startTail(): Unit = println("tail is wagging")
+ def stopTail(): Unit = println("tail is stopped")
+
+trait Runner:
+ def startRunning(): Unit = println("I’m running")
+ def stopRunning(): Unit = println("Stopped running")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Учитывая эти трейты, вот класс `Dog`, который их все расширяет,
+обеспечивая при этом поведение для абстрактного метода `speak`:
+
+{% tabs traits-class class=tabs-scala-version %}
+{% tab 'Scala 2' for=traits-class %}
+
+```scala
+class Dog(name: String) extends Speaker with TailWagger with Runner {
+ def speak(): String = "Woof!"
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=traits-class %}
+
+```scala
+class Dog(name: String) extends Speaker, TailWagger, Runner:
+ def speak(): String = "Woof!"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Обратите внимание, как класс расширяет трейты с помощью ключевого слова `extends`.
+
+Точно так же вот класс `Cat`, реализующий те же трейты,
+а также переопределяющий два конкретных метода, которые он наследует:
+
+{% tabs traits-override class=tabs-scala-version %}
+{% tab 'Scala 2' for=traits-override %}
+
+```scala
+class Cat(name: String) extends Speaker with TailWagger with Runner {
+ def speak(): String = "Meow"
+ override def startRunning(): Unit = println("Yeah ... I don’t run")
+ override def stopRunning(): Unit = println("No need to stop")
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=traits-override %}
+
+```scala
+class Cat(name: String) extends Speaker, TailWagger, Runner:
+ def speak(): String = "Meow"
+ override def startRunning(): Unit = println("Yeah ... I don’t run")
+ override def stopRunning(): Unit = println("No need to stop")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Примеры ниже показывают, как используются эти классы:
+
+{% tabs traits-use class=tabs-scala-version %}
+{% tab 'Scala 2' for=traits-use %}
+
+```scala
+val d = new Dog("Rover")
+println(d.speak()) // печатает "Woof!"
+
+val c = new Cat("Morris")
+println(c.speak()) // "Meow"
+c.startRunning() // "Yeah ... I don’t run"
+c.stopRunning() // "No need to stop"
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=traits-use %}
+
+```scala
+val d = Dog("Rover")
+println(d.speak()) // печатает "Woof!"
+
+val c = Cat("Morris")
+println(c.speak()) // "Meow"
+c.startRunning() // "Yeah ... I don’t run"
+c.stopRunning() // "No need to stop"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Если этот код имеет смысл — отлично, вам удобно использовать трейты в качестве интерфейсов.
+Если нет, не волнуйтесь, они более подробно описаны в главе ["Моделирование предметной области"][data-1].
+
+
+### Классы
+
+Классы Scala используются в программировании в стиле ООП.
+Вот пример класса, который моделирует "человека".
+В ООП поля обычно изменяемы, поэтому оба, `firstName` и `lastName` объявлены как `var` параметры:
+
+{% tabs class_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=class_1 %}
+
+```scala
+class Person(var firstName: String, var lastName: String) {
+ def printFullName() = println(s"$firstName $lastName")
+}
+
+val p = new Person("John", "Stephens")
+println(p.firstName) // "John"
+p.lastName = "Legend"
+p.printFullName() // "John Legend"
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=class_1 %}
+
+```scala
+class Person(var firstName: String, var lastName: String):
+ def printFullName() = println(s"$firstName $lastName")
+
+val p = Person("John", "Stephens")
+println(p.firstName) // "John"
+p.lastName = "Legend"
+p.printFullName() // "John Legend"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Обратите внимание, что объявление класса создает конструктор:
+
+{% tabs class_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=class_2 %}
+
+```scala
+// код использует конструктор из объявления класса
+val p = new Person("John", "Stephens")
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=class_2 %}
+
+```scala
+// код использует конструктор из объявления класса
+val p = Person("John", "Stephens")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Конструкторы и другие темы, связанные с классами, рассматриваются в главе ["Моделирование предметной области"][data-1].
+
+## Моделирование данных в ФП
+
+При написании кода в стиле ФП вы будете использовать следующие понятия:
+
+- Алгебраические типы данных для определения данных.
+- Трейты для функциональности данных.
+
+### Перечисления и суммированные типы
+
+Суммированные типы (_sum types_) — это один из способов моделирования алгебраических типов данных (ADT) в Scala.
+
+Они используются, когда данные могут быть представлены с различными вариантами.
+
+Например, у пиццы есть три основных атрибута:
+
+- Размер корки
+- Тип корки
+- Начинки
+-
+Они кратко смоделированы с помощью перечислений,
+которые представляют собой суммированные типы, содержащие только одноэлементные значения:
+
+{% tabs enum_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=enum_1 %}
+
+В Scala 2 `sealed` классы и `case object` объединяются для определения перечисления:
+
+```scala
+sealed abstract class CrustSize
+object CrustSize {
+ case object Small extends CrustSize
+ case object Medium extends CrustSize
+ case object Large extends CrustSize
+}
+
+sealed abstract class CrustType
+object CrustType {
+ case object Thin extends CrustType
+ case object Thick extends CrustType
+ case object Regular extends CrustType
+}
+
+sealed abstract class Topping
+object Topping {
+ case object Cheese extends Topping
+ case object Pepperoni extends Topping
+ case object BlackOlives extends Topping
+ case object GreenOlives extends Topping
+ case object Onions extends Topping
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=enum_1 %}
+
+Scala 3 предлагает конструкцию `enum` для определения перечислений:
+
+```scala
+enum CrustSize:
+ case Small, Medium, Large
+
+enum CrustType:
+ case Thin, Thick, Regular
+
+enum Topping:
+ case Cheese, Pepperoni, BlackOlives, GreenOlives, Onions
+```
+
+{% endtab %}
+{% endtabs %}
+
+Когда у вас есть перечисление, вы можете импортировать его элементы как обычные значения:
+
+{% tabs enum_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=enum_2 %}
+
+```scala
+import CrustSize._
+val currentCrustSize = Small
+
+// перечисления в сопоставлении с шаблоном
+currentCrustSize match {
+ case Small => println("Small crust size")
+ case Medium => println("Medium crust size")
+ case Large => println("Large crust size")
+}
+
+// перечисления в операторе `if`
+if (currentCrustSize == Small) println("Small crust size")
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=enum_2 %}
+
+```scala
+import CrustSize.*
+val currentCrustSize = Small
+
+// перечисления в сопоставлении с шаблоном
+currentCrustSize match
+ case Small => println("Small crust size")
+ case Medium => println("Medium crust size")
+ case Large => println("Large crust size")
+
+// перечисления в операторе `if`
+if currentCrustSize == Small then println("Small crust size")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Вот еще один пример того, как создать суммированные типы с помощью Scala,
+это не будет называться перечислением, потому что у случая `Succ` есть параметры:
+
+{% tabs enum_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=enum_3 %}
+
+```scala
+sealed abstract class Nat
+object Nat {
+ case object Zero extends Nat
+ case class Succ(pred: Nat) extends Nat
+}
+```
+
+Суммированные типы подробно рассматриваются в разделе ["Моделирование предметной области"]({% link _overviews/scala3-book/domain-modeling-tools.md %}) этой книги.
+
+{% endtab %}
+{% tab 'Scala 3' for=enum_3 %}
+
+```scala
+enum Nat:
+ case Zero
+ case Succ(pred: Nat)
+```
+
+Перечисления подробно рассматриваются в разделе ["Моделирование предметной области"]({% link _overviews/scala3-book/domain-modeling-tools.md %}) этой книги
+и в [справочной документации]({{ site.scala3ref }}/enums/enums.html).
+
+{% endtab %}
+{% endtabs %}
+
+### Продуктовые типы
+
+Тип продукта — это алгебраический тип данных (ADT), который имеет только одну форму,
+например, одноэлементный объект, представленный в Scala `case object`;
+или неизменяемая структура с доступными полями, представленная `case class`.
+
+`case class` обладает всеми функциями класса, а также содержит встроенные дополнительные функции,
+которые делают его полезным для функционального программирования.
+Когда компилятор видит ключевое слово `case` перед `class`, то применяет следующие эффекты и преимущества:
+
+- Параметры конструктора `case class` по умолчанию являются общедоступными полями `val`, поэтому поля неизменяемы,
+ а методы доступа генерируются для каждого параметра.
+- Генерируется метод `unapply`, который позволяет использовать `case class` в выражениях match различными способами.
+- В классе создается метод `copy`. Он позволяет создавать копии объекта без изменения исходного.
+- Создаются методы `equals` и `hashCode` для реализации структурного равенства.
+- Генерируется метод по умолчанию `toString`, полезный для отладки.
+
+Вы _можете_ вручную добавить все эти методы в класс самостоятельно,
+но, поскольку эти функции так часто используются в функциональном программировании,
+использование case класса гораздо удобнее.
+
+Этот код демонстрирует несколько функций `case class`:
+
+{% tabs case-class %}
+{% tab 'Scala 2 и 3' for=case-class %}
+
+```scala
+// определение case class
+case class Person(
+ name: String,
+ vocation: String
+)
+
+// создание экземпляра case class
+val p = Person("Reginald Kenneth Dwight", "Singer")
+
+// полезный метод toString
+p // : Person = Person(Reginald Kenneth Dwight,Singer)
+
+// можно получить доступ к неизменяемым полям
+p.name // "Reginald Kenneth Dwight"
+p.name = "Joe" // error: can’t reassign a val field
+
+// при необходимости внести изменения используйте метод `copy`
+// для “update as you copy”
+val p2 = p.copy(name = "Elton John")
+p2 // : Person = Person(Elton John,Singer)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Дополнительные сведения о `case` классах см. в разделах ["Моделирование предметной области"][data-1].
+
+[data-1]: {% link _overviews/scala3-book/domain-modeling-tools.md %}
diff --git a/_ru/scala3/book/taste-objects.md b/_ru/scala3/book/taste-objects.md
new file mode 100644
index 0000000000..a244c7cfa2
--- /dev/null
+++ b/_ru/scala3/book/taste-objects.md
@@ -0,0 +1,153 @@
+---
+layout: multipage-overview
+title: Одноэлементные объекты
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлено введение в использование одноэлементных объектов в Scala 3.
+language: ru
+num: 12
+previous-page: taste-functions
+next-page: taste-collections
+---
+
+
+В Scala ключевое слово `object` создает объект Singleton (паттерн проектирования "Одиночка").
+Другими словами, объект определяет класс, который имеет только один экземпляр.
+
+Объекты имеют несколько применений:
+
+- Они используются для создания коллекций служебных методов.
+- _Сопутствующий объект_ — это объект с тем же именем, что и у класса, определенного в этом же файле.
+ В этой ситуации такой класс также называется _сопутствующим классом_.
+- Они используются для реализации трейтов для создания _модулей_.
+
+
+## “Полезные” методы
+
+Поскольку `object` является "одиночкой", к его методам можно обращаться так же, как к статичным методам в Java классе.
+Например, этот объект `StringUtils` содержит небольшой набор методов, связанных со строками:
+
+{% tabs object_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=object_1 %}
+```scala
+object StringUtils {
+ def isNullOrEmpty(s: String): Boolean = s == null || s.trim.isEmpty
+ def leftTrim(s: String): String = s.replaceAll("^\\s+", "")
+ def rightTrim(s: String): String = s.replaceAll("\\s+$", "")
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=object_1 %}
+```scala
+object StringUtils:
+ def isNullOrEmpty(s: String): Boolean = s == null || s.trim.isEmpty
+ def leftTrim(s: String): String = s.replaceAll("^\\s+", "")
+ def rightTrim(s: String): String = s.replaceAll("\\s+$", "")
+```
+{% endtab %}
+{% endtabs %}
+
+Поскольку `StringUtils` - это "одиночка", его методы можно вызывать непосредственно для объекта:
+
+{% tabs object_2 %}
+{% tab 'Scala 2 и 3' for=object_2 %}
+```scala
+val x = StringUtils.isNullOrEmpty("") // true
+val x = StringUtils.isNullOrEmpty("a") // false
+```
+{% endtab %}
+{% endtabs %}
+
+## Сопутствующие объекты
+
+Сопутствующие класс или объект могут получить доступ к закрытым членам своего компаньона.
+Используйте сопутствующий объект для методов и значений, которые не относятся к экземплярам сопутствующего класса.
+
+В этом примере показано, как метод `area` в сопутствующем классе
+может получить доступ к приватному методу `calculateArea` в своем сопутствующем объекте:
+
+{% tabs object_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=object_3 %}
+```scala
+import scala.math._
+
+class Circle(radius: Double) {
+ import Circle._
+ def area: Double = calculateArea(radius)
+}
+
+object Circle {
+ private def calculateArea(radius: Double): Double =
+ Pi * pow(radius, 2.0)
+}
+
+val circle1 = new Circle(5.0)
+circle1.area // Double = 78.53981633974483
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=object_3 %}
+```scala
+import scala.math.*
+
+class Circle(radius: Double):
+ import Circle.*
+ def area: Double = calculateArea(radius)
+
+object Circle:
+ private def calculateArea(radius: Double): Double =
+ Pi * pow(radius, 2.0)
+
+val circle1 = Circle(5.0)
+circle1.area // Double = 78.53981633974483
+```
+{% endtab %}
+{% endtabs %}
+
+## Создание модулей из трейтов
+
+Объекты также можно использовать для реализации трейтов для создания модулей.
+Эта техника берет две трейта и объединяет их для создания конкретного `object`-а:
+
+{% tabs object_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=object_4 %}
+```scala
+trait AddService {
+ def add(a: Int, b: Int) = a + b
+}
+
+trait MultiplyService {
+ def multiply(a: Int, b: Int) = a * b
+}
+
+// реализация трейтов выше в качестве конкретного объекта
+object MathService extends AddService with MultiplyService
+
+// использование объекта
+import MathService._
+println(add(1,1)) // 2
+println(multiply(2,2)) // 4
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=object_4 %}
+```scala
+trait AddService:
+ def add(a: Int, b: Int) = a + b
+
+trait MultiplyService:
+ def multiply(a: Int, b: Int) = a * b
+
+// реализация трейтов выше в качестве конкретного объекта
+object MathService extends AddService, MultiplyService
+
+// использование объекта
+import MathService.*
+println(add(1,1)) // 2
+println(multiply(2,2)) // 4
+```
+{% endtab %}
+{% endtabs %}
diff --git a/_ru/scala3/book/taste-repl.md b/_ru/scala3/book/taste-repl.md
new file mode 100644
index 0000000000..e45dc0e8cc
--- /dev/null
+++ b/_ru/scala3/book/taste-repl.md
@@ -0,0 +1,93 @@
+---
+layout: multipage-overview
+title: REPL
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлено введение в Scala REPL.
+language: ru
+num: 6
+previous-page: taste-hello-world
+next-page: taste-vars-data-types
+---
+
+Scala REPL (“Read-Evaluate-Print-Loop”) - это интерпретатор командной строки,
+который используется в качестве “игровой площадки” для тестирования Scala кода.
+Для того чтобы запустить сеанс REPL, надо выполнить команду `scala` или `scala3` в зависимости от операционной системы,
+затем будет выведено приглашение “Welcome”, подобное этому:
+
+{% tabs command-line class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=command-line %}
+```bash
+$ scala
+Welcome to Scala {{site.scala-version}} (OpenJDK 64-Bit Server VM, Java 1.8.0_342).
+Type in expressions for evaluation. Or try :help.
+
+scala> _
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=command-line %}
+```bash
+$ scala
+Welcome to Scala {{site.scala-3-version}} (1.8.0_322, Java OpenJDK 64-Bit Server VM).
+Type in expressions for evaluation. Or try :help.
+
+scala> _
+```
+{% endtab %}
+
+{% endtabs %}
+
+REPL — это интерпретатор командной строки, поэтому он ждет, пока вы что-нибудь наберете.
+Теперь можно вводить выражения Scala, чтобы увидеть, как они работают:
+
+{% tabs expression-one %}
+{% tab 'Scala 2 и 3' for=expression-one %}
+````
+scala> 1 + 1
+val res0: Int = 2
+
+scala> 2 + 2
+val res1: Int = 4
+````
+{% endtab %}
+{% endtabs %}
+
+Как показано в выводе, если не присваивать переменную результату выражения,
+REPL автоматически создает для вас переменные с именами `res0`, `res1` и т.д.
+Эти имена переменных можно использовать в последующих выражениях:
+
+{% tabs expression-two %}
+{% tab 'Scala 2 и 3' for=expression-two %}
+````
+scala> val x = res0 * 10
+val x: Int = 20
+````
+{% endtab %}
+{% endtabs %}
+
+Обратите внимание, что в REPL output также показываются результаты выражений.
+
+В REPL можно проводить всевозможные эксперименты.
+В этом примере показано, как создать, а затем вызвать метод `sum`:
+
+{% tabs expression-three %}
+{% tab 'Scala 2 и 3' for=expression-three %}
+````
+scala> def sum(a: Int, b: Int): Int = a + b
+def sum(a: Int, b: Int): Int
+
+scala> sum(2, 2)
+val res2: Int = 4
+````
+{% endtab %}
+{% endtabs %}
+
+Также можно использовать игровую среду на основе браузера [scastie.scala-lang.org](https://scastie.scala-lang.org).
+
+Если вы предпочитаете писать код в текстовом редакторе, а не в консоли, то можно использовать [worksheet].
+
+[worksheet]: {% link _overviews/scala3-book/tools-worksheets.md %}
diff --git a/_ru/scala3/book/taste-summary.md b/_ru/scala3/book/taste-summary.md
new file mode 100644
index 0000000000..f2ca4e86da
--- /dev/null
+++ b/_ru/scala3/book/taste-summary.md
@@ -0,0 +1,35 @@
+---
+layout: multipage-overview
+title: Обзор
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице представлен краткий обзор предыдущих разделов 'Taste of Scala'.
+language: ru
+num: 16
+previous-page: taste-toplevel-definitions
+next-page: first-look-at-types
+---
+
+
+В предыдущих разделах вы видели:
+
+- Как использовать Scala REPL
+- Как создавать переменные с помощью `val` и `var`
+- Некоторые распространенные типы данных
+- Структуры управления
+- Как моделировать реальный мир, используя стили ООП и ФП
+- Как создавать и использовать методы
+- Как использовать лямбды (анонимные функции) и функции высшего порядка
+- Как использовать объекты для нескольких целей
+- Введение в [контекстную абстракцию][contextual]
+
+Мы также упоминали, что если вы предпочитаете использовать игровую среду на основе браузера вместо Scala REPL,
+вы также можете использовать [Scastie](https://scastie.scala-lang.org/).
+
+Scala включает в себя еще больше возможностей, которые не рассматриваются в этом кратком обзоре.
+Дополнительную информацию см. в оставшейся части этой книги и [в справочной документации][reference].
+
+[reference]: {{ site.scala3ref }}/overview.html
+[contextual]: {% link _overviews/scala3-book/ca-contextual-abstractions-intro.md %}
diff --git a/_ru/scala3/book/taste-toplevel-definitions.md b/_ru/scala3/book/taste-toplevel-definitions.md
new file mode 100644
index 0000000000..3d15f774a8
--- /dev/null
+++ b/_ru/scala3/book/taste-toplevel-definitions.md
@@ -0,0 +1,79 @@
+---
+layout: multipage-overview
+title: Верхнеуровневые определения
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: На этой странице представлено введение в определения верхнего уровня в Scala 3.
+language: ru
+num: 15
+previous-page: taste-contextual-abstractions
+next-page: taste-summary
+---
+
+
+В Scala 3 все виды определений могут быть записаны на “верхнем уровне” ваших файлов с исходным кодом.
+Например, вы можете создать файл с именем _MyCoolApp.scala_ и поместить в него следующее содержимое:
+
+{% tabs toplevel_1 %}
+{% tab 'Только в Scala 3' for=toplevel_1 %}
+```scala
+import scala.collection.mutable.ArrayBuffer
+
+enum Topping:
+ case Cheese, Pepperoni, Mushrooms
+
+import Topping.*
+class Pizza:
+ val toppings = ArrayBuffer[Topping]()
+
+val p = Pizza()
+
+extension (s: String)
+ def capitalizeAllWords = s.split(" ").map(_.capitalize).mkString(" ")
+
+val hwUpper = "hello, world".capitalizeAllWords
+
+type Money = BigDecimal
+
+// по желанию здесь можно указать ещё больше определений ...
+
+@main def myApp =
+ p.toppings += Cheese
+ println("show me the code".capitalizeAllWords)
+```
+{% endtab %}
+{% endtabs %}
+
+Как показано, нет необходимости помещать эти определения внутрь конструкции `package`, `class` или иной конструкции.
+
+## Заменяет объекты пакета
+
+Если вы знакомы со Scala 2, этот подход заменяет _объекты пакета_ (_package objects_).
+Но, будучи намного проще в использовании, они работают одинаково:
+когда вы помещаете определение в пакет с именем `foo`,
+вы можете получить доступ к этому определению во всех других пакетах в `foo`, например, в пакете `foo.bar`,
+как в этом примере:
+
+{% tabs toplevel_2 %}
+{% tab 'Только в Scala 3' for=toplevel_2 %}
+```scala
+package foo {
+ def double(i: Int) = i * 2
+}
+
+package foo {
+ package bar {
+ @main def fooBarMain =
+ println(s"${double(1)}") // это работает
+ }
+}
+```
+{% endtab %}
+{% endtabs %}
+
+Фигурные скобки используются в этом примере, чтобы подчеркнуть вложенность пакета.
+
+Преимуществом такого подхода является то, что можно размещать определения в пакете с именем `com.acme.myapp`,
+а затем можно ссылаться на эти определения в `com.acme.myapp.model`, `com.acme.myapp.controller` и т.д.
diff --git a/_ru/scala3/book/taste-vars-data-types.md b/_ru/scala3/book/taste-vars-data-types.md
new file mode 100644
index 0000000000..7409db07b4
--- /dev/null
+++ b/_ru/scala3/book/taste-vars-data-types.md
@@ -0,0 +1,276 @@
+---
+layout: multipage-overview
+title: Переменные и типы данных
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе демонстрируются переменные val и var, а также некоторые распространенные типы данных Scala.
+language: ru
+num: 7
+previous-page: taste-repl
+next-page: taste-control-structures
+---
+
+
+В этом разделе представлен обзор переменных и типов данных Scala.
+
+## Два вида переменных
+
+Когда вы создаете новую переменную в Scala, то объявляете, является ли переменная неизменяемой или изменяемой:
+
+
+
+
+
Тип переменной
+
Описание
+
+
+
+
+
val
+
Создает неизменяемую переменную — как final в Java. Вы всегда должны создавать переменную с val, если нет причины, по которой вам нужна изменяемая переменная.
+
+
+
var
+
Создает изменяемую переменную и должна использоваться только в том случае, если содержимое переменной будет меняться с течением времени.
+
+
+
+
+Эти примеры показывают, как создавать `val` и `var` переменные:
+
+{% tabs var-express-1 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+// неизменяемая
+val a = 0
+
+// изменяемая
+var b = 1
+```
+{% endtab %}
+{% endtabs %}
+
+В программе `val` переназначить нельзя.
+Появится ошибка компилятора, если попытаться её изменить:
+
+{% tabs var-express-2 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val msg = "Hello, world"
+msg = "Aloha" // ошибка "reassignment to val"; этот код не скомпилируется
+```
+{% endtab %}
+{% endtabs %}
+
+И наоборот, `var` можно переназначить:
+
+{% tabs var-express-3 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+var msg = "Hello, world"
+msg = "Aloha" // этот код скомпилируется, потому что var может быть переназначена
+```
+{% endtab %}
+{% endtabs %}
+
+## Объявление типов переменных
+
+Когда вы создаете переменную, то можете явно объявить ее тип или позволить компилятору его вывести:
+
+{% tabs var-express-4 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val x: Int = 1 // явно
+val x = 1 // неявно; компилятор выводит тип
+```
+{% endtab %}
+{% endtabs %}
+
+Вторая форма известна как _вывод типа_, и это отличный способ сделать кратким код такого типа.
+Компилятор Scala обычно может определить тип данных за вас, как показано в выводе этих примеров REPL:
+
+{% tabs var-express-5 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+scala> val x = 1
+val x: Int = 1
+
+scala> val s = "a string"
+val s: String = a string
+
+scala> val nums = List(1, 2, 3)
+val nums: List[Int] = List(1, 2, 3)
+```
+{% endtab %}
+{% endtabs %}
+
+Вы всегда можете явно объявить тип переменной, если хотите,
+но в простых присваиваниях, подобных нижеследующим, в этом нет необходимости:
+
+{% tabs var-express-6 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val x: Int = 1
+val s: String = "a string"
+val p: Person = Person("Richard")
+```
+{% endtab %}
+{% endtabs %}
+
+Обратите внимание, что при таком подходе код кажется более многословным, чем необходимо.
+
+## Встроенные типы данных
+
+Scala поставляется со стандартными числовыми типами данных, которые вы ожидаете,
+и все они являются полноценными экземплярами классов.
+В Scala все является объектом.
+
+Эти примеры показывают, как объявлять переменные числовых типов:
+
+{% tabs var-express-7 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val b: Byte = 1
+val i: Int = 1
+val l: Long = 1
+val s: Short = 1
+val d: Double = 2.0
+val f: Float = 3.0
+```
+{% endtab %}
+{% endtabs %}
+
+Поскольку `Int` и `Double` являются числовыми типами по умолчанию, то обычно они создаются без явного объявления типа:
+
+{% tabs var-express-8 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val i = 123 // по умолчанию Int
+val j = 1.0 // по умолчанию Double
+```
+{% endtab %}
+{% endtabs %}
+
+В своем коде вы также можете добавлять символы `L`, `D` и `F` (и их эквиваленты в нижнем регистре) к числам,
+чтобы указать, что они являются `Long`, `Double` или `Float` значениями:
+
+{% tabs var-express-9 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val x = 1_000L // val x: Long = 1000
+val y = 2.2D // val y: Double = 2.2
+val z = 3.3F // val z: Float = 3.3
+```
+{% endtab %}
+{% endtabs %}
+
+Когда вам нужны действительно большие числа, используйте типы `BigInt` и `BigDecimal`:
+
+{% tabs var-express-10 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+var a = BigInt(1_234_567_890_987_654_321L)
+var b = BigDecimal(123_456.789)
+```
+{% endtab %}
+{% endtabs %}
+
+Где `Double` и `Float` - это приблизительные десятичные числа, а `BigDecimal` используется для точной арифметики.
+
+В Scala также есть типы данных `String` и `Char`:
+
+{% tabs var-express-11 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val name = "Bill" // String
+val c = 'a' // Char
+```
+{% endtab %}
+{% endtabs %}
+
+### Строки
+
+Строки Scala похожи на строки Java, но у них есть две замечательные дополнительные функции:
+
+- Они поддерживают интерполяцию строк
+- Легко создавать многострочные строки
+
+#### Строковая интерполяция
+
+Интерполяция строк обеспечивает очень удобный способ использования переменных внутри строк.
+Например, учитывая эти три переменные:
+
+{% tabs var-express-12 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val firstName = "John"
+val mi = 'C'
+val lastName = "Doe"
+```
+{% endtab %}
+{% endtabs %}
+
+Вы можете объединить эти переменные в строку следующим образом:
+
+{% tabs var-express-13 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+println(s"Name: $firstName $mi $lastName") // "Name: John C Doe"
+```
+{% endtab %}
+{% endtabs %}
+
+Просто поставьте перед строкой букву `s`, а затем поставьте символ `$` перед именами переменных внутри строки.
+
+Чтобы вставить произвольные выражения в строку, заключите их в фигурные скобки:
+
+{% tabs var-express-14 %}
+{% tab 'Scala 2 и 3' %}
+
+``` scala
+println(s"2 + 2 = ${2 + 2}") // prints "2 + 2 = 4"
+
+val x = -1
+println(s"x.abs = ${x.abs}") // prints "x.abs = 1"
+```
+{% endtab %}
+{% endtabs %}
+
+Символ `s`, помещенный перед строкой, является лишь одним из возможных интерполяторов.
+Если использовать `f` вместо `s`, можно использовать синтаксис форматирования в стиле `printf` в строке.
+Кроме того, интерполятор строк - это всего лишь специальный метод, и его можно определить самостоятельно.
+Например, некоторые библиотеки баз данных определяют очень мощный интерполятор `sql`.
+
+#### Многострочные строки
+
+Многострочные строки создаются путем включения строки в три двойные кавычки:
+
+{% tabs var-express-15 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val quote = """The essence of Scala:
+ Fusion of functional and object-oriented
+ programming in a typed setting."""
+```
+{% endtab %}
+{% endtabs %}
+
+> Дополнительные сведения о строковых интерполяторах и многострочных строках см. в главе [“Первое знакомство с типами”][first-look].
+
+[first-look]: {% link _overviews/scala3-book/first-look-at-types.md %}
diff --git a/_ru/scala3/book/tools-sbt.md b/_ru/scala3/book/tools-sbt.md
new file mode 100644
index 0000000000..2dcb91b7de
--- /dev/null
+++ b/_ru/scala3/book/tools-sbt.md
@@ -0,0 +1,488 @@
+---
+layout: multipage-overview
+title: Сборка и тестирование проектов Scala с помощью Sbt
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе рассматриваются широко используемый инструмент сборки sbt и библиотека тестирования ScalaTest.
+language: ru
+num: 70
+previous-page: scala-tools
+next-page: tools-worksheets
+---
+
+В этом разделе будут показаны два инструмента, которые обычно используются в проектах Scala:
+
+- инструмент сборки [sbt](https://www.scala-sbt.org)
+- [ScalaTest](https://www.scalatest.org) - среда тестирования исходного кода
+
+Начнем с использования sbt для создания Scala-проектов, а затем рассмотрим, как использовать sbt и ScalaTest вместе для тестирования.
+
+> Если вы хотите узнать об инструментах, которые помогут вам перенести код Scala 2 на Scala 3,
+> ознакомьтесь с нашим [Руководством по миграции на Scala 3](/scala3/guides/migration/compatibility-intro.html).
+
+## Создание проектов Scala с помощью sbt
+
+Можно использовать несколько различных инструментов для создания проектов Scala, включая Ant, Maven, Gradle, Mill и другие.
+Но инструмент под названием _sbt_ был первым инструментом сборки, специально созданным для Scala.
+
+> Чтобы установить sbt, см. [страницу загрузки](https://www.scala-sbt.org/download.html) или нашу страницу ["Начало работы"][getting_started].
+
+### Создание проекта "Hello, world"
+
+Вы можете создать sbt проект "Hello, world" всего за несколько шагов.
+Сначала создайте каталог для работы и перейдите в него:
+
+```bash
+$ mkdir hello
+$ cd hello
+```
+
+В каталоге `hello` создайте подкаталог `project`:
+
+```bash
+$ mkdir project
+```
+
+Создайте файл с именем _build.properties_ в каталоге `project` со следующим содержимым:
+
+```text
+sbt.version=1.10.11
+```
+
+Затем создайте файл с именем _build.sbt_ в корневом каталоге проекта, содержащий следующую строку:
+
+```scala
+scalaVersion := "{{ site.scala-3-version }}"
+```
+
+Теперь создайте файл с именем _Hello.scala_ (первая часть имени не имеет значения) со следующей строкой:
+
+```scala
+@main def helloWorld = println("Hello, world")
+```
+
+Это все, что нужно сделать.
+
+Должна получиться следующая структура проекта:
+
+```bash
+$ tree
+.
+├── build.sbt
+├── Hello.scala
+└── project
+ └── build.properties
+```
+
+Теперь запустите проект с помощью команды `sbt`:
+
+```bash
+$ sbt run
+```
+
+Вы должны увидеть вывод, который выглядит следующим образом, включая `"Hello, world"` из программы:
+
+```bash
+$ sbt run
+[info] welcome to sbt 1.6.1 (AdoptOpenJDK Java 11.x)
+[info] loading project definition from project ...
+[info] loading settings for project from build.sbt ...
+[info] compiling 1 Scala source to target/scala-3.0.0/classes ...
+[info] running helloWorld
+Hello, world
+[success] Total time: 2 s
+```
+
+Программа запуска — средство командной строки `sbt` - загружает версию sbt, установленную в файле _project/build.properties_,
+которая загружает версию компилятора Scala, установленную в файле _build.sbt_,
+компилирует код в файле _Hello.scala_ и запускает результирующий байт-код.
+
+Если посмотреть на корневой каталог, то можно увидеть, что появилась папка с именем _target_.
+Это рабочие каталоги, которые использует sbt.
+
+Создание и запуск небольшого проекта Scala с помощью sbt занимает всего несколько простых шагов.
+
+### Использование sbt в более крупных проектах
+
+Для небольшого проекта это все, что требует sbt для запуска.
+Для более крупных проектов с большим количеством файлов исходного кода, зависимостей или плагинов,
+потребуется создать организованную структуру каталогов.
+Остальная часть этого раздела демонстрирует структуру, которую использует sbt.
+
+### Структура каталогов sbt
+
+Как и Maven, sbt использует стандартную структуру каталогов проекта.
+Преимуществом стандартизации является то, что, как только структура станет привычной,
+станет легко работать с другими проектами Scala/sbt.
+
+Первое, что нужно знать - это то, что под корневым каталогом проекта sbt ожидает структуру каталогов,
+которая выглядит следующим образом:
+
+```text
+.
+├── build.sbt
+├── project/
+│ └── build.properties
+├── src/
+│ ├── main/
+│ │ ├── java/
+│ │ ├── resources/
+│ │ └── scala/
+│ └── test/
+│ ├── java/
+│ ├── resources/
+│ └── scala/
+└── target/
+```
+
+Также в корневой каталог можно добавить каталог _lib_,
+если необходимо в свой проект добавить внешние зависимости — файлы JAR.
+
+Если достаточно создать проект, который имеет только файлы исходного кода Scala и тесты,
+но не будет использовать Java файлы и не нуждается в каких-либо "ресурсах" (встроенные изображения, файлы конфигурации и т.д.),
+то в каталоге _src_ можно оставить только:
+
+```text
+.
+└── src/
+ ├── main/
+ │ └── scala/
+ └── test/
+ └── scala/
+```
+
+### "Hello, world" со структурой каталогов sbt
+
+Создать такую структуру каталогов просто.
+Существуют инструменты, которые сделают это за вас, но если вы используете систему Unix/Linux,
+можно использовать следующие команды для создания структуры каталогов проекта sbt:
+
+```bash
+$ mkdir HelloWorld
+$ cd HelloWorld
+$ mkdir -p src/{main,test}/scala
+$ mkdir project target
+```
+
+После запуска этих команд, по запросу `find .` вы должны увидеть такой результат:
+
+```bash
+$ find .
+.
+./project
+./src
+./src/main
+./src/main/scala
+./src/test
+./src/test/scala
+./target
+```
+
+Если вы это видите, отлично, вы готовы для следующего шага.
+
+> Существуют и другие способы создания файлов и каталогов для проекта sbt.
+> Один из способов - использовать команду sbt new, которая [задокументирована на scala-sbt.org](https://www.scala-sbt.org/1.x/docs/Hello.html).
+> Этот подход здесь не показан, поскольку некоторые из создаваемых им файлов более сложны, чем необходимо для такого введения.
+
+### Создание первого файла build.sbt
+
+На данный момент нужны еще две вещи для запуска проекта "Hello, world":
+
+- файл _build.sbt_
+- файл _Hello.scala_
+
+Для такого небольшого проекта файлу _build.sbt_ нужна только запись `scalaVersion`, но мы добавим три строки:
+
+```scala
+name := "HelloWorld"
+version := "0.1"
+scalaVersion := "{{ site.scala-3-version }}"
+```
+
+Поскольку проекты sbt используют стандартную структуру каталогов, sbt может найти все, что ему нужно.
+
+Теперь осталось просто добавить небольшую программу "Hello, world".
+
+### Программа "Hello, world"
+
+В больших проектах все файлы исходного кода будут находиться в каталогах _src/main/scala_ и _src/test/scala_,
+но для небольшого примера, подобного этому, можно поместить файл исходного кода в корневой каталог.
+Поэтому создайте файл с именем _HelloWorld.scala_ в корневом каталоге со следующим содержимым:
+
+```scala
+@main def helloWorld = println("Hello, world")
+```
+
+Этот код определяет "main" метод, который печатает `"Hello, world"` при запуске.
+
+Теперь используйте команду `sbt run` для компиляции и запуска проекта:
+
+```bash
+$ sbt run
+
+[info] welcome to sbt
+[info] loading settings for project ...
+[info] loading project definition
+[info] loading settings for project root from build.sbt ...
+[info] Compiling 1 Scala source ...
+[info] running helloWorld
+Hello, world
+[success] Total time: 4 s
+```
+
+При первом запуске `sbt` загружает все, что ему нужно (это может занять несколько секунд),
+но после первого раза запуск становится намного быстрее.
+
+Кроме того, после выполнения первого шага можно обнаружить, что гораздо быстрее запускать sbt в интерактивном режиме.
+Для этого вначале отдельно запустите команду `sbt`:
+
+```bash
+$ sbt
+
+[info] welcome to sbt
+[info] loading settings for project ...
+[info] loading project definition ...
+[info] loading settings for project root from build.sbt ...
+[info] sbt server started at
+ local:///${HOME}/.sbt/1.0/server/7d26bae822c36a31071c/sock
+sbt:hello-world> _
+```
+
+Затем внутри этой оболочки выполните команду `run`:
+
+```
+sbt:hello-world> run
+
+[info] running helloWorld
+Hello, world
+[success] Total time: 0 s
+```
+
+Так намного быстрее.
+
+Если вы наберете `help` в командной строке sbt, то увидите список других команд, доступных для запуска.
+Введите `exit` (или нажмите `CTRL-D`), чтобы выйти из оболочки sbt.
+
+### Использование шаблонов проектов
+
+Ручное создание структуры проекта может быть утомительным. К счастью, sbt может создать структуру на основе шаблона.
+
+Чтобы создать проект Scala 3 из шаблона, выполните следующую команду в оболочке:
+
+```
+$ sbt new scala/scala3.g8
+```
+
+Sbt загрузит шаблон, задаст несколько вопросов и создаст файлы проекта в подкаталоге:
+
+```
+$ tree scala-3-project-template
+scala-3-project-template
+├── build.sbt
+├── project
+│ └── build.properties
+├── README.md
+└── src
+ ├── main
+ │ └── scala
+ │ └── Main.scala
+ └── test
+ └── scala
+ └── Test1.scala
+```
+
+> Если вы хотите создать проект Scala 3, который кросс-компилируется со Scala 2, используйте шаблон `scala/scala3-cross.g8`:
+>
+> ```
+> $ sbt new scala/scala3-cross.g8
+> ```
+
+Узнайте больше о `sbt new` и шаблонах проектов в [документации sbt](https://www.scala-sbt.org/1.x/docs/sbt-new-and-Templates.html#sbt+new+and+Templates).
+
+### Другие инструменты сборки для Scala
+
+Хотя sbt широко используется, есть и другие инструменты, которые можно использовать для создания проектов Scala:
+
+- [Ant](https://ant.apache.org/)
+- [Gradle](https://gradle.org/)
+- [Maven](https://maven.apache.org/)
+- [Mill](https://com-lihaoyi.github.io/mill/)
+
+#### Coursier
+
+[Coursier](https://get-coursier.io/docs/overview) - это "преобразователь зависимостей", похожий по функциям на Maven и Ivy.
+Он написан на Scala с нуля, "охватывает принципы функционального программирования"
+и для быстроты параллельно загружает артефакты.
+sbt использует Coursier для обработки большинства разрешений зависимостей,
+а в качестве инструмента командной строки его можно использовать для простой установки таких инструментов,
+как sbt, Java и Scala, как показано на странице ["С чего начать?"][getting_started].
+
+Этот пример со страницы `launch` показывает, что команда `cs launch` может использоваться для запуска приложений из зависимостей:
+
+```scala
+$ cs launch org.scalameta::scalafmt-cli:2.4.2 -- --help
+scalafmt 2.4.2
+Usage: scalafmt [options] [...]
+
+ -h, --help prints this usage text
+ -v, --version print version
+ more ...
+```
+
+Подробнее см. на странице [запуска Coursier](https://get-coursier.io/docs/cli-launch).
+
+## Использование sbt со ScalaTest
+
+[ScalaTest](https://www.scalatest.org) — одна из основных библиотек тестирования для проектов Scala.
+В этом разделе рассмотрим шаги, необходимые для создания проекта Scala/sbt, использующего ScalaTest.
+
+### 1) Создание структуры каталогов проекта
+
+Как и в предыдущем уроке, создаем структуру каталогов sbt для проекта с именем _HelloScalaTest_ с помощью следующих команд:
+
+```bash
+$ mkdir HelloScalaTest
+$ cd HelloScalaTest
+$ mkdir -p src/{main,test}/scala
+$ mkdir project
+```
+
+### 2) Создание файлов build.properties и build.sbt
+
+Затем создаем файл _build.properties_ в подкаталоге _project/_ проекта с такой строкой:
+
+```text
+sbt.version=1.10.11
+```
+
+Создаем файл _build.sbt_ в корневом каталоге проекта со следующим содержимым:
+
+```scala
+name := "HelloScalaTest"
+version := "0.1"
+scalaVersion := "{{site.scala-3-version}}"
+
+libraryDependencies ++= Seq(
+ "org.scalatest" %% "scalatest" % "3.2.19" % Test
+)
+```
+
+Первые три строки этого файла практически такие же, как и в первом примере.
+Строки `libraryDependencies` сообщают sbt о включении зависимостей (файлов JAR), которые необходимы для добавления ScalaTest.
+
+> Документация по ScalaTest всегда была хорошей, и вы всегда можете найти актуальную информацию о том,
+> как должны выглядеть эти строки, на странице ["Установка ScalaTest"](https://www.scalatest.org/install).
+
+### 3) Создание файла исходного кода Scala
+
+Затем создаем программу Scala, которую можно использовать для демонстрации ScalaTest.
+Сначала создайте каталог в _src/main/scala_ с именем _math_:
+
+```bash
+$ mkdir src/main/scala/math
+ ----
+```
+
+Внутри этого каталога создайте файл _MathUtils.scala_ со следующим содержимым:
+
+```scala
+package math
+
+object MathUtils:
+ def double(i: Int) = i * 2
+```
+
+Этот метод обеспечивает простой способ демонстрации ScalaTest.
+
+### 4) Создание первых тестов ScalaTest
+
+ScalaTest очень гибок и предлагает несколько различных способов написания тестов.
+Простой способ начать работу — написать тесты с помощью `AnyFunSuite`.
+Для начала создайте каталог с именем _math_ в каталоге _src/test/scala_:
+
+```bash
+$ mkdir src/test/scala/math
+ ----
+```
+
+Затем создайте в этом каталоге файл с именем _MathUtilsTests.scala_ со следующим содержимым:
+
+```scala
+package math
+
+import org.scalatest.funsuite.AnyFunSuite
+
+class MathUtilsTests extends AnyFunSuite:
+
+ // test 1
+ test("'double' should handle 0") {
+ val result = MathUtils.double(0)
+ assert(result == 0)
+ }
+
+ // test 2
+ test("'double' should handle 1") {
+ val result = MathUtils.double(1)
+ assert(result == 2)
+ }
+
+ test("test with Int.MaxValue") (pending)
+
+end MathUtilsTests
+```
+
+Этот код демонстрирует `AnyFunSuite` подход.
+Несколько важных моментов:
+
+- тестовый класс должен расширять `AnyFunSuite`
+- тесты создаются, задавая каждому `test` уникальное имя
+- в конце каждого теста необходимо вызвать `assert`, чтобы проверить, выполнено ли условие
+- когда вы знаете, что хотите написать тест, но не хотите писать его прямо сейчас,
+ создайте тест как "pending" (ожидающий) с показанным синтаксисом
+
+Подобное использование ScalaTest напоминает JUnit, так что если вы переходите с Java на Scala, это должно показаться знакомым.
+
+Теперь можно запустить эти тесты с помощью команды `sbt test`.
+Пропуская первые несколько строк вывода, результат выглядит следующим образом:
+
+```
+sbt:HelloScalaTest> test
+
+[info] Compiling 1 Scala source ...
+[info] MathUtilsTests:
+[info] - 'double' should handle 0
+[info] - 'double' should handle 1
+[info] - test with Int.MaxValue (pending)
+[info] Total number of tests run: 2
+[info] Suites: completed 1, aborted 0
+[info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 1
+[info] All tests passed.
+[success] Total time: 1 s
+```
+
+Если все работает хорошо, вы увидите примерно такой результат.
+Добро пожаловать в мир тестирования приложений Scala с помощью sbt и ScalaTest.
+
+### Поддержка различных видов тестов
+
+В этом примере демонстрируется стиль тестирования, аналогичный стилю xUnit _Test-Driven Development_ (TDD),
+с некоторыми преимуществами _Behavior-Driven Development_ (BDD).
+
+Как уже упоминалось, ScalaTest является гибким, и вы также можете писать тесты, используя другие стили,
+такие как стиль, похожий на RSpec Ruby.
+Вы также можете использовать моканные объекты, тестирование на основе свойств
+и использовать ScalaTest для тестирования кода Scala.js.
+
+Дополнительные сведения о различных доступных стилях тестирования
+см. в Руководстве пользователя на [веб-сайте ScalaTest](https://www.scalatest.org).
+
+## Что дальше?
+
+Дополнительные сведения о sbt и ScalaTest см. в следующих ресурсах:
+
+- [The sbt documentation](https://www.scala-sbt.org/1.x/docs/)
+- [The ScalaTest website](https://www.scalatest.org/)
+
+[getting_started]: {{ site.baseurl }}/ru/getting-started/install-scala.html
diff --git a/_ru/scala3/book/tools-worksheets.md b/_ru/scala3/book/tools-worksheets.md
new file mode 100644
index 0000000000..5409c5ad40
--- /dev/null
+++ b/_ru/scala3/book/tools-worksheets.md
@@ -0,0 +1,63 @@
+---
+layout: multipage-overview
+title: Рабочие листы
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе рассматриваются рабочие листы — альтернатива проектам Scala.
+language: ru
+num: 71
+previous-page: tools-sbt
+next-page: interacting-with-java
+---
+
+Worksheet - это файл Scala, который вычисляется при сохранении,
+и результат каждого выражения отображается в столбце справа от программы.
+Рабочие листы похожи на [сеанс REPL][REPL session] на стероидах
+и имеют поддержку редактора 1-го класса: завершение, гиперссылки, интерактивные ошибки при вводе и т.д.
+Рабочие листы используют расширение `.worksheet.sc`.
+
+Далее покажем, как использовать рабочие листы в IntelliJ и в VS Code (с расширением Metals).
+
+1. Откройте проект Scala или создайте его:
+ - чтобы создать проект в IntelliJ, выберите "File" -> "New" -> "Project...",
+ выберите "Scala" в левой колонке и нажмите "Далее", чтобы задать название проекта и каталог.
+ - чтобы создать проект в VS Code, выполните команду "Metals: New Scala project",
+ выберите начальный `scala/scala3.g8`, задайте местоположение проекта,
+ откройте его в новом окне VS Code и импортируйте сборку.
+1. Создайте файл с именем `hello.worksheet.sc` в каталоге `src/main/scala/`.
+ - в IntelliJ щелкните правой кнопкой мыши на каталоге `src/main/scala/` и выберите "New", а затем "File".
+ - в VS Code щелкните правой кнопкой мыши на каталоге `src/main/scala/` и выберите "New File".
+1. Вставьте следующее содержимое в редактор:
+
+ ```
+ println("Hello, world!")
+
+ val x = 1
+ x + x
+ ```
+
+1. Запустите worksheet:
+
+ - в IntelliJ щелкните зеленую стрелку в верхней части редактора, чтобы запустить worksheet.
+ - в VS Code сохраните файл.
+
+ Вы должны увидеть результат выполнения каждой строки на правой панели (IntelliJ) или в виде комментариев (VS Code).
+
+
+
+Рабочий лист, выполненный в IntelliJ.
+
+
+
+Рабочий лист, выполненный в VS Code (с расширением Metals).
+
+Обратите внимание, что worksheet будет использовать версию Scala,
+определенную проектом (обычно задается ключом `scalaVersion` в файле `build.sbt`).
+
+Также обратите внимание, что worksheet не имеют [точек входа в программу][program entry point].
+Вместо этого операторы и выражения верхнего уровня оцениваются сверху вниз.
+
+[REPL session]: {{ site.baseurl }}/ru/scala3/book/taste-repl.html
+[program entry point]: {{ site.baseurl }}/ru/scala3/book/methods-main-methods.html
diff --git a/_ru/scala3/book/types-adts-gadts.md b/_ru/scala3/book/types-adts-gadts.md
new file mode 100644
index 0000000000..50091980e3
--- /dev/null
+++ b/_ru/scala3/book/types-adts-gadts.md
@@ -0,0 +1,223 @@
+---
+layout: multipage-overview
+title: Алгебраические типы данных
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлены и демонстрируются алгебраические типы данных (ADT) в Scala 3.
+language: ru
+num: 53
+previous-page: types-union
+next-page: types-variance
+versionSpecific: true
+---
+
+Только в Scala 3
+
+Алгебраические типы данных (ADT) могут быть созданы с помощью конструкции `enum`,
+поэтому кратко рассмотрим перечисления, прежде чем рассматривать ADT.
+
+## Перечисления
+
+_Перечисление_ используется для определения типа, состоящего из набора именованных значений:
+
+```scala
+enum Color:
+ case Red, Green, Blue
+```
+
+который можно рассматривать как сокращение для:
+
+```scala
+enum Color:
+ case Red extends Color
+ case Green extends Color
+ case Blue extends Color
+```
+
+#### Параметры
+
+Перечисления могут быть параметризованы:
+
+```scala
+enum Color(val rgb: Int):
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+```
+
+Таким образом, каждый из различных вариантов содержит параметр `rgb`,
+которому присваивается соответствующее значение:
+
+```scala
+println(Color.Green.rgb) // выводит 65280
+```
+
+#### Пользовательские определения
+
+Перечисления также могут содержать пользовательские определения:
+
+```scala
+enum Planet(mass: Double, radius: Double):
+
+ private final val G = 6.67300E-11
+ def surfaceGravity = G * mass / (radius * radius)
+ def surfaceWeight(otherMass: Double) = otherMass * surfaceGravity
+
+ case Mercury extends Planet(3.303e+23, 2.4397e6)
+ case Venus extends Planet(4.869e+24, 6.0518e6)
+ case Earth extends Planet(5.976e+24, 6.37814e6)
+ // остальные 5 или 6 планет ...
+```
+
+Подобно классам и `case` классам, вы также можете определить сопутствующий объект для перечисления:
+
+```scala
+object Planet:
+ def main(args: Array[String]) =
+ val earthWeight = args(0).toDouble
+ val mass = earthWeight / Earth.surfaceGravity
+ for (p <- values)
+ println(s"Your weight on $p is ${p.surfaceWeight(mass)}")
+```
+
+## Алгебраические типы данных (ADTs)
+
+Концепция `enum` является достаточно общей,
+чтобы также поддерживать _алгебраические типы данных_ (ADT) и их обобщенную версию (GADT).
+Вот пример, показывающий, как тип `Option` может быть представлен в виде АТД:
+
+```scala
+enum Option[+T]:
+ case Some(x: T)
+ case None
+```
+
+В этом примере создается перечисление `Option` с параметром ковариантного типа `T`,
+состоящим из двух вариантов `Some` и `None`.
+`Some` _параметризуется_ значением параметра `x`;
+это сокращение для написания `case` класса, расширяющего `Option`.
+Поскольку `None` не параметризуется, то он считается обычным enum значением.
+
+Предложения `extends`, которые были опущены в предыдущем примере, также могут быть указаны явно:
+
+```scala
+enum Option[+T]:
+ case Some(x: T) extends Option[T]
+ case None extends Option[Nothing]
+```
+
+Как и в случае с обычным `enum` значениями, варианты enum определяются в его сопутствующем объекте,
+поэтому они называются `Option.Some` и `Option.None` (если только определения не «вытягиваются» при импорте):
+
+```scala
+scala> Option.Some("hello")
+val res1: t2.Option[String] = Some(hello)
+
+scala> Option.None
+val res2: t2.Option[Nothing] = None
+```
+
+Как и в других случаях использования перечисления, АТД могут определять дополнительные методы.
+Например, вот снова `Option`, с методом `isDefined` и конструктором `Option(...)` в сопутствующем объекте:
+
+```scala
+enum Option[+T]:
+ case Some(x: T)
+ case None
+
+ def isDefined: Boolean = this match
+ case None => false
+ case Some(_) => true
+
+object Option:
+ def apply[T >: Null](x: T): Option[T] =
+ if (x == null) None else Some(x)
+```
+
+Перечисления и АТД используют одну и ту же синтаксическую конструкцию,
+поэтому их можно рассматривать просто как два конца спектра, и вполне допустимо создавать гибриды.
+Например, приведенный ниже код реализует `Color` либо с тремя значениями перечисления,
+либо с параметризованным вариантом, принимающим значение RGB:
+
+```scala
+enum Color(val rgb: Int):
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+ case Mix(mix: Int) extends Color(mix)
+```
+
+#### Рекурсивные перечисления
+
+До сих пор все перечисления, которые мы определяли, состояли из различных вариантов значений или case классов.
+Перечисления также могут быть рекурсивными, как показано в приведенном ниже примере кодирования натуральных чисел:
+
+```scala
+enum Nat:
+ case Zero
+ case Succ(n: Nat)
+```
+
+Например, значение `Succ(Succ(Zero))` представляет число `2` в унарной кодировке.
+Списки могут быть определены похожим образом:
+
+```scala
+enum List[+A]:
+ case Nil
+ case Cons(head: A, tail: List[A])
+```
+
+## Обобщенные алгебраические типы данных (GADT)
+
+Приведенная выше нотация для перечислений очень краткая
+и служит идеальной отправной точкой для моделирования ваших типов данных.
+Поскольку мы всегда можем быть более подробными, то можем выразить гораздо более мощные типы:
+обобщенные алгебраические типы данных (GADT).
+
+Вот пример GADT, в котором параметр типа (`T`) указывает на тип содержимого, хранящегося в `Box`:
+
+```scala
+enum Box[T](contents: T):
+ case IntBox(n: Int) extends Box[Int](n)
+ case BoolBox(b: Boolean) extends Box[Boolean](b)
+```
+
+Сопоставление с образцом с конкретным конструктором (`IntBox` или `BoolBox`) восстанавливает информацию о типе:
+
+```scala
+def extract[T](b: Box[T]): T = b match
+ case IntBox(n) => n + 1
+ case BoolBox(b) => !b
+```
+
+Безопасно возвращать `Int` в первом случае, так как мы знаем из сопоставления с образцом, что ввод был `IntBox`.
+
+## Дешугаризация перечислений
+
+_Концептуально_ перечисления можно рассматривать как определение запечатанного класса вместе с сопутствующим ему объектом.
+Давайте посмотрим на дешугаризацию нашего перечисления `Color`:
+
+```scala
+sealed abstract class Color(val rgb: Int) extends scala.reflect.Enum
+object Color:
+ case object Red extends Color(0xFF0000) { def ordinal = 0 }
+ case object Green extends Color(0x00FF00) { def ordinal = 1 }
+ case object Blue extends Color(0x0000FF) { def ordinal = 2 }
+ case class Mix(mix: Int) extends Color(mix) { def ordinal = 3 }
+
+ def fromOrdinal(ordinal: Int): Color = ordinal match
+ case 0 => Red
+ case 1 => Green
+ case 2 => Blue
+ case _ => throw new NoSuchElementException(ordinal.toString)
+```
+
+Заметьте, что вышеописанная дешугаризация упрощена, и мы намеренно опускаем [некоторые детали][desugar-enums].
+
+В то время как перечисления можно кодировать вручную с помощью других конструкций,
+использование перечислений является более кратким,
+а также включает несколько дополнительных утилит (таких, как метод `fromOrdinal`).
+
+[desugar-enums]: {{ site.scala3ref }}/enums/desugarEnums.html
diff --git a/_ru/scala3/book/types-dependent-function.md b/_ru/scala3/book/types-dependent-function.md
new file mode 100644
index 0000000000..88750e2ec5
--- /dev/null
+++ b/_ru/scala3/book/types-dependent-function.md
@@ -0,0 +1,179 @@
+---
+layout: multipage-overview
+title: Зависимые типы функций
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлены и демонстрируются зависимые типы функций в Scala 3.
+language: ru
+num: 57
+previous-page: types-structural
+next-page: types-others
+versionSpecific: true
+---
+
+_Зависимый тип функции_ (_dependent function type_) описывает типы функций,
+где тип результата может зависеть от значений параметров функции.
+Концепция зависимых типов и типов зависимых функций является более продвинутой,
+и обычно с ней сталкиваются только при разработке собственных библиотек или использовании расширенных библиотек.
+
+## Зависимые типы методов
+
+Рассмотрим следующий пример гетерогенной базы данных, в которой могут храниться значения разных типов.
+Ключ содержит информацию о типе соответствующего значения:
+
+```scala
+trait Key { type Value }
+
+trait DB {
+ def get(k: Key): Option[k.Value] // зависимый метод
+}
+```
+
+Получив ключ, метод `get` предоставляет доступ к карте и потенциально возвращает сохраненное значение типа `k.Value`.
+Мы можем прочитать этот _path-dependent type_ как:
+"в зависимости от конкретного типа аргумента `k` возвращается соответствующее значение".
+
+Например, у нас могут быть следующие ключи:
+
+```scala
+object Name extends Key { type Value = String }
+object Age extends Key { type Value = Int }
+```
+
+Вызовы метода `get` теперь будут возвращать такие типы:
+
+```scala
+val db: DB = ...
+val res1: Option[String] = db.get(Name)
+val res2: Option[Int] = db.get(Age)
+```
+
+Вызов метода `db.get(Name)` возвращает значение типа `Option[String]`,
+а вызов `db.get(Age)` возвращает значение типа `Option[Int]`.
+Тип возвращаемого значения _зависит_ от конкретного типа аргумента, переданного для `get` — отсюда и название _dependent type_.
+
+## Зависимые типы функций
+
+Как видно выше, в Scala 2 уже была поддержка зависимых типов методов.
+Однако создание значений типа `DB` довольно громоздко:
+
+```scala
+// создание пользователя DB
+def user(db: DB): Unit =
+ db.get(Name) ... db.get(Age)
+
+// создание экземпляра DB и передача его `user`
+user(new DB {
+ def get(k: Key): Option[k.Value] = ... // реализация DB
+})
+```
+
+Необходимо вручную создать анонимный внутренний класс `DB`, реализующий метод `get`.
+Для кода, основанного на создании множества различных экземпляров `DB`, это очень утомительно.
+
+Трейт `DB` имеет только один абстрактный метод `get`.
+Было бы неплохо использовать в этом месте лямбда-синтаксис?
+
+```scala
+user { k =>
+ ... // реализация DB
+}
+```
+
+На самом деле, в Scala 3 теперь это возможно! Можно определить `DB` как _зависимый тип функции_:
+
+```scala
+type DB = (k: Key) => Option[k.Value]
+// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// зависимый тип функции
+```
+
+Учитывая это определение `DB`, можно использовать приведенный выше вызов `user`.
+
+Подробнее о внутреннем устройстве зависимых типов функций можно прочитать в [справочной документации][ref].
+
+## Практический пример: числовые выражения
+
+Предположим, что необходимо определить модуль, который абстрагируется от внутреннего представления чисел.
+Это может быть полезно, например, для реализации библиотек для автоматического дифференцирования.
+
+Начнем с определения модуля для чисел:
+
+```scala
+trait Nums:
+ // тип Num оставлен абстрактным
+ type Num
+
+ // некоторые операции над числами
+ def lit(d: Double): Num
+ def add(l: Num, r: Num): Num
+ def mul(l: Num, r: Num): Num
+```
+
+> Здесь опускается конкретная реализация `Nums`, но в качестве упражнения можно реализовать `Nums`,
+> назначив тип `Num = Double` и реализуя соответствующие методы.
+
+Программа, использующая числовую абстракцию, теперь имеет следующий тип:
+
+```scala
+type Prog = (n: Nums) => n.Num => n.Num
+
+val ex: Prog = nums => x => nums.add(nums.lit(0.8), x)
+```
+
+Тип функции, которая вычисляет производную, наподобие `ex`:
+
+```scala
+def derivative(input: Prog): Double
+```
+
+Учитывая удобство зависимых типов функций, вызов этой функции в разных программах прост:
+
+```scala
+derivative { nums => x => x }
+derivative { nums => x => nums.add(nums.lit(0.8), x) }
+// ...
+```
+
+Напомним, что та же программа в приведенной выше кодировке будет выглядеть так:
+
+```scala
+derivative(new Prog {
+ def apply(nums: Nums)(x: nums.Num): nums.Num = x
+})
+derivative(new Prog {
+ def apply(nums: Nums)(x: nums.Num): nums.Num = nums.add(nums.lit(0.8), x)
+})
+// ...
+```
+
+#### Комбинация с контекстными функциями
+
+Комбинация методов расширения, [контекстных функций][ctx-fun] и зависимых функций обеспечивает мощный инструмент для разработчиков библиотек.
+Например, мы можем уточнить нашу библиотеку, как указано выше, следующим образом:
+
+```scala
+trait NumsDSL extends Nums:
+ extension (x: Num)
+ def +(y: Num) = add(x, y)
+ def *(y: Num) = mul(x, y)
+
+def const(d: Double)(using n: Nums): n.Num = n.lit(d)
+
+type Prog = (n: NumsDSL) ?=> n.Num => n.Num
+// ^^^
+// prog теперь - контекстная функция,
+// которая неявно предполагает NumsDSL в контексте вызова
+
+def derivative(input: Prog): Double = ...
+
+// теперь нам не нужно упоминать Nums в приведенных ниже примерах
+derivative { x => const(1.0) + x }
+derivative { x => x * x + const(2.0) }
+// ...
+```
+
+[ref]: {{ site.scala3ref }}/new-types/dependent-function-types.html
+[ctx-fun]: {{ site.scala3ref }}/contextual/context-functions.html
diff --git a/_ru/scala3/book/types-generics.md b/_ru/scala3/book/types-generics.md
new file mode 100644
index 0000000000..5ece10b356
--- /dev/null
+++ b/_ru/scala3/book/types-generics.md
@@ -0,0 +1,103 @@
+---
+layout: multipage-overview
+title: Параметризованные типы
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлены параметризованные типы в Scala 3.
+language: ru
+num: 50
+previous-page: types-inferred
+next-page: types-intersection
+---
+
+Универсальные (_generic_) классы (или trait-ы) принимают тип в качестве _параметра_ в квадратных скобках `[...]`.
+Для обозначения параметров типа согласно конвенции Scala используется одна заглавная буква (например, `A`).
+Затем этот тип можно использовать внутри класса по мере необходимости
+для параметров экземпляра метода или для возвращаемых типов:
+
+{% tabs stack class=tabs-scala-version %}
+
+{% tab 'Scala 2' %}
+
+```scala
+// здесь мы объявляем параметр типа A
+// v
+class Stack[A] {
+ private var elements: List[A] = Nil
+ // ^
+ // здесь мы ссылаемся на этот тип
+ // v
+ def push(x: A): Unit =
+ elements = elements.prepended(x)
+ def peek: A = elements.head
+ def pop(): A = {
+ val currentTop = peek
+ elements = elements.tail
+ currentTop
+ }
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+// здесь мы объявляем параметр типа A
+// v
+class Stack[A]:
+ private var elements: List[A] = Nil
+ // ^
+ // здесь мы ссылаемся на этот тип
+ // v
+ def push(x: A): Unit =
+ elements = elements.prepended(x)
+ def peek: A = elements.head
+ def pop(): A =
+ val currentTop = peek
+ elements = elements.tail
+ currentTop
+```
+
+{% endtab %}
+{% endtabs %}
+
+Эта реализация класса `Stack` принимает любой тип в качестве параметра.
+Прелесть параметризованных типов состоит в том,
+что теперь можно создавать `Stack[Int]`, `Stack[String]` и т.д.,
+что позволяет повторно использовать реализацию `Stack` для произвольных типов элементов.
+
+Пример создания и использования `Stack[Int]`:
+
+{% tabs stack-usage class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+val stack = new Stack[Int]
+stack.push(1)
+stack.push(2)
+println(stack.pop()) // выводит 2
+println(stack.pop()) // выводит 1
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+val stack = Stack[Int]
+stack.push(1)
+stack.push(2)
+println(stack.pop()) // выводит 2
+println(stack.pop()) // выводит 1
+```
+
+{% endtab %}
+{% endtabs %}
+
+> Подробности о том, как выразить вариантность с помощью универсальных типов,
+> см. в разделе ["Вариантность"][variance].
+
+[variance]: {% link _overviews/scala3-book/types-variance.md %}
diff --git a/_ru/scala3/book/types-inferred.md b/_ru/scala3/book/types-inferred.md
new file mode 100644
index 0000000000..cadedc1ca0
--- /dev/null
+++ b/_ru/scala3/book/types-inferred.md
@@ -0,0 +1,65 @@
+---
+layout: multipage-overview
+title: Определение типов
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлены и демонстрируются выводимые типы в Scala 3.
+language: ru
+num: 49
+previous-page: types-introduction
+next-page: types-generics
+---
+
+Как и в других статически типизированных языках программирования,
+в Scala тип можно _объявить_ при создании новой переменной:
+
+{% tabs xy %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val x: Int = 1
+val y: Double = 1
+```
+
+{% endtab %}
+{% endtabs %}
+
+В этих примерах типы _явно_ объявлены как `Int` и `Double` соответственно.
+Однако в Scala обычно необязательно указывать тип при объявлении переменной:
+
+{% tabs abm %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val a = 1
+val b = List(1, 2, 3)
+val m = Map(1 -> "one", 2 -> "two")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Когда вы это сделаете, Scala сама _выведет_ типы, как показано в следующей сессии REPL:
+
+{% tabs abm2 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+scala> val a = 1
+val a: Int = 1
+
+scala> val b = List(1, 2, 3)
+val b: List[Int] = List(1, 2, 3)
+
+scala> val m = Map(1 -> "one", 2 -> "two")
+val m: Map[Int, String] = Map(1 -> one, 2 -> two)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Действительно, большинство переменных определяются без указания типа,
+и способность Scala автоматически определять его — это одна из особенностей,
+которая делает Scala _похожим_ на язык с динамической типизацией.
diff --git a/_ru/scala3/book/types-intersection.md b/_ru/scala3/book/types-intersection.md
new file mode 100644
index 0000000000..759855824b
--- /dev/null
+++ b/_ru/scala3/book/types-intersection.md
@@ -0,0 +1,76 @@
+---
+layout: multipage-overview
+title: Пересечение типов
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлены пересечение типов в Scala 3.
+language: ru
+num: 51
+previous-page: types-generics
+next-page: types-union
+---
+
+Только в Scala 3
+
+Используемый для типов оператор `&` создает так называемый _тип пересечения_ (_intersection type_).
+Тип `A & B` представляет собой значения, которые **одновременно** относятся как к типу `A`, так и к типу `B`.
+Например, в следующем примере используется тип пересечения `Resettable & Growable[String]`:
+
+{% tabs intersection-reset-grow %}
+
+{% tab 'Только в Scala 3' %}
+
+```scala
+trait Resettable:
+ def reset(): Unit
+
+trait Growable[A]:
+ def add(a: A): Unit
+
+def f(x: Resettable & Growable[String]): Unit =
+ x.reset()
+ x.add("first")
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+В методе `f` в этом примере параметр `x` должен быть _одновременно_ как `Resettable`, так и `Growable[String]`.
+
+Все _члены_ типа пересечения `A & B` являются типом `A` и типом `B`.
+Следовательно, как показано, для `Resettable & Growable[String]` доступны методы `reset` и `add`.
+
+Пересечение типов может быть полезно для _структурного_ описания требований.
+В примере выше для `f` мы прямо заявляем, что нас устраивает любое значение для `x`,
+если оно является подтипом как `Resettable`, так и `Growable`.
+**Нет** необходимости создавать _номинальный_ вспомогательный trait, подобный следующему:
+
+{% tabs normal-trait class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala
+trait Both[A] extends Resettable with Growable[A]
+def f(x: Both[String]): Unit
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' %}
+
+```scala
+trait Both[A] extends Resettable, Growable[A]
+def f(x: Both[String]): Unit
+```
+
+{% endtab %}
+{% endtabs %}
+
+Существует важное различие между двумя вариантами определения `f`:
+в то время как оба позволяют вызывать `f` с экземплярами `Both`,
+только первый позволяет передавать экземпляры,
+которые являются подтипами `Resettable` и `Growable[String]`, _но не_ `Both[String]`.
+
+> Обратите внимание, что `&` _коммутативно_: `A & B` имеет тот же тип, что и `B & A`.
diff --git a/_ru/scala3/book/types-introduction.md b/_ru/scala3/book/types-introduction.md
new file mode 100644
index 0000000000..65ecf50ebf
--- /dev/null
+++ b/_ru/scala3/book/types-introduction.md
@@ -0,0 +1,68 @@
+---
+layout: multipage-overview
+title: Типы и система типов
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: В этой главе представлено введение в типы и систему типов Scala 3.
+language: ru
+num: 48
+previous-page: fp-summary
+next-page: types-inferred
+---
+
+Scala — уникальный язык, поскольку он статически типизирован, но часто кажется гибким и динамичным.
+Например, благодаря выводу типов можно писать код без явного указания типов переменных:
+
+{% tabs hi %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val a = 1
+val b = 2.0
+val c = "Hi!"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Это делает код динамически типизированным.
+А благодаря новым функциям в Scala 3, таким как [объединение типов][union-types],
+также можно писать код, подобный следующему,
+который кратко выражает, какие значения ожидаются в качестве аргументов и какие типы возвращаются:
+
+{% tabs union-example %}
+{% tab 'Только в Scala 3' %}
+
+```scala
+def isTruthy(a: Boolean | Int | String): Boolean = ???
+def dogCatOrWhatever(): Dog | Plant | Car | Sun = ???
+```
+
+{% endtab %}
+{% endtabs %}
+
+Как видно из примера, при использовании объединения типы необязательно должны иметь общую иерархию,
+и их по-прежнему можно принимать в качестве аргументов или возвращать из метода.
+
+При разработке приложений такие функции, как вывод типов,
+используются каждый день, а generics - каждую неделю.
+При чтении Scaladoc для классов и методов, также необходимо иметь некоторое представление о _ковариантности_.
+Использование типов может быть относительно простым,
+а также обеспечивает большую выразительность, гибкость и контроль для разработчиков библиотек.
+
+## Преимущества типов
+
+Языки программирования со статической типизацией предлагают ряд преимуществ, в том числе:
+
+- помощь IDE в обеспечении надежной поддержки
+- устранение многих классов потенциальных ошибок во время компиляции
+- помощь в рефакторинге
+- предоставление надежной документации, которая не может быть нерелевантной, поскольку проверена на тип
+
+## Знакомство с особенностями системы типов в Scala
+
+Учитывая это краткое введение, в следующих разделах представлен обзор особенностей системы типов в Scala.
+
+[union-types]: {% link _overviews/scala3-book/types-union.md %}
diff --git a/_ru/scala3/book/types-opaque-types.md b/_ru/scala3/book/types-opaque-types.md
new file mode 100644
index 0000000000..f6942738a9
--- /dev/null
+++ b/_ru/scala3/book/types-opaque-types.md
@@ -0,0 +1,178 @@
+---
+layout: multipage-overview
+title: Непрозрачные типы
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлены и демонстрируются непрозрачные типы в Scala 3.
+language: ru
+num: 55
+previous-page: types-variance
+next-page: types-structural
+versionSpecific: true
+---
+
+_Непрозрачные псевдонимы типов_ (_opaque type aliases_) обеспечивают абстракцию типов без каких-либо **накладных расходов**.
+
+В Scala 2 аналогичный результат можно получить с помощью [классов значений][value-classes].
+
+## Накладные расходы на абстракцию
+
+Предположим, что необходимо определить модуль,
+предлагающий арифметические операции над числами, которые представлены их логарифмами.
+Это может быть полезно для повышения точности, когда числовые значения очень большие или близкие к нулю.
+
+Поскольку важно отличать "обычные" `Double` от чисел, хранящихся в виде их логарифмов, введем класс `Logarithm`:
+
+```scala
+class Logarithm(protected val underlying: Double):
+ def toDouble: Double = math.exp(underlying)
+ def + (that: Logarithm): Logarithm =
+ // здесь используется метод apply сопутствующего объекта
+ Logarithm(this.toDouble + that.toDouble)
+ def * (that: Logarithm): Logarithm =
+ new Logarithm(this.underlying + that.underlying)
+
+object Logarithm:
+ def apply(d: Double): Logarithm = new Logarithm(math.log(d))
+```
+
+Метод `apply` сопутствующего объекта позволяет создавать значения типа `Logarithm`,
+которые можно использовать следующим образом:
+
+```scala
+val l2 = Logarithm(2.0)
+val l3 = Logarithm(3.0)
+println((l2 * l3).toDouble) // выводит 6.0
+println((l2 + l3).toDouble) // выводит 4.999...
+```
+
+В то время как класс `Logarithm` предлагает хорошую абстракцию для значений `Double`,
+которые хранятся в этой конкретной логарифмической форме,
+это накладывает серьезные накладные расходы на производительность:
+для каждой отдельной математической операции нужно извлекать значение `underlying`,
+а затем снова обернуть его в новый экземпляр `Logarithm`.
+
+## Модульные абстракции
+
+Рассмотрим другой подход к реализации той же библиотеки.
+На этот раз вместо того, чтобы определять `Logarithm` как класс, определяем его с помощью _псевдонима типа_.
+Во-первых, зададим абстрактный интерфейс модуля:
+
+```scala
+trait Logarithms:
+
+ type Logarithm
+
+ // операции на Logarithm
+ def add(x: Logarithm, y: Logarithm): Logarithm
+ def mul(x: Logarithm, y: Logarithm): Logarithm
+
+ // функции конвертации между Double и Logarithm
+ def make(d: Double): Logarithm
+ def extract(x: Logarithm): Double
+
+ // методы расширения, для вызова `add` и `mul` в качестве "методов" на Logarithm
+ extension (x: Logarithm)
+ def toDouble: Double = extract(x)
+ def + (y: Logarithm): Logarithm = add(x, y)
+ def * (y: Logarithm): Logarithm = mul(x, y)
+```
+
+Теперь давайте реализуем этот абстрактный интерфейс, задав тип `Logarithm` равным `Double`:
+
+```scala
+object LogarithmsImpl extends Logarithms:
+
+ type Logarithm = Double
+
+ // операции на Logarithm
+ def add(x: Logarithm, y: Logarithm): Logarithm = make(x.toDouble + y.toDouble)
+ def mul(x: Logarithm, y: Logarithm): Logarithm = x + y
+
+ // функции конвертации между Double и Logarithm
+ def make(d: Double): Logarithm = math.log(d)
+ def extract(x: Logarithm): Double = math.exp(x)
+```
+
+В рамках реализации `LogarithmsImpl` уравнение `Logarithm = Double` позволяет реализовать различные методы.
+
+#### Дырявые абстракции
+
+Однако эта абстракция немного "дырява".
+Мы должны убедиться, что всегда программируем _только_ с абстрактным интерфейсом `Logarithms`
+и никогда не используем `LogarithmsImpl` напрямую.
+Прямое использование `LogarithmsImpl` сделало бы равенство `Logarithm = Double` видимым для пользователя,
+который может случайно использовать `Double` там, где ожидается логарифмическое удвоение.
+Например:
+
+```scala
+import LogarithmsImpl.*
+val l: Logarithm = make(1.0)
+val d: Double = l // проверка типов ДОЗВОЛЯЕТ равенство!
+```
+
+Необходимость разделения модуля на абстрактный интерфейс и реализацию может быть полезной,
+но также требует больших усилий, чтобы просто скрыть детали реализации `Logarithm`.
+Программирование с использованием абстрактного модуля `Logarithms` может быть очень утомительным
+и часто требует использования дополнительных функций, таких как типы, зависящие от пути, как в следующем примере:
+
+```scala
+def someComputation(L: Logarithms)(init: L.Logarithm): L.Logarithm = ...
+```
+
+#### Накладные расходы упаковки/распаковки
+
+Абстракции типов, такие как `type Logarithm`, [стираются](https://www.scala-lang.org/files/archive/spec/2.13/03-types.html#type-erasure)
+в соответствии с их привязкой (`Any` - в нашем случае).
+То есть, хотя нам не нужно вручную переносить и разворачивать значение `Double`,
+все равно будут некоторые накладные расходы, связанные с упаковкой примитивного типа `Double`.
+
+## Непрозрачные типы
+
+Вместо того чтобы вручную разбивать компонент `Logarithms` на абстрактную часть и на конкретную реализацию,
+можно просто использовать opaque типы для достижения аналогичного эффекта:
+
+```scala
+object Logarithms:
+//vvvvvv это важное различие!
+ opaque type Logarithm = Double
+
+ object Logarithm:
+ def apply(d: Double): Logarithm = math.log(d)
+
+ extension (x: Logarithm)
+ def toDouble: Double = math.exp(x)
+ def + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y))
+ def * (y: Logarithm): Logarithm = x + y
+```
+
+Тот факт, что `Logarithm` совпадает с `Double`, известен только в области, где он определен,
+которая в приведенном выше примере соответствует объекту `Logarithms`.
+Равенство `Logarithm = Double` может использоваться для реализации методов (например, `*` и `toDouble`).
+
+Однако вне модуля тип `Logarithm` полностью инкапсулирован или «непрозрачен».
+Для пользователей `Logarithm`-а невозможно обнаружить, что `Logarithm` на самом деле реализован как `Double`:
+
+```scala
+import Logarithms.*
+val log2 = Logarithm(2.0)
+val log3 = Logarithm(3.0)
+println((log2 * log3).toDouble) // выводит 6.0
+println((log2 + log3).toDouble) // выводит 4.999...
+
+val d: Double = log2 // ERROR: Found Logarithm required Double
+```
+
+Несмотря на то, что мы абстрагировались от `Logarithm`, абстракция предоставляется бесплатно:
+поскольку существует только одна реализация, во время выполнения не будет накладных расходов
+на упаковку для примитивных типов, таких как `Double`.
+
+### Обзор непрозрачных типов
+
+Непрозрачные типы предлагают надежную абстракцию над деталями реализации, не накладывая расходов на производительность.
+Как показано выше, непрозрачные типы удобны в использовании и очень хорошо интегрируются с [функцией методов расширения][extension].
+
+[extension]: {% link _overviews/scala3-book/ca-extension-methods.md %}
+[value-classes]: {% link _overviews/core/value-classes.md %}
diff --git a/_ru/scala3/book/types-others.md b/_ru/scala3/book/types-others.md
new file mode 100644
index 0000000000..131bdd403b
--- /dev/null
+++ b/_ru/scala3/book/types-others.md
@@ -0,0 +1,30 @@
+---
+layout: multipage-overview
+title: Другие типы
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе упоминаются другие расширенные типы в Scala 3.
+language: ru
+num: 58
+previous-page: types-dependent-function
+next-page: ca-contextual-abstractions-intro
+versionSpecific: true
+---
+
+В Scala есть несколько других расширенных типов, которые не показаны в этой книге, в том числе:
+
+- Лямбда-типы
+- Типы соответствия
+- Экзистенциальные типы
+- Типы высшего порядка
+- Синглтон-типы
+- Типы уточнения
+- Вид полиморфизма
+
+Дополнительные сведения об этих типах см. в [Справочной документации Scala 3][reference].
+Для singleton типов см. раздел [literal types](https://scala-lang.org/files/archive/spec/3.4/03-types.html#literal-types)
+спецификации Scala 3, а для уточненных типов — раздел [refined types](https://scala-lang.org/files/archive/spec/3.4/03-types.html).
+
+[reference]: {{ site.scala3ref }}/overview.html
diff --git a/_ru/scala3/book/types-structural.md b/_ru/scala3/book/types-structural.md
new file mode 100644
index 0000000000..103e6db389
--- /dev/null
+++ b/_ru/scala3/book/types-structural.md
@@ -0,0 +1,120 @@
+---
+layout: multipage-overview
+title: Структурные типы
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлены и демонстрируются структурные типы в Scala 3.
+language: ru
+num: 56
+previous-page: types-opaque-types
+next-page: types-dependent-function
+versionSpecific: true
+---
+
+_Scala 2 содержит более слабую форму структурных типов, основанную на Java reflection,
+достигаемую с помощью `import scala.language.reflectiveCalls`_.
+
+## Введение
+
+Некоторые варианты использования, такие как моделирование доступа к базе данных,
+более удобны в динамически типизированных языках, чем в статически типизированных языках.
+С динамически типизированными языками естественно моделировать строку как запись или объект
+и выбирать записи с помощью простых точечных обозначений, например `row.columnName`.
+
+Достижение того же результата в статически типизированном языке требует определения класса для каждой возможной строки,
+возникающей в результате манипуляций с базой данных, включая строки, возникающие в результате `join` и проектирования,
+и настройки схемы для сопоставления между строкой и представляющим ее классом.
+
+Это требует большого количества шаблонов,
+что заставляет разработчиков менять преимущества статической типизации на более простые схемы,
+в которых имена столбцов представляются в виде строк и передаются другим операторам, например `row.select("columnName")`.
+Этот подход лишен преимуществ статической типизации и все еще не так естественен, как динамически типизируемая версия.
+
+Структурные типы (structural types) помогают в ситуациях,
+когда желательно поддерживать простую точечную нотацию в динамических контекстах, не теряя преимуществ статической типизации.
+Они также позволяют разработчикам настраивать, как должны определяться поля и методы.
+
+## Пример
+
+Вот пример структурного типа `Person`:
+
+```scala
+class Record(elems: (String, Any)*) extends Selectable:
+ private val fields = elems.toMap
+ def selectDynamic(name: String): Any = fields(name)
+
+type Person = Record {
+ val name: String
+ val age: Int
+}
+```
+
+Тип `Person` добавляет _уточнение_ (_refinement_) к своему родительскому типу `Record`, которое определяет поля `name` и `age`.
+Говорится, что уточнение носит _структурный_ (_structural_) характер,
+поскольку `name` и `age` не определены в родительском типе.
+Но тем не менее они существуют как члены класса `Person`.
+Например, следующая программа напечатала бы `"Emma is 42 years old."`:
+
+```scala
+val person = Record(
+ "name" -> "Emma",
+ "age" -> 42
+).asInstanceOf[Person]
+
+println(s"${person.name} is ${person.age} years old.")
+```
+
+Родительский тип `Record` в этом примере представляет собой универсальный класс,
+который может в своем аргументе `elems` принимать произвольные записи.
+Этот аргумент - последовательность пар ключей типа `String` и значений типа `Any`.
+Когда создается `Person` как `Record`, необходимо с помощью приведения типов задать,
+что запись определяет правильные поля правильных типов.
+Сама `Record` слишком слабо типизирована, поэтому компилятор не может знать об этом без помощи пользователя.
+На практике связь между структурным типом и его базовым общим представлением, скорее всего,
+будет выполняться на уровне базы данных и, следовательно, не будет беспокоить конечного пользователя.
+
+`Record` расширяет маркер `trait scala.Selectable` и определяет метод `selectDynamic`,
+который сопоставляет имя поля с его значением.
+Выбор элемента структурного типа выполняется путем вызова соответствующего метода.
+`person.name` и `person.age` преобразуются компилятором Scala в:
+
+```scala
+person.selectDynamic("name").asInstanceOf[String]
+person.selectDynamic("age").asInstanceOf[Int]
+```
+
+## Второй пример
+
+Чтобы закрепить сказанное, вот еще один структурный тип с именем `Book`, представляющий книгу, доступную в базе данных:
+
+```scala
+type Book = Record {
+ val title: String
+ val author: String
+ val year: Int
+ val rating: Double
+}
+```
+
+Как и в случае с `Person`, экземпляр `Book` создается следующим образом:
+
+```scala
+val book = Record(
+ "title" -> "The Catcher in the Rye",
+ "author" -> "J. D. Salinger",
+ "year" -> 1951,
+ "rating" -> 4.5
+).asInstanceOf[Book]
+```
+
+## Класс Selectable
+
+Помимо `selectDynamic` класс `Selectable` иногда также определяет метод `applyDynamic`,
+который можно использовать для замены вызовов функций на вызов структурных элементов.
+Таким образом, если `a` является экземпляром `Selectable`, структурный вызов типа `a.f(b, c)` преобразуется в:
+
+```scala
+a.applyDynamic("f")(b, c)
+```
diff --git a/_ru/scala3/book/types-union.md b/_ru/scala3/book/types-union.md
new file mode 100644
index 0000000000..5c3a089488
--- /dev/null
+++ b/_ru/scala3/book/types-union.md
@@ -0,0 +1,110 @@
+---
+layout: multipage-overview
+title: Объединение типов
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлены объединение типов в Scala 3.
+language: ru
+num: 52
+previous-page: types-intersection
+next-page: types-adts-gadts
+versionSpecific: true
+---
+
+Используемый для типов `|` оператор создает так называемый _тип объединения_ (_union type_).
+Тип `А | B` представляет значения, которые относятся **либо** к типу `A`, **либо** к типу `B`.
+
+В следующем примере метод `help` принимает параметр с именем `id` типа объединения `Username | Password`,
+который может быть либо `Username`, либо `Password`:
+
+```scala
+case class Username(name: String)
+case class Password(hash: Hash)
+
+def help(id: Username | Password) =
+ val user = id match
+ case Username(name) => lookupName(name)
+ case Password(hash) => lookupPassword(hash)
+ // дальнейший код ...
+```
+
+Мы реализуем метод `help`, разделяя две альтернативы с использованием сопоставления с образцом.
+
+Этот код является гибким и типобезопасным решением.
+Если попытаться передать тип, отличный от `Username` или `Password`, компилятор пометит это как ошибку:
+
+```scala
+help("hi") // error: Found: ("hi" : String)
+ // Required: Username | Password
+```
+
+Ошибка также будет получена, если попытаться добавить `case` в выражение `match`,
+которое не соответствует типам `Username` или `Password`:
+
+```scala
+case 1.0 => ??? // Ошибка: это строка не компилируется
+```
+
+### Альтернатива объединенным типам
+
+Как показано, объединенные типы могут использоваться для представления вариантов нескольких разных типов,
+не требуя, чтобы эти типы были частью специально созданной иерархии классов.
+
+#### Предварительное планирование иерархии классов
+
+Другие языки требуют предварительного планирования иерархии классов, как показано в следующем примере:
+
+```scala
+trait UsernameOrPassword
+case class Username(name: String) extends UsernameOrPassword
+case class Password(hash: Hash) extends UsernameOrPassword
+def help(id: UsernameOrPassword) = ...
+```
+
+Предварительное планирование не очень хорошо масштабируется,
+поскольку, например, требования пользователей API могут быть непредсказуемыми.
+Кроме того, загромождение иерархии типов маркерами типа `UsernameOrPassword` затрудняет чтение кода.
+
+#### Теговые объединения
+
+Другой альтернативой является задание отдельного типа перечисления, например:
+
+```scala
+enum UsernameOrPassword:
+ case IsUsername(u: Username)
+ case IsPassword(p: Password)
+```
+
+Перечисление `UsernameOrPassword` представляет собой _помеченное_ (_tagged_) объединение `Username` и `Password`.
+Однако этот способ моделирования объединения требует _явной упаковки и распаковки_,
+и, например, `Username` **не** является подтипом `UsernameOrPassword`.
+
+### Вывод типов объединения
+
+Компилятор присваивает типу объединения выражение, _только если_ такой тип явно задан.
+Например, рассмотрим такие значения:
+
+```scala
+val name = Username("Eve") // name: Username = Username(Eve)
+val password = Password(123) // password: Password = Password(123)
+```
+
+В этом REPL примере показано,
+как можно использовать тип объединения при привязке переменной к результату выражения `if`/`else`:
+
+```
+scala> val a = if true then name else password
+val a: Object = Username(Eve)
+
+scala> val b: Password | Username = if true then name else password
+val b: Password | Username = Username(Eve)
+```
+
+Типом `a` является `Object`, который является супертипом `Username` и `Password`,
+но не _наименьшим_ супертипом, `Password | Username`.
+Если необходим наименьший супертип, его нужно указать явно, как это делается для `b`.
+
+> Типы объединения являются двойственными типам пересечения.
+> И как `&` с типами пересечения, `|` также коммутативен: `A | B` того же типа, что и `B | А`.
diff --git a/_ru/scala3/book/types-variance.md b/_ru/scala3/book/types-variance.md
new file mode 100644
index 0000000000..fa2d409364
--- /dev/null
+++ b/_ru/scala3/book/types-variance.md
@@ -0,0 +1,283 @@
+---
+layout: multipage-overview
+title: Вариантность
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлена и демонстрируется вариантность в Scala 3.
+language: ru
+num: 54
+previous-page: types-adts-gadts
+next-page: types-opaque-types
+---
+
+_Вариантность_ (_variance_) параметра типа управляет подтипом параметризованных типов (таких, как классы или трейты).
+
+Чтобы объяснить вариантность, давайте рассмотрим следующие определения типов:
+
+{% tabs types-variance-1 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+trait Item { def productNumber: String }
+trait Buyable extends Item { def price: Int }
+trait Book extends Buyable { def isbn: String }
+
+```
+
+{% endtab %}
+{% endtabs %}
+
+Предположим также следующие параметризованные типы:
+
+{% tabs types-variance-2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=types-variance-2 %}
+
+```scala
+// пример инвариантного типа
+trait Pipeline[T] {
+ def process(t: T): T
+}
+
+// пример ковариантного типа
+trait Producer[+T] {
+ def make: T
+}
+
+// пример контрвариантного типа
+trait Consumer[-T] {
+ def take(t: T): Unit
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=types-variance-2 %}
+
+```scala
+// пример инвариантного типа
+trait Pipeline[T]:
+ def process(t: T): T
+
+// пример ковариантного типа
+trait Producer[+T]:
+ def make: T
+
+// пример контрвариантного типа
+trait Consumer[-T]:
+ def take(t: T): Unit
+```
+
+{% endtab %}
+{% endtabs %}
+
+В целом существует три режима вариантности (variance):
+
+- **инвариант** (invariant) — значение по умолчанию, написанное как `Pipeline[T]`
+- **ковариантный** (covariant) — помечен знаком `+`, например `Producer[+T]`
+- **контравариантный** (contravariant) — помечен знаком `-`, как в `Consumer[-T]`
+
+Подробнее рассмотрим, что означает и как используется эта аннотация.
+
+### Инвариантные типы
+
+По умолчанию такие типы, как `Pipeline`, инвариантны в своем аргументе типа (в данном случае `T`).
+Это означает, что такие типы, как `Pipeline[Item]`, `Pipeline[Buyable]` и `Pipeline[Book]`, _не являются подтипами_ друг друга.
+
+И это правильно! Предположим, что следующий метод использует два значения (`b1`, `b2`) типа `Pipeline[Buyable]`
+и передает свой аргумент `b` методу `process` при его вызове на `b1` и `b2`:
+
+{% tabs types-variance-3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=types-variance-3 %}
+
+```scala
+def oneOf(
+ p1: Pipeline[Buyable],
+ p2: Pipeline[Buyable],
+ b: Buyable
+): Buyable = {
+ val b1 = p1.process(b)
+ val b2 = p2.process(b)
+ if (b1.price < b2.price) b1 else b2
+ }
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=types-variance-3 %}
+
+```scala
+def oneOf(
+ p1: Pipeline[Buyable],
+ p2: Pipeline[Buyable],
+ b: Buyable
+): Buyable =
+ val b1 = p1.process(b)
+ val b2 = p2.process(b)
+ if b1.price < b2.price then b1 else b2
+```
+
+{% endtab %}
+{% endtabs %}
+
+Теперь вспомните, что у нас есть следующие _отношения подтипов_ между нашими типами:
+
+{% tabs types-variance-4 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+Book <: Buyable <: Item
+```
+
+{% endtab %}
+{% endtabs %}
+
+Мы не можем передать `Pipeline[Book]` методу `oneOf`,
+потому что в реализации `oneOf` мы вызываем `p1` и `p2` со значением типа `Buyable`.
+`Pipeline[Book]` ожидает `Book`, что потенциально может вызвать ошибку времени выполнения.
+
+Мы не можем передать `Pipeline[Item]`, потому что вызов `process` обещает вернуть `Item`;
+однако мы должны вернуть `Buyable`.
+
+#### Почему Инвариант?
+
+На самом деле тип `Pipeline` должен быть инвариантным,
+так как он использует свой параметр типа `T` _и в качестве_ аргумента, _и в качестве_ типа возвращаемого значения.
+По той же причине некоторые типы в библиотеке коллекций Scala, такие как `Array` или `Set`, также являются _инвариантными_.
+
+### Ковариантные типы
+
+В отличие от `Pipeline`, который является инвариантным,
+тип `Producer` помечается как **ковариантный** (covariant) путем добавления к параметру типа префикса `+`.
+Это допустимо, так как параметр типа используется только в качестве типа _возвращаемого_ значения.
+
+Пометка типа как ковариантного означает, что мы можем передать (или вернуть) `Producer[Book]` там,
+где ожидается `Producer[Buyable]`. И на самом деле, это разумно.
+Тип `Producer[Buyable].make` только обещает _вернуть_ `Buyable`.
+Но для пользователей `make`, так же допустимо принять `Book`, который является подтипом `Buyable`,
+то есть это _по крайней мере_ `Buyable`.
+
+Это иллюстрируется следующим примером, где функция `makeTwo` ожидает `Producer[Buyable]`:
+
+{% tabs types-variance-5 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+def makeTwo(p: Producer[Buyable]): Int =
+ p.make.price + p.make.price
+```
+
+{% endtab %}
+{% endtabs %}
+
+Допустимо передать в `makeTwo` производителя книг:
+
+{% tabs types-variance-6 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val bookProducer: Producer[Book] = ???
+makeTwo(bookProducer)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Вызов `price` в рамках `makeTwo` по-прежнему действителен и для `Book`.
+
+#### Ковариантные типы для неизменяемых контейнеров
+
+Ковариантность чаще всего встречается при работе с неизменяемыми контейнерами, такими как `List`, `Seq`, `Vector` и т.д.
+
+Например, `List` и `Vector` определяются приблизительно так:
+
+{% tabs types-variance-7 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+class List[+A] ...
+class Vector[+A] ...
+```
+
+{% endtab %}
+{% endtabs %}
+
+Таким образом, можно использовать `List[Book]` там, где ожидается `List[Buyable]`.
+Это также интуитивно имеет смысл: если ожидается коллекция вещей, которые можно купить,
+то вполне допустимо получить коллекцию книг.
+В примере выше у книг есть дополнительный метод `isbn`, но дополнительные возможности можно игнорировать.
+
+### Контравариантные типы
+
+В отличие от типа `Producer`, который помечен как ковариантный,
+тип `Consumer` помечен как **контравариантный** (contravariant) путем добавления к параметру типа префикса `-`.
+Это допустимо, так как параметр типа используется только _в позиции аргумента_.
+
+Пометка его как контравариантного означает, что можно передать (или вернуть) `Consumer[Item]` там,
+где ожидается `Consumer[Buyable]`.
+То есть у нас есть отношение подтипа `Consumer[Item] <: Consumer[Buyable]`.
+Помните, что для типа `Producer` все было наоборот, и у нас был `Producer[Buyable] <: Producer[Item]`.
+
+И в самом деле, это разумно. Метод `Consumer[Item].take` принимает `Item`.
+Как вызывающий `take`, мы также можем предоставить `Buyable`, который будет с радостью принят `Consumer[Item]`,
+поскольку `Buyable` — это подтип `Item`, то есть, _по крайней мере_, `Item`.
+
+#### Контравариантные типы для потребителей
+
+Контравариантные типы встречаются гораздо реже, чем ковариантные типы.
+Как и в нашем примере, вы можете думать о них как о «потребителях».
+Наиболее важным типом, помеченным как контравариантный, с которым можно столкнуться, является тип функций:
+
+{% tabs types-variance-8 class=tabs-scala-version %}
+{% tab 'Scala 2' for=types-variance-8 %}
+
+```scala
+trait Function[-A, +B] {
+ def apply(a: A): B
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=types-variance-8 %}
+
+```scala
+trait Function[-A, +B]:
+ def apply(a: A): B
+```
+
+{% endtab %}
+{% endtabs %}
+
+Тип аргумента `A` помечен как контравариантный `A` — он использует значения типа `A`.
+Тип результата `B`, напротив, помечен как ковариантный — он создает значения типа `B`.
+
+Вот несколько примеров, иллюстрирующих отношения подтипов, вызванные аннотациями вариантности функций:
+
+{% tabs types-variance-9 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val f: Function[Buyable, Buyable] = b => b
+
+// OK - допустимо вернуть Buyable там, где ожидается Item
+val g: Function[Buyable, Item] = f
+
+// OK - допустимо передать аргумент Book туда, где ожидается Buyable
+val h: Function[Book, Buyable] = f
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Резюме
+
+В этом разделе были рассмотрены три различных вида вариантности:
+
+- **Producers** обычно ковариантны и помечают свой параметр типа со знаком `+`.
+ Это справедливо и для неизменяемых коллекций.
+- **Consumers** обычно контравариантны и помечают свой параметр типа со знаком `-`.
+- Типы, которые являются **одновременно** производителями и потребителями,
+ должны быть инвариантными и не требуют какой-либо маркировки для параметра своего типа.
+ В эту категорию, в частности, попадают изменяемые коллекции, такие как `Array`.
diff --git a/_ru/scala3/book/why-scala-3.md b/_ru/scala3/book/why-scala-3.md
new file mode 100644
index 0000000000..6f2d7eb1a1
--- /dev/null
+++ b/_ru/scala3/book/why-scala-3.md
@@ -0,0 +1,492 @@
+---
+layout: multipage-overview
+title: Почему Scala 3?
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: chapter
+description: На этой странице описаны преимущества языка программирования Scala 3.
+language: ru
+num: 3
+previous-page: scala-features
+next-page: taste-intro
+---
+
+Использование Scala, и Scala 3 в частности, дает много преимуществ.
+Трудно перечислить их все, но “топ десять” может выглядеть так:
+
+1. Scala сочетает в себе функциональное программирование (ФП) и объектно-ориентированное программирование (ООП)
+2. Scala статически типизирован, но часто ощущается как язык с динамической типизацией
+3. Синтаксис Scala лаконичен, но все же удобочитаем; его часто называют _выразительным_
+4. _Implicits_ в Scala 2 были определяющей функцией, а в Scala 3 они были улучшены и упрощены
+5. Scala легко интегрируется с Java, поэтому вы можете создавать проекты со смешанным кодом Scala и Java, а код Scala легко использует тысячи существующих библиотек Java
+6. Scala можно использовать на сервере, а также в браузере со [Scala.js](https://www.scala-js.org)
+7. Стандартная библиотека Scala содержит десятки готовых функциональных методов, позволяющих сэкономить ваше время и значительно сократить потребность в написании пользовательских циклов `for` и алгоритмов
+8. “Best practices”, встроенные в Scala, поддерживают неизменность, анонимные функции, функции высшего порядка, сопоставление с образцом, классы, которые не могут быть расширены по умолчанию, и многое другое
+9. Экосистема Scala предлагает самые современные ФП библиотеки в мире
+10. Сильная система типов
+
+
+## 1) Слияние ФП/ООП
+
+Больше, чем любой другой язык, Scala поддерживает слияние парадигм ФП и ООП.
+Как заявил Мартин Одерски, сущность Scala — это слияние функционального и объектно-ориентированного программирования в типизированной среде, где:
+
+- Функции для логики
+- Объекты для модульности
+
+Возможно, одними из лучших примеров модульности являются классы стандартной библиотеки.
+Например, `List` определяется как класс---технически это абстрактный класс---и новый экземпляр создается следующим образом:
+
+{% tabs list %}
+{% tab 'Scala 2 и 3' for=list %}
+```scala
+val x = List(1, 2, 3)
+```
+{% endtab %}
+{% endtabs %}
+
+Однако то, что кажется программисту простым `List`, на самом деле построено из комбинации нескольких специализированных типов,
+включая трейты с именами `Iterable`, `Seq` и `LinearSeq`.
+Эти типы также состоят из других небольших модульных единиц кода.
+
+В дополнение к построению типа наподобие `List` из серии модульных трейтов,
+`List` API также состоит из десятков других методов, многие из которых являются функциями высшего порядка:
+
+{% tabs list-methods %}
+{% tab 'Scala 2 и 3' for=list-methods %}
+```scala
+val xs = List(1, 2, 3, 4, 5)
+
+xs.map(_ + 1) // List(2, 3, 4, 5, 6)
+xs.filter(_ < 3) // List(1, 2)
+xs.find(_ > 3) // Some(4)
+xs.takeWhile(_ < 3) // List(1, 2)
+```
+{% endtab %}
+{% endtabs %}
+
+В этих примерах значения в списке не могут быть изменены.
+Класс `List` неизменяем, поэтому все эти методы возвращают новые значения, как показано в каждом комментарии.
+
+## 2) Ощущение динамики
+
+_Вывод типов_ (_type inference_) в Scala часто заставляет язык чувствовать себя динамически типизированным, даже если он статически типизирован.
+Это верно для объявления переменной:
+
+{% tabs dynamic %}
+{% tab 'Scala 2 и 3' for=dynamic %}
+```scala
+val a = 1
+val b = "Hello, world"
+val c = List(1,2,3,4,5)
+val stuff = ("fish", 42, 1_234.5)
+```
+{% endtab %}
+{% endtabs %}
+
+Это также верно при передаче анонимных функций функциям высшего порядка:
+
+{% tabs dynamic-hof %}
+{% tab 'Scala 2 и 3' for=dynamic-hof %}
+```scala
+list.filter(_ < 4)
+list.map(_ * 2)
+list.filter(_ < 4)
+ .map(_ * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+и при определении методов:
+
+{% tabs dynamic-method %}
+{% tab 'Scala 2 и 3' for=dynamic-method %}
+```scala
+def add(a: Int, b: Int) = a + b
+```
+{% endtab %}
+{% endtabs %}
+
+Это как никогда верно для Scala 3, например, при использовании [типов объединения][union-types]:
+
+{% tabs union %}
+{% tab 'Только в Scala 3' for=union %}
+```scala
+// параметр типа объединения
+def help(id: Username | Password) =
+ val user = id match
+ case Username(name) => lookupName(name)
+ case Password(hash) => lookupPassword(hash)
+ // дальнейший код ...
+
+// значение типа объединения
+val b: Password | Username = if (true) name else password
+```
+{% endtab %}
+{% endtabs %}
+
+## 3) Лаконичный синтаксис
+
+Scala — это неформальный, “краткий, но все же читабельный“ язык. Например, объявление переменной лаконично:
+
+{% tabs concise %}
+{% tab 'Scala 2 и 3' for=concise %}
+```scala
+val a = 1
+val b = "Hello, world"
+val c = List(1,2,3)
+```
+{% endtab %}
+{% endtabs %}
+
+Создание типов, таких как трейты, классы и перечисления, является кратким:
+
+{% tabs enum %}
+{% tab 'Только в Scala 3' for=enum %}
+```scala
+trait Tail:
+ def wagTail(): Unit
+ def stopTail(): Unit
+
+enum Topping:
+ case Cheese, Pepperoni, Sausage, Mushrooms, Onions
+
+class Dog extends Animal, Tail, Legs, RubberyNose
+
+case class Person(
+ firstName: String,
+ lastName: String,
+ age: Int
+)
+```
+{% endtab %}
+{% endtabs %}
+
+Функции высшего порядка кратки:
+
+{% tabs list-hof %}
+{% tab 'Scala 2 и 3' for=list-hof %}
+
+```scala
+list.filter(_ < 4)
+list.map(_ * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+Все эти и многие другие выражения кратки и при этом очень удобочитаемы: то, что мы называем _выразительным_ (_expressive_).
+
+## 4) Implicits, упрощение
+
+Implicits в Scala 2 были главной отличительной особенностью дизайна.
+Они представляли собой фундаментальный способ абстрагирования от контекста с единой парадигмой,
+обслуживающей множество вариантов использования, среди которых:
+
+- Реализация [типовых классов]({% link _overviews/scala3-book/ca-type-classes.md %})
+- Установление контекста
+- Внедрение зависимости
+- Выражение возможностей
+
+С тех пор другие языки внедрили аналогичные концепции, все из которых являются вариантами основной идеи _вывода терминов_:
+при заданном типе компилятор синтезирует “канонический” термин этого типа.
+
+Хотя implicits были определяющей функцией в Scala 2, их дизайн был значительно улучшен в Scala 3:
+
+- Есть единственный способ определить значения “given”
+- Есть единственный способ ввести неявные параметры и аргументы
+- Есть отдельный способ импорта givens, который не позволяет им потеряться в море обычного импорта
+- Существует единственный способ определить неявное преобразование, которое четко обозначено как таковое и не требует специального синтаксиса
+
+К преимуществам этих изменений относятся:
+
+- Новый дизайн позволяет избежать взаимодействия функциональностей и делает язык более согласованным
+- Это делает implicits более простыми для изучения и более сложными для злоупотребления
+- Это значительно улучшает ясность 95% программ Scala, использующих implicits
+- У него есть потенциал, чтобы сделать вывод терминов принципиальным способом, который также доступен и удобен
+
+Эти возможности подробно расписаны в соответствующих разделах, таких как [введение в контекстную абстракцию][contextual], а также раздел о [`given` и предложениях `using`][given] для получения более подробной информации.
+
+## 5) Полная интеграция с Java
+
+Взаимодействие между Scala и Java не вызывает затруднений во многих ситуациях.
+Например:
+
+- Вы можете использовать все тысячи библиотек Java, доступных в ваших проектах Scala
+- Scala `String` — это, по сути, Java `String` с дополнительными возможностями
+- Scala легко использует классы даты/времени из Java пакета *java.time._*
+
+Вы также можете использовать классы коллекций Java в Scala, а для придания им большей функциональности Scala включает методы,
+позволяющие преобразовывать их в коллекции Scala.
+
+Несмотря на то, что почти каждое взаимодействие является бесшовным,
+в [главе “Взаимодействие с Java”][java] показано, как лучше использовать некоторые функции вместе,
+в том числе как использовать:
+
+- Коллекции Java в Scala
+- Java `Optional` в Scala
+- Интерфейсы Java в Scala
+- Коллекции Scala в Java
+- Scala `Option` в Java
+- Scala traits в Java
+- Методы Scala, вызывающие исключения в Java коде
+- Scala varargs параметры в Java
+
+Подробнее об этих функциях см. в этой главе.
+
+## 6) Клиент & сервер
+
+Scala можно использовать на стороне сервера с потрясающими фреймворками:
+
+- [Play Framework](https://www.playframework.com) позволяет создавать масштабируемые серверные приложения и микросервисы
+- [Akka Actors](https://akka.io) позволяет использовать модель акторов для значительного упрощения распределенных и параллельных программных приложений
+
+Scala также можно использовать в браузере с [проектом Scala.js](https://www.scala-js.org), который является безопасной заменой JavaScript.
+В экосистеме Scala.js есть [десятки библиотек](https://www.scala-js.org/libraries), позволяющих использовать React, Angular, jQuery
+и многие другие библиотеки JavaScript и Scala в браузере.
+
+В дополнение к этим инструментам проект [Scala Native](https://github.com/scala-native/scala-native)
+“представляет собой оптимизирующий опережающий компилятор и облегченную управляемую среду выполнения, разработанную специально для Scala”.
+Он позволяет создавать бинарные исполняемые приложения в “системном” стиле с помощью простого кода Scala, а также позволяет использовать низкоуровневые примитивы.
+
+## 7) Стандартные библиотечные методы
+
+Вам довольно редко понадобится писать пользовательский цикл `for`,
+потому что десятки готовых функциональных методов в стандартной библиотеке Scala сэкономят ваше время
+и помогут сделать код более согласованным в разных приложениях.
+
+В следующих примерах показаны некоторые из встроенных методов коллекций, а также многие другие.
+Хотя все они используют класс `List`, одни и те же методы работают с другими классами коллекций,
+такими как `Seq`, `Vector`, `LazyList`, `Set`, `Map`, `Array` и `ArrayBuffer`.
+
+Вот некоторые примеры:
+
+{% tabs list-more %}
+{% tab 'Scala 2 и 3' for=list-more %}
+```scala
+List.range(1, 3) // List(1, 2)
+List.range(start = 1, end = 6, step = 2) // List(1, 3, 5)
+List.fill(3)("foo") // List(foo, foo, foo)
+List.tabulate(3)(n => n * n) // List(0, 1, 4)
+List.tabulate(4)(n => n * n) // List(0, 1, 4, 9)
+
+val a = List(10, 20, 30, 40, 10) // List(10, 20, 30, 40, 10)
+a.distinct // List(10, 20, 30, 40)
+a.drop(2) // List(30, 40, 10)
+a.dropRight(2) // List(10, 20, 30)
+a.dropWhile(_ < 25) // List(30, 40, 10)
+a.filter(_ < 25) // List(10, 20, 10)
+a.filter(_ > 100) // List()
+a.find(_ > 20) // Some(30)
+a.head // 10
+a.headOption // Some(10)
+a.init // List(10, 20, 30, 40)
+a.intersect(List(19,20,21)) // List(20)
+a.last // 10
+a.lastOption // Some(10)
+a.map(_ * 2) // List(20, 40, 60, 80, 20)
+a.slice(2, 4) // List(30, 40)
+a.tail // List(20, 30, 40, 10)
+a.take(3) // List(10, 20, 30)
+a.takeRight(2) // List(40, 10)
+a.takeWhile(_ < 30) // List(10, 20)
+a.filter(_ < 30).map(_ * 10) // List(100, 200, 100)
+
+val fruits = List("apple", "pear")
+fruits.map(_.toUpperCase) // List(APPLE, PEAR)
+fruits.flatMap(_.toUpperCase) // List(A, P, P, L, E, P, E, A, R)
+
+val nums = List(10, 5, 8, 1, 7)
+nums.sorted // List(1, 5, 7, 8, 10)
+nums.sortWith(_ < _) // List(1, 5, 7, 8, 10)
+nums.sortWith(_ > _) // List(10, 8, 7, 5, 1)
+```
+{% endtab %}
+{% endtabs %}
+
+## 8) Встроенные "best practices"
+
+Идиомы Scala поощряют "best practices" во многих ситуациях.
+Для неизменяемости рекомендуется создавать неизменяемые val переменные:
+
+{% tabs val %}
+{% tab 'Scala 2 и 3' for=val %}
+```scala
+val a = 1 // неизменяемая переменная
+```
+{% endtab %}
+{% endtabs %}
+
+Вам также рекомендуется использовать неизменяемые классы коллекций, такие как `List` и `Map`:
+
+{% tabs list-map %}
+{% tab 'Scala 2 и 3' for=list-map %}
+```scala
+val b = List(1,2,3) // List неизменяем
+val c = Map(1 -> "one") // Map неизменяема
+```
+{% endtab %}
+{% endtabs %}
+
+Case классы в первую очередь предназначены для использования в [моделировании предметной области]({% link _overviews/scala3-book/domain-modeling-intro.md %}), и их параметры также неизменяемы:
+
+{% tabs case-class %}
+{% tab 'Scala 2 и 3' for=case-class %}
+```scala
+case class Person(name: String)
+val p = Person("Michael Scott")
+p.name // Michael Scott
+p.name = "Joe" // compiler error (переназначение val name)
+```
+{% endtab %}
+{% endtabs %}
+
+Как показано в предыдущем разделе, классы коллекций Scala поддерживают функции высшего порядка,
+и вы можете передавать в них методы (не показаны) и анонимные функции:
+
+{% tabs higher-order %}
+{% tab 'Scala 2 и 3' for=higher-order %}
+```scala
+a.dropWhile(_ < 25)
+a.filter(_ < 25)
+a.takeWhile(_ < 30)
+a.filter(_ < 30).map(_ * 10)
+nums.sortWith(_ < _)
+nums.sortWith(_ > _)
+```
+{% endtab %}
+{% endtabs %}
+
+Выражения `match` позволяют использовать сопоставление с образцом, и они действительно являются _выражениями_, которые возвращают значения:
+
+{% tabs match class=tabs-scala-version %}
+{% tab 'Scala 2' for=match %}
+```scala
+val numAsString = i match {
+ case 1 | 3 | 5 | 7 | 9 => "odd"
+ case 2 | 4 | 6 | 8 | 10 => "even"
+ case _ => "too big"
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=match %}
+```scala
+val numAsString = i match
+ case 1 | 3 | 5 | 7 | 9 => "odd"
+ case 2 | 4 | 6 | 8 | 10 => "even"
+ case _ => "too big"
+```
+{% endtab %}
+{% endtabs %}
+
+Поскольку они могут возвращать значения, их часто используют в качестве тела метода:
+
+{% tabs match-body class=tabs-scala-version %}
+{% tab 'Scala 2' for=match-body %}
+```scala
+def isTruthy(a: Matchable) = a match {
+ case 0 | "" => false
+ case _ => true
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=match-body %}
+```scala
+def isTruthy(a: Matchable) = a match
+ case 0 | "" => false
+ case _ => true
+```
+{% endtab %}
+{% endtabs %}
+
+## 9) Библиотеки экосистемы
+
+Библиотеки Scala для функционального программирования, такие как [Cats](https://typelevel.org/cats) и [Zio](https://zio.dev),
+являются передовыми библиотеками в сообществе ФП.
+Об этих библиотеках можно сказать все модные словечки, такие как высокопроизводительная, типобезопасная, параллельная, асинхронная, ресурсобезопасная, тестируемая, функциональная, модульная, бинарно-совместимая, эффективная, эффектная и т.д.
+
+Мы могли бы перечислить здесь сотни библиотек, но, к счастью, все они перечислены в другом месте: подробности см. в списке [“Awesome Scala”](https://github.com/lauris/awesome-scala).
+
+## 10) Сильная система типов
+
+В Scala есть сильная система типов, и она была еще больше улучшена в Scala 3.
+Цели Scala 3 были определены на раннем этапе, и к ним относятся:
+
+- Упрощение
+- Устранение несоответствий
+- Безопасность
+- Эргономика
+- Производительность
+
+_Упрощение_ достигается за счет десятков измененных и удаленных функций.
+Например, изменения перегруженного ключевого слова `implicit` в Scala 2 на термины `given` и `using` в Scala 3 делает язык более понятным, особенно для начинающих разработчиков.
+
+_Устранение несоответствий_ связано с десятками [удаленных функций][dropped], [измененных функций][changed], и [добавленных функций][added] в Scala 3.
+Некоторые из наиболее важных функций в этой категории:
+
+- Типы пересечения
+- Типы объединения
+- Неявные функциональные типы
+- Зависимые функциональные типы
+- Параметры трейтов
+- Generic кортежи
+
+_Безопасность_ связана с несколькими новыми и измененными функциями:
+
+- Мультиверсальное равенство
+- Ограничение неявных преобразований
+- Null безопасность
+- Безопасная инициализация
+
+Хорошими примерами _эргономики_ являются перечисления и методы расширения,
+добавленные в Scala 3 довольно удобочитаемым образом:
+
+{% tabs extension %}
+{% tab 'Только в Scala 3' for=extension %}
+```scala
+// перечисления
+enum Color:
+ case Red, Green, Blue
+
+// методы расширения
+extension (c: Circle)
+ def circumference: Double = c.radius * math.Pi * 2
+ def diameter: Double = c.radius * 2
+ def area: Double = math.Pi * c.radius * c.radius
+```
+{% endtab %}
+{% endtabs %}
+
+_Производительность_ относится к нескольким областям.
+Одним из них являются [непрозрачные типы][opaque-types].
+В Scala 2 было несколько попыток создать решения, соответствующие практике проектирования, управляемого предметной областью (DDD),
+когда значениям присваивались более осмысленные типы.
+Эти попытки включали:
+
+- Псевдонимы типов
+- Классы значений
+- Case классы
+
+К сожалению, у всех этих подходов были недостатки, как описано в [SIP непрозрачных типов](https://docs.scala-lang.org/sips/opaque-types.html).
+И наоборот, цель непрозрачных типов, как описано в этом SIP, заключается в том, что “операции с этими типами-оболочками не должны создавать дополнительных накладных расходов во время выполнения, но при этом обеспечивать безопасное использование типов во время компиляции”.
+
+Дополнительные сведения о системе типов см. в [справочной документации][reference].
+
+## Другие замечательные функции
+
+Scala обладает множеством замечательных функций, и выбор Топ-10 может быть субъективным.
+Несколько опросов показали, что разные группы разработчиков ценят разные функции.
+Надеемся, вы откроете для себя больше замечательных возможностей Scala по мере использования языка.
+
+[java]: {% link _overviews/scala3-book/interacting-with-java.md %}
+[given]: {% link _overviews/scala3-book/ca-context-parameters.md %}
+[contextual]: {% link _overviews/scala3-book/ca-contextual-abstractions-intro.md %}
+[reference]: {{ site.scala3ref }}
+[dropped]: {{ site.scala3ref }}/dropped-features
+[changed]: {{ site.scala3ref }}/changed-features
+[added]:{{ site.scala3ref }}/other-new-features
+
+[union-types]: {% link _overviews/scala3-book/types-union.md %}
+[opaque-types]: {% link _overviews/scala3-book/types-opaque-types.md %}
diff --git a/_ru/scala3/contribute-to-docs.md b/_ru/scala3/contribute-to-docs.md
new file mode 100644
index 0000000000..d01570ac6e
--- /dev/null
+++ b/_ru/scala3/contribute-to-docs.md
@@ -0,0 +1,68 @@
+---
+layout: singlepage-overview
+title: Вклад в документацию
+partof: scala3-scaladoc
+scala3: true
+language: ru
+---
+
+## Обзор
+В настоящее время предпринимается множество усилий по созданию высококачественной документации для Scala 3.
+В частности, это следующие документы:
+
+- Книга Scala 3
+- Учебник по макросам
+- Руководство по миграции
+- Справочник по языку Scala 3
+
+Мы приветствуем вклад сообщества в каждый аспект документации.
+
+
+### Как я могу внести свой вклад?
+В целом, есть много способов, которыми вы можете нам помочь:
+
+- **Запутались в чем-то в любом из документов?** Откройте issue.
+- **Нашли что-то неактуальное?** Откройте issue или создайте PR.
+- **Опечатки и другие мелкие улучшения текста?** Создайте PR.
+- **Хотите добавить что-то новое или внести большие изменения?** Отлично! Пожалуйста, откройте issue и давайте обсудим это.
+
+Как правило, каждый из различных проектов документации содержит ссылки
+(как и этот документ на панели оглавления — пока видимые только в desktop view) для их редактирования и улучшения.
+Кроме того, ниже мы предоставим вам всю необходимую информацию для начала работы.
+
+
+## Книга Scala 3
+[Книга Scala 3][scala3-book] написана Alvin Alexander и содержит обзор всех важных функций Scala 3.
+Она предназначена для читателей, которые только знакомятся со Scala.
+
+- [Исходники](https://github.com/scala/docs.scala-lang/tree/main/_overviews/scala3-book)
+- [Вопросы](https://github.com/scala/docs.scala-lang/issues)
+
+## Учебник по макросам
+[Учебник по макросам](/scala3/guides/macros) написан Nicolas Stucki и содержит подробную информацию о макросах в Scala 3 и best-practices.
+
+- [Исходники](https://github.com/scala/docs.scala-lang/tree/main/_overviews/scala3-macros)
+- [Вопросы](https://github.com/scala/docs.scala-lang/issues)
+
+## Руководство по миграции
+[Руководство по миграции на Scala 3](/scala3/guides/migration/compatibility-intro.html) содержит исчерпывающий обзор
+совместимости между Scala 2 и Scala 3, презентацию по инструментам миграции и подробные руководства по миграции.
+
+- [Исходники](https://github.com/scala/docs.scala-lang/tree/main/_overviews/scala3-migration)
+- [Вопросы](https://github.com/scala/docs.scala-lang/issues)
+
+## Руководство по содействию в разработке Scala 3
+[Руководство по содействию в разработке Scala 3](/scala3/guides/contribution/contribution-intro.html)
+содержит исчерпывающий обзор вклада в разработку и внутреннего устройства компилятора и библиотек Scala 3.
+
+- [Исходники](https://github.com/scala/docs.scala-lang/tree/main/_overviews/scala3-contribution)
+- [Вопросы](https://github.com/scala/docs.scala-lang/issues)
+
+## Справочник по языку Scala 3
+[Справочник по Scala 3]({{ site.scala3ref }}) содержит формальное представление и подробную техническую информацию о различных возможностях языка.
+
+- [Исходники](https://github.com/scala/scala3/tree/main/docs/_docs)
+- [Вопросы](https://github.com/scala/scala3/issues)
+
+
+[scala3-book]: {% link _overviews/scala3-book/introduction.md %}
diff --git a/_ru/scala3/guides/scaladoc/blog.md b/_ru/scala3/guides/scaladoc/blog.md
new file mode 100644
index 0000000000..540a05bd03
--- /dev/null
+++ b/_ru/scala3/guides/scaladoc/blog.md
@@ -0,0 +1,87 @@
+---
+layout: multipage-overview
+title: Встроенный блог
+partof: scala3-scaladoc
+language: ru
+num: 5
+previous-page: static-site
+next-page: site-versioning
+---
+
+Scaladoc позволяет включить в документацию простой блог.
+На данный момент предоставляются только основные функции.
+В будущем мы планируем включить более продвинутые функции, такие как теги или авторские страницы.
+
+К блогу относятся немного иначе, чем к обычным статическим сайтам.
+Эта статья поможет вам создать свой собственный блог.
+
+## Правильная настройка каталога
+
+Статьи в блоге должны быть помещены в каталог `_blog/_posts`.
+
+```
+├── _blog
+│ ├── _posts
+│ │ └── 2016-12-05-implicit-function-types.md
+│ └── index.html
+```
+
+Scaladoc загружает блог, если существует каталог `_blog`.
+
+## Соглашение об именовании
+
+Все имена файлов сообщений блога должны начинаться с даты в числовом формате, соответствующем `YYYY-MM-DD`.
+Пример имени - `2022-06-17-dotty-compiler-bootstraps.md`.
+
+## Метаданные страницы
+
+Страницы блога в scaladoc поддерживают [Yaml Frontmatter](https://assemble.io/docs/YAML-front-matter.html),
+что позволяет указывать различные значения, которые будут использоваться для метаданных на вашей странице.
+Вот возможные поля:
+
+```
+---
+layout: <Ссылка на макет страницы для страницы блога>
+author: <Автор страницы>
+title: <Заголовок страницы>
+subTitle: <Подзаголовок страницы>
+date: <Дата создания страницы>, например, 2016-12-05
+authorImg: <Ссылка на картинку автора>
+---
+<Содержимое страницы>
+```
+
+Вы также можете найти более подробную информацию о метаданных [на сайте документации Jekyll](https://jekyllrb.com/docs/front-matter/).
+
+## Синтаксис содержимого
+
+Имейте в виду, что для записи вашего блога необходимо использовать формат Markdown.
+Более детальная информация о синтаксисе доступна в [Руководстве по Markdown](https://www.markdownguide.org/basic-syntax/).
+
+## Конфигурация блога
+
+Scaladoc позволяет настраивать блог, при его создании.
+
+Чтобы изменить настройки документации блога по умолчанию,
+пользователям необходимо создать файл с именем `blog.yml` в **корневом каталоге блога**.
+Этот файл должен содержать параметры, которые пользователь хочет изменить.
+Например, если пользователь хочет изменить исходный каталог на "my_posts",
+исходящий каталог на "my_docs" и временно скрыть блог,
+то можно создать файл со следующим содержимым:
+
+```
+input: my_posts
+output: my_docs
+hidden: true
+```
+
+### Параметры:
+
+`input`: указывает каталог, содержащий markdown-файлы для постов блога (по умолчанию: "\_posts" в "docs").
+
+`output`: указывает папку, в которой будут созданы HTML-страницы (по умолчанию: "blog" в "target/docs").
+
+`hidden`: позволяет пользователям временно скрывать блог (по умолчанию: "false").
+
+Чтобы изменить эти настройки, создайте файл с параметрами и сохраните его в корневом каталоге блога.
+При следующей сборке блога будут использоваться новые параметры.
diff --git a/_ru/scala3/guides/scaladoc/docstrings.md b/_ru/scala3/guides/scaladoc/docstrings.md
new file mode 100644
index 0000000000..6ba32d082e
--- /dev/null
+++ b/_ru/scala3/guides/scaladoc/docstrings.md
@@ -0,0 +1,222 @@
+---
+layout: multipage-overview
+title: Docstrings - специфичные теги и особенности
+partof: scala3-scaladoc
+language: ru
+num: 2
+previous-page: index
+next-page: linking
+---
+
+В этой главе описывается, как правильно писать строки документации и как использовать все доступные функции scaladoc.
+Так как многое осталось таким же, как и в старом scaladoc, некоторые детали взяты из этой
+[статьи](https://docs.scala-lang.org/overviews/scaladoc/for-library-authors.html).
+
+Scaladoc расширяет возможности Markdown дополнительными функциями, такими как ссылки на определения API.
+Это можно использовать в статической документации и постах в блогах для создания смешанного контента.
+
+## Куда поместить строки документации
+
+Комментарии Scaladoc идут перед элементами, к которым они относятся, в специальном блоке комментариев,
+который начинается с `/**` и заканчивается `*/`, например:
+
+```scala
+/** Комментарий начинается здесь.
+ * Левая "звезда", за которой следует пробел в каждой строке,
+ * позволяет продолжить комментарий.
+ *
+ * Даже на пустых строках разрыва абзаца.
+ *
+ * Обратите внимание, что '*' в каждой строке выровнена
+ * со вторым '*' в '/**' так, чтобы
+ * левое поле находилось в том же столбце, где
+ * первая строка и последующие.
+ *
+ * Комментарий закрывается с помощью '*' и обратного слэша.
+ *
+ * Если используются теги Scaladoc (@param, @group и т.д.),
+ * не забудьте поместить их в отдельные строки без предшествующих им строк.
+ *
+ * Например:
+ *
+ * Рассчитать квадрат заданного числа
+ *
+ * @param d the Double to square
+ * @return the result of squaring d
+ */
+ def square(d: Double): Double = d * d
+```
+
+В приведенном выше примере этот комментарий Scaladoc связан с методом square,
+поскольку он находится прямо перед ним в исходном коде.
+
+Комментарии Scaladoc могут идти перед полями, методами, классами, трейтами, объектами.
+На данный момент scaladoc не поддерживает прямое решение для документирования пакетов.
+На гитхабе есть специальный [issue](https://github.com/scala/scala3/issues/11284), где вы можете проверить текущий статус проблемы.
+
+Для первичных конструкторов класса, которые в Scala совпадают с определением самого класса,
+тег @constructor используется для указания комментария, помещаемого в документацию первичных конструкторов, а не в обзор класса.
+
+## Теги
+
+Scaladoc использует теги `@`для предоставления определенных подробностей полей в комментариях.
+Теги включают:
+
+### Теги, специфичные для класса
+
+- `@constructor` помещенный в комментарий класса, будет описывать первичный конструктор.
+
+### Теги, специфичные для метода
+
+- `@return` для детализации возвращаемого значения из метода (по одному на метод).
+
+### Теги метода, конструктора и/или класса
+
+- `@throws` какие исключения (если есть) может генерировать метод или конструктор.
+- `@param` детализация параметра метода или конструктора, предоставляется по одному `@param` для каждого параметра метода/конструктора.
+- `@tparam` детализация параметра типа для метода, конструктора или класса. Указывается по одному для каждого параметра типа.
+
+### Теги использования
+
+- `@see` ссылки на другие источники информации, такие как ссылки на внешние документы или связанные объекты в документации.
+- `@note` добавление примечания о предварительных или последующих условиях или любых других заметных ограничениях или ожиданиях.
+- `@example` предоставление примера кода или соответствующей документации.
+
+
+### Теги группировки
+
+Эти теги хорошо подходят для больших типов или пакетов со многими элементами.
+Они позволяют организовать страницу Scaladoc в отдельные разделы, каждый из которых отображается отдельно в выбранном порядке.
+
+Эти теги не включены по умолчанию! Необходимо передать флаг `-groups` в Scaladoc, чтобы включить их.
+В sbt это обычно выглядит примерно так:
+
+```scala
+Compile / doc / scalacOptions ++= Seq(
+ "-groups"
+)
+```
+
+Каждый раздел должен иметь идентификатор из одного слова, который используется во всех этих тегах, как показано ниже в `group`.
+По умолчанию этот идентификатор отображается как заголовок раздела документации,
+но можно использовать `@groupname`, чтобы указать более длинный заголовок.
+
+Как правило, необходимо поместить `@groupprio` (и, возможно, `@groupname` и `@groupdesc`) в Scaladoc для самого пакета/трейта/класса/объекта,
+описывая все группы и их порядок. Затем поместить `@group` в Scaladoc для каждого члена, указав, в какой группе он находится.
+
+Члены, у которых нет тега `@group`, будут перечислены в результирующей документации как “Ungrouped”.
+
+- `@group ` - пометить сущность как члена `` группы
+- `@groupname ` - указание необязательного имени для группы. `` отображается как заголовок группы перед её описанием.
+- `@groupdesc ` - добавление необязательного описания для отображения под именем группы. Поддерживает многострочный форматированный текст.
+- `@groupprio ` - управление порядком группы на странице. По умолчанию 0. Несгруппированные элементы имеют неявный приоритет 1000.
+ Используются значения от 0 до 999, чтобы задать положение относительно других групп. Малые значения появятся перед большими значениями.
+
+### Другие теги
+
+- `@author` предоставление информации об авторе для следующего объекта.
+- `@version` версия системы или API, частью которой является этот объект.
+- `@since` похож на `@version`, но определяет систему или API, в котором эта сущность была впервые определена.
+- `@deprecated` помечает объект как устаревший, предоставляя как замену реализации, которую следует использовать,
+ так и версию/дату, когда этот объект устарел.
+- `@syntax ` позволяет изменить парсер для docstring. Синтаксис по умолчанию — markdown,
+ однако можно изменить его с помощью этой директивы. В настоящее время доступны синтаксисы `markdown` или `wiki`.
+ Пример использования: `@syntax wiki`.
+
+### Макросы
+
+- `@define ` позволяет использовать $name в других комментариях Scaladoc в том же исходном файле, который будет заменен на ``.
+
+Если комментарий не предоставляется для объекта на текущем уровне наследования,
+но предоставляется для переопределенного объекта на более высоком уровне иерархии наследования,
+будет использоваться комментарий из суперкласса.
+
+Аналогично, если `@param`, `@tparam`, `@return` и другие теги сущностей опущены, но доступны из суперкласса, будут использоваться из суперкласса.
+
+### Явный
+
+Для явного наследования комментариев используется тег `@inheritdoc`.
+
+### Разметка
+
+Scaladoc предоставляет два анализатора синтаксиса: `markdown` (по умолчанию) или `wikidoc`.
+В Scaladoc по-прежнему можно встраивать теги HTML (как и в Javadoc), но в большинстве случаев это не обязательно,
+поскольку вместо этого может использоваться разметка.
+
+#### Markdown
+
+Markdown использует [вариант commonmark](https://spec.commonmark.org/current/) с двумя пользовательскими расширениями:
+- `wikidoc` ссылки для удобства
+- `wikidoc`кодовые блоки с синтаксисом фигурных скобок
+
+#### Wikidoc
+
+Wikidoc — это синтаксис, используемый для scala2 scaladoc.
+Он поддерживается из-за многих существующих исходников, однако **не** рекомендуется его использование в новых проектах.
+Синтаксис вики можно включить с помощью глобального флага `-comment-syntax wiki` или с помощью `@syntax wiki` директивы в строке документации.
+
+Некоторые из стандартных доступных разметок:
+
+```
+`monospace`
+''italic text''
+'''bold text'''
+__underline__
+^superscript^
+,,subscript,,
+[[entity link]], e.g. [[scala.collection.Seq]]
+[[https://external.link External Link]], e.g. [[https://scala-lang.org Scala Language Site]]
+```
+
+Для получения дополнительной информации о вики-ссылках см. [эту главу](#связывание-с-api).
+
+Другие примечания по форматированию
+
+- Абзацы начинаются с одной (или нескольких) пустых строк. `*` на полях для комментария допустимо (и должно быть включено),
+ в противном случае строка должна оставаться пустой.
+- Заголовки определяются окружающими символами `=` с большим количеством `=` для обозначения подзаголовков.
+ Например `=Heading=`, `==Sub-Heading==` и т.д.
+- Блоки списка представляют собой последовательность элементов списка с одинаковым стилем и уровнем,
+ без прерываний от других стилей блоков. Неупорядоченные списки можно маркировать с помощью `-`,
+ нумерованные списки можно обозначать с помощью `1.`, `i.`, `I.` или `a.` для различных стилей нумерации.
+ В обоих случаях должно быть дополнительное пространство впереди, а большее пространство создает подуровень.
+
+Разметка для блоков списка выглядит так:
+
+```
+/** Вот неупорядоченный список:
+ *
+ * - Первый элемент
+ * - Второй элемент
+ * - Подпункт ко второму
+ * - Еще один подпункт
+ * - Третий пункт
+ *
+ * Вот упорядоченный список:
+ *
+ * 1. Первый пронумерованный элемент
+ * 1. Второй номер позиции
+ * i. Подпункт ко второму
+ * i. Еще один подпункт
+ * 1. Третий пункт
+ */
+```
+
+### Общие примечания по написанию комментариев к Scaladoc
+
+Краткость - это хорошо! Быстро переходите к сути, у людей ограничено время, которое они могут потратить на вашу документацию,
+используйте его с умом. Опустите ненужные слова. "Prefer возвращает X", а не "этот метод возвращает X",
+и "X, Y и Z", а не "этот метод возвращает X, Y и Z".
+Принцип DRY (_Don’t repeat yourself_) - не повторяйтесь.
+Не дублируйте описание метода в теге `@return` и других формах повторяющихся комментариев.
+
+### Подробнее о написании Scaladoc
+
+Дополнительную информацию о рекомендациях по форматированию и стилю можно найти
+в [руководстве по стилю Scala-lang scaladoc](https://docs.scala-lang.org/style/scaladoc.html).
+
+## Связывание с API
+
+Scaladoc позволяет ссылаться на документацию по API с помощью ссылок в стиле Wiki.
+Связать с `scala.collection.immutable.List` так же просто, как указать `[[scala.collection.immutable.List]]`.
+Для получения дополнительной информации о точном синтаксисе см. [ссылки в документации](/ru/scala3/guides/scaladoc/linking.html#определение-ссылок).
diff --git a/_ru/scala3/guides/scaladoc/index.md b/_ru/scala3/guides/scaladoc/index.md
new file mode 100644
index 0000000000..048272f371
--- /dev/null
+++ b/_ru/scala3/guides/scaladoc/index.md
@@ -0,0 +1,13 @@
+---
+layout: multipage-overview
+title: Scaladoc
+partof: scala3-scaladoc
+language: ru
+num: 1
+next-page: docstrings
+---
+
+
+
+Scaladoc — это инструмент для создания API документации ваших проектов Scala 3.
+Он предоставляет функциональность, аналогичную `javadoc`, а также `jekyll` или `docusaurus`.
diff --git a/_ru/scala3/guides/scaladoc/linking.md b/_ru/scala3/guides/scaladoc/linking.md
new file mode 100644
index 0000000000..fd0670ba65
--- /dev/null
+++ b/_ru/scala3/guides/scaladoc/linking.md
@@ -0,0 +1,94 @@
+---
+layout: multipage-overview
+title: Ссылки в документации
+partof: scala3-scaladoc
+language: ru
+num: 3
+previous-page: docstrings
+next-page: static-site
+---
+
+Основная функция Scaladoc — создание API документации из комментариев к коду.
+
+По умолчанию комментарии к коду понимаются как Markdown, хотя мы также поддерживаем старый Scaladoc синтаксис
+[Wiki](https://docs.scala-lang.org/style/scaladoc.html).
+
+## Синтаксис
+
+### Определение ссылок
+
+Наш синтаксис определения ссылки очень близок к синтаксису Scaladoc, хотя мы внесли некоторые улучшения.
+
+#### Основной синтаксис
+
+Определение ссылки выглядит следующим образом: `[[scala.collection.immutable.List]]`.
+
+Другими словами, определение ссылки представляет собой последовательность идентификаторов, разделенных знаком `.`.
+Идентификаторы также могут быть разделены с помощью `#`.
+
+По умолчанию идентификатор `id` ссылается на первую (в исходном порядке) сущность с именем `id`.
+Идентификатор может заканчиваться на `$`, что заставляет его ссылаться на значение (объект, значение, given);
+идентификатор также может заканчиваться на `!`, что заставляет его ссылаться на тип (класс, псевдоним типа, член типа).
+
+Ссылки рассчитываются относительно текущего местоположения в источнике.
+То есть при документировании класса ссылки относятся к сущности, включающей класс (пакет, класс, объект);
+то же самое относится к документированию определений.
+
+Специальные символы в ссылках могут быть экранированы обратной косой чертой, что вместо этого делает их частью идентификаторов.
+Например, `` [[scala.collection.immutable\.List]] `` ссылается на класс `` `immutable.List` ``, указанный в package `scala.collection`.
+
+#### Новый синтаксис
+
+Определение ссылок Scaladoc было расширено, чтобы сделать их более удобными для записи и чтения в исходном коде.
+Также целью было сблизить связь и синтаксис Scala. Новые функции:
+
+1. `package` может использоваться в качестве префикса для ссылки на прилагаемый пакет.
+ Пример:
+ ```
+ package utils
+ class C {
+ def foo = "foo".
+ }
+ /** See also [[package.C]]. */
+ class D {
+ def bar = "bar".
+ }
+ ```
+ Ключевое слово `package` помогает сделать ссылки на прилагаемый пакет короче
+ и немного более устойчивым к рефакторингу имен.
+1. `this` может использоваться в качестве префикса для ссылки на прилагаемый классоподобный пример:
+ ```
+ class C {
+ def foo = "foo"
+ /** This is not [[this.foo]], this is bar. */
+ def bar = "bar"
+ }
+ ```
+ Использование здесь ключевого слова помогает сделать ссылки более привычными,
+ а также помогает ссылкам "пережить" изменения имени класса.
+1. Обратные кавычки могут использоваться для экранирования идентификаторов.
+ Пример:
+ ```
+ def `([.abusive.])` = ???
+ /** TODO: Figure out what [[`([.abusive.])`]] is. */
+ def foo = `([.abusive.])`
+ ```
+ Ранее (в версиях 2.x) для ссылки на такие идентификаторы в Scaladoc требовалось экранирование обратной косой чертой.
+ Теперь (в версиях 3.x) Scaladoc позволяет использовать знакомую обратную кавычку Scala.
+
+#### Зачем сохранять синтаксис Wiki для ссылок?
+
+Есть несколько причин, по которым синтаксис Wiki сохранен для ссылок на документацию
+вместо повторного использования синтаксиса Markdown. Это:
+
+1. Безымянные ссылки в Markdown уродливы: `[](definition)` против `[[definition]]`
+ Безусловно, большинство ссылок в документации безымянные. Должно быть очевидно, как их писать.
+2. Поиск локального члена конфликтует с фрагментами URL: `[](#field)` против `[[#field]]`
+3. Разрешение перегрузки противоречит синтаксису MD: `[](meth(Int))` против `[[meth(Int)]]`
+4. Теперь, когда есть парсер для синтаксиса ссылок, можно разрешить пробелы внутри
+ (в Scaladoc нужно было экранировать их косой чертой), но это не распознается как ссылка в Markdown:
+ `[](meth(Int, Float))` против `[[meth(Int, Float)]]`
+
+Ни одна из этих причин не делает полностью невозможным использование стандартного синтаксиса ссылок Markdown,
+но они делают его гораздо более неуклюжим и уродливым, чем нужно.
+Кроме того, синтаксис ссылок Markdown даже не сохраняет никаких символов.
diff --git a/_ru/scala3/guides/scaladoc/search-engine.md b/_ru/scala3/guides/scaladoc/search-engine.md
new file mode 100644
index 0000000000..9ef88e0630
--- /dev/null
+++ b/_ru/scala3/guides/scaladoc/search-engine.md
@@ -0,0 +1,102 @@
+---
+layout: multipage-overview
+title: Поиск по типу
+partof: scala3-scaladoc
+language: ru
+num: 7
+previous-page: site-versioning
+next-page: snippet-compiler
+---
+
+Поиск функций по их символическим именам может занять много времени.
+Именно поэтому новый scaladoc позволяет искать методы и поля по их типам.
+
+Рассмотрим следующее определение метода расширения:
+```
+extension [T](arr: IArray[T]) def span(p: T => Boolean): (IArray[T], IArray[T]) = ...
+```
+Вместо поиска `span` также можно искать по `IArray[A] => (A => Boolean) => (IArray[A], IArray[A])`.
+
+Чтобы использовать эту функцию, введите сигнатуру искомого элемента в строке поиска scaladoc.
+Вот как это работает:
+
+
+
+Эта функция предоставляется поисковой системой [Inkuire](https://github.com/VirtusLab/Inkuire), которая работает для Scala 3 и Kotlin.
+Чтобы быть в курсе развития этой функции, следите за репозиторием [Inkuire](https://github.com/VirtusLab/Inkuire).
+
+## Примеры запросов
+
+Некоторые примеры запросов с предполагаемыми результатами:
+- `List[Int] => (Int => Long) => List[Long]` -> `map`
+- `Seq[A] => (A => B) => Seq[B]` -> `map`
+- `(A, B) => A` -> `_1`
+- `Set[Long] => Long => Boolean` -> `contains`
+- `Int => Long => Int` -> `const`
+- `String => Int => Char` -> `apply`
+- `(Int & Float) => (String | Double)` -> `toDouble`, `toString`
+- `F[A] => Int` -> `length`
+
+## Синтаксис запроса
+
+Для того чтобы запрос панели поиска scaladoc выполнялся с использованием Inkuire вместо поисковой системы по умолчанию,
+запрос должен содержать последовательность символов `=>`.
+
+Принятый ввод аналогичен сигнатуре каррированной функции в Scala 3. С некоторыми отличиями:
+- AndTypes, OrTypes и Functions должны быть заключены в круглые скобки, например, `(Int & Any) => String`
+- поля и методы без параметров можно найти, указав перед их типом `=>`, например, `=> Int`
+- Можно использовать подстановочный знак `_`, чтобы указать, что необходимо сопоставить любой тип в данном месте,
+ например, `Long => Double => _`
+- Типы в виде одной буквы, например `A`, или буквы с цифрой `X1`, автоматически считаются переменными типа.
+- Другие переменные типа могут быть объявлены так же, как и в полиморфных функциях,
+ например `[AVariable, AlsoAVariable] => AVariable => AlsoAVariable => AVariable`
+
+### Работа с псевдонимами типов и приемниками методов
+
+Когда дело доходит до того, как код сопоставляется с записями InkuireDb, есть некоторые преобразования,
+чтобы сделать движок более самостоятельным (хотя и открытым для предложений и изменений).
+Во-первых, получатель (не владелец модуля) функции может рассматриваться как первый аргумент.
+Также применяется автоматическое каррирование, чтобы результаты не зависели от списков аргументов.
+При поиске совпадений `val` и `def` не различаются.
+
+Итак, по запросу `Num => Int => Int => Int` должны быть найдены следующие объявления:
+```
+class Num():
+ def a(i: Int, j: Int): Int
+ def b(i: Int)(j: Int): Int
+ def c(i: Int): (Int => Int)
+ val d: Int => Int => Int
+ val e: Int => Int => Int
+ val f: (Int, Int) => Int
+end Num
+
+def g(i: Num, j: Int, k: Int): Int
+extension (i: Num) def h(j: Int, k: Int): Int
+def i(i: Num, j: Int)(k: Int): Int
+extension (i: Num) def j(j: Int)(k: Int): Int
+...
+```
+
+Когда дело доходит до псевдонимов типов, они дешугаризуются как в объявлении, так и в подписи запроса.
+Это означает, что для объявлений:
+```
+type Name = String
+
+def fromName(name: Name): String
+def fromString(str: String): Name
+```
+оба метода `fromName` и `fromString`, должны быть найдены по запросам `Name => Name`, `String => String`, `Name => String` и `String => Name`.
+
+## Как это работает
+
+Inkuire работает как рабочий JavaScript в браузере благодаря мощи [ScalaJS](https://www.scala-js.org/).
+
+Чтобы включить Inkuire при запуске scaladoc, добавьте флаг `-Ygenerate-inkuire`.
+При добавлении этого флага создаются два файла:
+- `inkuire-db.json` - это файл, содержащий все доступные для поиска объявления из текущего документированного проекта в формате,
+ читаемом поисковой системой Inkuire.
+- `inkuire-config.json` - этот файл содержит расположение файлов базы данных,
+ которые должны быть доступны для поиска в документации текущего проекта.
+ По умолчанию он будет сгенерирован с расположением локального файла базы данных,
+ а также с подразумеваемыми по умолчанию расположениями файлов базы данных во внешних сопоставлениях
+ [`-external-mappings`](/ru/scala3/guides/scaladoc/settings.html#-external-mappings).
diff --git a/_ru/scala3/guides/scaladoc/settings.md b/_ru/scala3/guides/scaladoc/settings.md
new file mode 100644
index 0000000000..942e88342b
--- /dev/null
+++ b/_ru/scala3/guides/scaladoc/settings.md
@@ -0,0 +1,218 @@
+---
+layout: multipage-overview
+title: Настройки
+partof: scala3-scaladoc
+language: ru
+num: 9
+previous-page: snippet-compiler
+---
+
+В этой главе перечислены параметры конфигурации, которые можно использовать при вызове scaladoc.
+Некоторую информацию, показанную здесь, можно получить, вызвав scaladoc с флагом `-help`.
+
+## Изменения scaladoc по сравнению со Scala 2
+
+Scaladoc был переписан с нуля, и некоторые функции оказались бесполезными в новом контексте.
+Текущее состояние совместимости со старыми флагами scaladoc можно увидеть [здесь](https://github.com/scala/scala3/issues/11907).
+
+## Указание настроек
+
+Настройки scaladoc можно указывать в качестве аргументов командной строки,
+например, `scaladoc -d output -project my-project target/scala-3.0.0-RC2/classes`.
+При вызове из sbt, обновите значение `Compile / doc / scalacOptions` и `Compile / doc / target` соответственно, например
+
+```
+Compile / doc / target := file("output"),
+Compile / doc / scalacOptions ++= Seq("-project", "my-project"),
+```
+
+## Обзор всех доступных настроек
+
+##### -project
+
+Название проекта. Чтобы обеспечить совместимость с псевдонимами Scala2 с `-doc-title`
+
+##### -project-version
+
+Текущая версия проекта, которая отображается в верхнем левом углу.
+Чтобы обеспечить совместимость с псевдонимами Scala2 с `-doc-version`
+
+##### -project-logo
+
+Логотип проекта, который появляется в верхнем левом углу.
+Для темной темы можно выделить отдельный логотип с суффиксом `_dark`.
+Например, если есть логотип `mylogo.png`, то для темной темы предполагается `mylogo_dark.png`.
+Чтобы обеспечить совместимость с псевдонимами Scala2 с `-doc-logo`
+
+##### -project-footer
+
+Строковое сообщение, которое отображается в разделе нижнего колонтитула.
+Чтобы обеспечить совместимость с псевдонимами Scala2 с `-doc-footer`
+
+##### -comment-syntax
+
+Язык стилей, используемый для разбора комментариев.
+В настоящее время поддерживается два синтаксиса: `markdown` или `wiki`.
+Если настройка отсутствует, по умолчанию - `markdown`.
+
+##### -revision
+
+Редакция (ветвь или ссылка), используемая для создания проекта.
+Полезно с исходными ссылками, чтобы они не всегда указывали на последний `main`, который может быть изменен.
+
+##### -source-links
+
+Ссылки на источники обеспечивают сопоставление между файлом в документации и репозиторием кода.
+
+Примеры исходных ссылок:
+`-source-links:docs=github://scala/scala3/main#docs`
+
+Принимаемые форматы:
+
+`=`
+
+где `` является одним из следующих:
+
+- `github:///[/revision][#subpath]`
+ будет соответствовать https://github.com/$organization/$repository/[blob|edit]/$revision[/$subpath]/$filePath[$lineNumber],
+ если редакция не указана, тогда требуется указать редакцию в качестве аргумента для Scaladoc
+- `gitlab:///`
+ будет соответствовать https://gitlab.com/$organization/$repository/-/[blob|edit]/$revision[/$subpath]/$filePath[$lineNumber],
+ если редакция не указана, тогда требуется, чтобы редакция была указана как аргумент в Scaladoc
+- ``
+
+`` — это формат параметра `doc-source-url` из старого scaladoc.
+ПРИМЕЧАНИЕ. Поддерживаются только шаблоны `€{FILE_PATH_EXT}`, `€{TPL_NAME}`, `€{FILE_EXT}`, `€{FILE_PATH}` и `€{FILE_LINE}`.
+
+Шаблон может быть определен только подмножеством источников, определенных префиксом пути, представленным ``.
+В этом случае пути, используемые в шаблонах, будут относительны к ``.
+
+##### -external-mappings
+
+Сопоставление регулярных выражений, соответствующих записям пути к классам, и внешней документации.
+
+Пример внешнего сопоставления:
+`-external-mappings:.*scala.*::scaladoc3::https://scala-lang.org/api/3.x/,.*java.*::javadoc::https://docs.oracle.com/javase/8/docs/api/`
+
+Отображение имеет вид `::[scaladoc3|scaladoc|javadoc]::`.
+Можно указать несколько сопоставлений, разделенных запятыми, как показано в примере.
+
+##### -social-links
+
+Ссылки на социальные сети. Например:
+
+`-social-links:github::https://github.com/scala/scala3,discord::https://discord.com/invite/scala,twitter::https://x.com/scala_lang`
+
+Допустимые значения имеют вид: `[github|twitter|gitter|discord]::link`.
+Scaladoc также поддерживает `custom::link::white_icon_name::black_icon_name`.
+В этом случае иконки должны находиться в каталоге `images/`.
+
+##### -skip-by-id
+
+Идентификаторы пакетов или классов верхнего уровня, которые следует пропускать при создании документации.
+
+##### -skip-by-regex
+
+Регулярные выражения, соответствующие полным именам пакетов или классов верхнего уровня,
+которые следует пропускать при создании документации.
+
+##### -doc-root-content
+
+Файл, из которого следует импортировать документацию корневого пакета.
+
+##### -author
+
+Добавление авторов в строку документации `@author Name Surname` по умолчанию не будет включено в сгенерированную html-документацию.
+Если необходимо явно пометить классы авторами, scaladoc запускается с данным флагом.
+
+##### -groups
+
+Группировка похожих функций вместе (на основе аннотации `@group`)
+
+##### -private
+
+Показать все типы и члены. Если параметр не указан, показывать только `public` и `protected` типы и члены.
+
+##### -doc-canonical-base-url
+
+Базовый URL-адрес для использования в качестве префикса и добавления `canonical` URL-адресов на все страницы.
+Канонический URL-адрес может использоваться поисковыми системами для выбора URL-адреса,
+который вы хотите, чтобы люди видели в результатах поиска.
+Если не установлено, канонические URL-адреса не генерируются.
+
+##### -siteroot
+
+Каталог, содержащий статические файлы, из которых создается документация. Каталог по умолчанию - `./docs`
+
+##### -no-link-warnings
+
+Подавить предупреждения для двусмысленных или невалидных ссылок.
+Не влияет на предупреждения о некорректных ссылках ресурсов и т. д.
+
+##### -versions-dictionary-url
+
+URL-адрес, указывающий на документ JSON, содержащий словарь: `version label -> documentation location`.
+Файл JSON имеет единственное поле `versions`, которое содержит словарь,
+связывающий метки определенных версий документации с URL-адресами, указывающими на их `index.html`.
+Полезно для библиотек, которые поддерживают разные версии документации.
+
+Пример JSON-файла:
+
+```
+{
+ "versions": {
+ "3.0.x": "https://dotty.epfl.ch/3.0.x/docs/index.html",
+ "Nightly": "https://dotty.epfl.ch/docs/index.html"
+ }
+}
+```
+
+##### -snippet-compiler
+
+Аргументы компилятора фрагментов, позволяющие настроить проверку типа сниппета.
+
+Этот параметр принимает список аргументов в формате:
+`args := arg{,args} arg := [path=]flag`
+, где `path` - префикс пути к исходным файлам, в которых находятся сниппеты,
+и `flag` - режим проверки типов.
+
+Если `path` отсутствует, аргумент будет использоваться по умолчанию для всех несопоставленных путей.
+
+Доступные флаги:
+
+- `compile` — включает проверку фрагментов.
+- `nocompile` — отключает проверку сниппетов.
+- `fail` — включает проверку фрагмента, утверждает, что сниппет не компилируется.
+
+Флаг `fail` удобен для фрагментов, которые показывают,
+что какое-то действие в конечном итоге завершится ошибкой во время компиляции.
+
+Пример использования:
+
+`-snippet-compiler:my/path/nc=nocompile,my/path/f=fail,compile`
+
+Что значит:
+
+- все фрагменты в файлах в каталоге `my/path/nc` вообще не должны рассматриваться снипеттом
+- все фрагменты в файлах в каталоге `my/path/f` не должны компилироваться во время компиляции
+- все остальные фрагменты должны компилироваться успешно
+
+#### -scastie-configuration
+
+Определите дополнительную sbt конфигурацию для Scastie фрагментов кода.
+Например, когда вы импортируете внешние библиотеки в свои фрагменты,
+необходимо добавить соответствующие зависимости.
+
+```
+"-scastie-configuration", """libraryDependencies += "org.apache.commons" % "commons-lang3" % "3.12.0""""
+```
+
+##### -Ysnippet-compiler-debug
+
+Установка этого параметра заставляет компилятор фрагментов печатать сниппет по мере его компиляции (после упаковки).
+
+##### -Ydocument-synthetic-types
+
+Включение в документацию страниц с документацией по встроенным типам (например, `Any`, `Nothing`).
+Этот параметр полезен только для stdlib, поскольку scaladoc для Scala 3 использует файлы TASTy.
+Все остальные пользователи не должны касаться этой настройки.
diff --git a/_ru/scala3/guides/scaladoc/site-versioning.md b/_ru/scala3/guides/scaladoc/site-versioning.md
new file mode 100644
index 0000000000..fac5266a7c
--- /dev/null
+++ b/_ru/scala3/guides/scaladoc/site-versioning.md
@@ -0,0 +1,51 @@
+---
+layout: multipage-overview
+title: Версионирование сайта
+partof: scala3-scaladoc
+language: ru
+num: 6
+previous-page: blog
+next-page: search-engine
+---
+
+Scaladoc предоставляет удобный способ переключения между различными версиями документации.
+Эта функция полезна, когда желательно оставить старые версии документации пользователям,
+которые ещё не перешли на новую версию библиотеки.
+
+### Как это настроить
+
+Эта функция была разработана для легкой масштабируемости без необходимости повторного создания всех scaladocs
+после добавления новой версии. Для этого вводится новая настройка: `-versions-dictionary-url`.
+Его аргумент должен быть URL-адресом документа JSON, содержащего информацию о расположении конкретных версий.
+Файл JSON должен содержать свойство `versions` со словарём,
+связывающий метки определенных версий документации с URL-адресами, указывающими на их `index.html`.
+
+Пример JSON-файла:
+```
+{
+ "versions": {
+ "3.0.x": "https://dotty.epfl.ch/3.0.x/docs/index.html",
+ "Nightly": "https://dotty.epfl.ch/docs/index.html"
+ }
+}
+```
+
+Такие документы необходимо указывать для каждой из версий, однако позже это дает больше гибкости.
+Если необходимо добавить версию документов API рядом с предыдущими 5 версиями, которые уже опубликованы,
+нужно только загрузить новые документы на веб-сервер и добавить новую запись в файл JSON.
+Все версии сайта теперь узнают о новой версии.
+
+Важно отметить, что существует только один файл JSON, чтобы избежать избыточности,
+и каждый scaladoc должен заранее настроить свой URL-адрес, например, в sbt:
+
+```
+doc / scalacOptions ++= Seq("-versions-dictionary-url", "https://dotty.epfl.ch/versions.json")
+```
+
+
+### Как это выглядит с точки зрения пользователя
+
+Предоставление файла JSON через `-versions-dictionary-url` позволяет scaladoc связывать версии.
+Также удобно иметь возможность изменить метку ревизии в выпадающем меню. Все изменится автоматически.
+
+
diff --git a/_ru/scala3/guides/scaladoc/snippet-compiler.md b/_ru/scala3/guides/scaladoc/snippet-compiler.md
new file mode 100644
index 0000000000..adb2c0932c
--- /dev/null
+++ b/_ru/scala3/guides/scaladoc/snippet-compiler.md
@@ -0,0 +1,261 @@
+---
+layout: multipage-overview
+title: Проверка фрагмента
+partof: scala3-scaladoc
+language: ru
+num: 8
+previous-page: search-engine
+next-page: settings
+---
+
+Основная функциональность документации — помочь пользователям понять и правильно использовать проект.
+Иногда часть проекта нуждается в нескольких словах, чтобы показать ее использование,
+но бывают моменты, когда описания недостаточно, и нет ничего лучше, чем подробный пример.
+
+Удобный способ предоставления примеров в документации — создание фрагментов кода,
+представляющих использование заданной функциональности. Проблема фрагментов кода в том,
+что одновременно с разработкой проекта их нужно обновлять.
+Иногда изменения в одной части проекта могут нарушить работу примеров в других частях.
+Количество фрагментов и количество времени, прошедшего с момента их написания, не позволяет запомнить каждое место,
+где нужно их исправить. Через какое-то время наступает понимание, что документация — полный бардак
+и нужно пройтись по всем примерам и переписать их.
+
+Многие проекты Scala 2 используют markdown документацию с проверкой типов с помощью [tut](https://tpolecat.github.io/tut/)
+или [mdoc](https://scalameta.org/mdoc/). Почти все хотя бы слышали об этих инструментах.
+Поскольку они оказались очень полезными и сообщество Scala их успешно приняло,
+планируется включить функции tut и mdoc в компилятор, чтобы он был готов к включению в Scaladoc.
+
+
+
+## Начало работы
+
+По умолчанию проверка фрагментов отключена.
+Её можно включить, добавив в Scaladoc следующий аргумент:
+
+`-snippet-compiler:compile`
+
+Например, в sbt конфигурация выглядит так:
+
+```scala
+Compile / doc / scalacOptions ++= Seq("-snippet-compiler:compile")
+```
+
+Эта опция включает компилятор фрагментов для всех scala фрагментов в проектной документации и распознает все фрагменты внутри ``` блоков scala.
+В настоящее время проверка фрагментов работает как в строках документации, написанных в Markdown, так и на статических сайтах.
+
+
+Для нового проекта этой конфигурации должно хватить.
+Однако, если вы переносите существующий проект, можно отключить компиляцию для некоторых фрагментов,
+которые в настоящее время не могут быть обновлены.
+
+Для этого добавьте `nocompile` флаг прямо в scala фрагмент:
+
+````
+```scala sc:nocompile
+// under the hood `map` is transformed into
+List(1).map( _ + 1)()
+```
+````
+
+Однако иногда сбой компиляции является преднамеренным поведением, например, для демонстрации ошибки.
+В этом случае выставляется флаг `fail`, который представляет одну из функций: [Assert compilation errors](#assert-compilation-errors).
+
+````
+```scala sc:fail
+List(1,2,3).toMap
+```
+````
+
+Более подробное объяснение и более сложные настройки, такие как настройки флагов на основе пути,
+см. в разделе ["Расширенная конфигурация"](#расширенная-конфигурация).
+
+## Обзор функций
+
+### Assert compilation errors
+
+Scala — это язык программирования со статической типизацией.
+Иногда в документации должны упоминаться случаи, когда код не должен компилироваться,
+или авторы хотят предоставить способы восстановления после определенных ошибок компиляции.
+
+Например, этот код:
+
+```scala
+List(1,2,3).toMap
+```
+
+приводит к результату:
+
+```nohighlight
+
+At 18:21:
+ List(1,2,3).toMap
+Error: Cannot prove that Int <:< (K, V)
+
+where: K is a type variable with constraint
+ V is a type variable with constraint
+.
+```
+
+Примеры, представляющие код, который дает сбой во время компиляции, могут быть очень важными.
+Например, можно показать, как библиотека защищена от неправильного кода.
+Другой вариант использования — представить распространенные ошибки и способы их решения.
+Принимая во внимание эти варианты использования, предоставляется функция проверки того, компилируются ли отмеченные фрагменты кода.
+
+Для фрагментов кода, которые намеренно не компилируются, например следующего, добавьте флаг `fail` во фрагмент кода:
+
+````
+```scala sc:fail
+List(1,2,3).toMap
+```
+````
+Проверка фрагмента проходит успешно и показывает ожидаемые ошибки компиляции в документации.
+
+
+Для фрагмента, который компилируется без ошибок:
+````
+```scala sc:fail
+List((1,2), (2,3)).toMap
+```
+````
+результирующий вывод выглядит следующим образом:
+```nohighlight
+
+In static site (./docs/docs/index.md):
+Error: Snippet should not compile but compiled succesfully
+```
+
+
+### Контекст
+
+В Scaladoc внедрён механизм переноса, предоставляющий контекст для каждого фрагмента.
+Эта предварительная обработка выполняется автоматически для всех фрагментов в строках документации.
+
+Например, предположим, что необходимо задокументировать метод `slice` в файле `collection.List` для того,
+чтобы объяснить, как он работает, сравнив его с комбинацией методов `drop` и `take`, используя такой фрагмент кода:
+```scala
+slice(2, 5) == drop(2).take(3)
+```
+Показ этого примера — одна из первых вещей, которые приходят на ум, но он не скомпилируется без функции контекста.
+
+Помимо основной цели, это уменьшает шаблон фрагмента, потому что не нужно импортировать элементы одного и того же пакета
+и создавать экземпляры документированного класса.
+
+Фрагмент кода после предварительной обработки выглядит так:
+```scala
+package scala.collection
+trait Snippet[A] { self: List[A] =>
+ slice(2,5) == drop(2).take(3)
+}
+```
+
+### Скрытие кода
+
+Несмотря на наличие контекстной функции, описанной выше, иногда автору необходимо предоставить больше элементов
+для области действия. Однако, с одной стороны, большой блок импортов и инициализаций необходимых классов
+может привести к потере читабельности. Но с другой стороны, хотелось бы иметь возможность видеть весь код.
+Для второго случая введен специальный синтаксис для фрагментов,
+который скрывает определенные фрагменты `import` кода — операторы, например, — но также позволяет
+расширить этот код в документации одним щелчком мыши.
+
+Пример:
+
+```scala
+//{
+import scala.collection.immutable.List
+//}
+val intList: List[Int] = List(1, 2, 3)
+```
+
+
+
+### Включенные фрагменты
+
+При написании фрагментов кода часто требуется механизм повторного использования кода из одного фрагмента в другом.
+Например, взгляните на следующий фрагмент документации:
+
+
+Чтобы успешно скомпилировать последний фрагмент, нужно иметь ранее объявленные определения в области видимости.
+Для этого сценария — и, возможно, для многих других — добавлена новая функция: включение фрагмента.
+Она позволяет повторно использовать код из одного фрагмента в другом, что снижает избыточность и повышает удобство сопровождения.
+
+Чтобы настроить это, добавьте аргумент `sc-name` к фрагменту, который необходимо включить в более поздний блок кода:
+```` ```scala sc-name: ````
+
+, где `snippet-name` должен быть уникальным в пределах файла и не может содержать пробелы и запятые.
+
+Затем в более позднем блоке кода в документации используйте аргумент `sc-compile-with` в scala фрагменте,
+который должен “включать” предыдущий блок кода:
+```` ```scala sc-compile-with:(,)+ ````
+
+, где `snippet-name` - имя фрагмента, который должен быть включен.
+
+После настройки этой функции в примере код выглядит так:
+
+
+и вывод выглядит так:
+
+
+Можно указать более одного включения. Обратите внимание, что порядок, в котором они указаны, определяет порядок включения.
+
+**Замечание**: можно включать только фрагменты, определенные над целевым фрагментом.
+
+## Расширенная конфигурация
+
+Часто включение проверки фрагментов для _всех_ фрагментов не является желаемым уровнем контроля,
+поскольку варианты использования могут быть более сложными. Для таких ситуаций подготовлен инструмент,
+чтобы пользователи могли настроить его под свои нужды.
+
+### Доступные флаги
+
+Чтобы обеспечить больший контроль, компилятор фрагмента предоставляет три флага, которые позволяют изменить его поведение:
+- `compile` - включает проверку фрагментов
+- `nocompile` - отключает проверку фрагментов
+- `fail` - включает проверку фрагментов с подтверждением ошибки компиляции
+
+### Настройки на основе пути
+
+Для большей гибкости вместо установки одного флага для управления всеми фрагментами кода в проекте
+его можно установить только для определенного пути, добавив префикс `=` перед флагом. Например:
+
+`-snippet-compiler:docs=compile` - устанавливает флаг `compile` для фрагментов в `docs`.
+
+Если `docs` - это каталог, флаг устанавливается для всех файлов внутри `docs`.
+
+Кроме того, `-snippet-compiler` может управляться более чем одним параметром, при этом параметры разделяются запятыми.
+Например:
+```
+-snippet-compiler:docs=compile,library/src=compile,library/src/scala/quoted=nocompile,library/src/scala/compiletime=fail
+```
+Флаги выбираются по самому длинному совпадению префикса, поэтому можно определить общую настройку,
+а затем изменить это поведение по умолчанию для более конкретных путей.
+```
+-snippet-compiler:compile,library/src/scala/quoted=nocompile,library/src/scala/compiletime=fail
+```
+Флаг без префикса пути, такой как флаг `compile` в этом примере, считается значением по умолчанию.
+
+### Переопределение прямо во фрагменте
+
+Аргументы CLI — хороший механизм для установки флагов для определенных файлов.
+Однако этот подход нельзя использовать для настройки определенных фрагментов.
+Допустим, необходимо написать один фрагмент кода, который должен потерпеть неудачу,
+и другие фрагменты, которые должны скомпилироваться.
+Эти аргументы находятся в информационной части блока кода:
+
+````
+```scala
+// snippet
+```
+````
+
+Например, чтобы настроить проверку для определенного фрагмента, добавьте следующий аргумент в его информационную часть фрагмента,
+где `flag` - один из доступных флагов, перечисленных выше (например, `compile`, `nocompile` или `fail`):
+
+`sc:`
+
+В качестве конкретного примера этот код показывает, как использовать флаг `fail` в отдельном фрагменте:
+
+````
+```scala sc:fail
+val itShouldFail: Int = List(1.1, 2, 3).head
+```
+````
diff --git a/_ru/scala3/guides/scaladoc/static-site.md b/_ru/scala3/guides/scaladoc/static-site.md
new file mode 100644
index 0000000000..2249f88ffe
--- /dev/null
+++ b/_ru/scala3/guides/scaladoc/static-site.md
@@ -0,0 +1,296 @@
+---
+layout: multipage-overview
+title: Статическая документация
+partof: scala3-scaladoc
+language: ru
+num: 4
+previous-page: linking
+next-page: blog
+---
+
+Scaladoc умеет генерировать статические сайты, известные по [Jekyll](http://jekyllrb.com/) или [Docusaurus](https://docusaurus.io/).
+Наличие комбинированного инструмента позволяет обеспечить взаимодействие между статической документацией
+и API, что позволяет им естественным образом сочетаться.
+
+Создать сайт так же просто, как и в Jekyll. Корень сайта содержит макет сайта,
+и все файлы, размещенные там, будут либо считаться статическими, либо обрабатываться для расширения шаблона.
+
+Файлы, которые рассматриваются для расширения шаблона, должны заканчиваться на `*.{html,md}`
+и в дальнейшем будут называться "файлами шаблонов" или "шаблонами".
+
+Простой сайт "Hello World" может выглядеть примерно так:
+
+```
+.
+└── /
+ └── _docs/
+ ├── index.html
+ └── getting-started.html
+```
+
+Что даст сайт со следующими файлами в сгенерированной документации:
+
+```
+index.html
+getting-started.html
+```
+
+Scaladoc может преобразовывать как файлы, так и каталоги (чтобы организовать документацию в древовидную структуру).
+По умолчанию каталоги имеют заголовок, основанный на имени файла, с пустым содержимым.
+Можно предоставить индексные страницы для каждого раздела, создав `index.html` или `index.md` (но не одновременно) в выделенном каталоге.
+
+Имейте в виду, что для локального просмотра вашего сайта со всеми его функциями, такими как поиск или фрагменты,
+требуется локальный сервер. Например, если ваш выходной каталог - `output`,
+вы можете использовать python сервер для просмотра всего, выполнив следующие действия и открыв `localhost:8080`:
+
+```sh
+cd output
+python3 -m http.server 8080
+```
+
+## Характеристики
+
+Scaladoc использует механизм шаблонов [Liquid](https://shopify.github.io/liquid/)
+и предоставляет несколько настраиваемых фильтров и тегов, характерных для документации Scala.
+
+В Scaladoc все шаблоны могут содержать вступительную часть YAML.
+Передняя часть анализируется и помещается в переменную `page`, доступную в шаблонах через Liquid.
+
+Пример вступительной статьи:
+
+```
+---
+title: My custom title
+---
+```
+
+Scaladoc использует некоторые предопределенные свойства для управления аспектами страницы.
+
+Предустановленные свойства:
+
+- **title** - обеспечивает заголовок страницы, который будет использоваться в навигации и метаданных HTML.
+- **extraCss** - дополнительные файлы `.css`, которые будут включены в эту страницу.
+ Пути должны указываться относительно корня документации. **Этот параметр не экспортируется в механизм шаблонов.**
+- **extraJs** - дополнительные файлы `.js`, которые будут включены в эту страницу.
+ Пути должны указываться относительно корня документации. **Этот параметр не экспортируется в механизм шаблонов.**
+- **hasFrame** - если установлено значение `false`, страница не будет включать макет по умолчанию (навигацию, breadcrumbs и т.д.),
+ а только токен-оболочку HTML для предоставления метаданных и ресурсов (файлы js и css). **Этот параметр не экспортируется в механизм шаблонов.**
+- **layout** - предопределенный макет для использования, см. ниже. **Этот параметр не экспортируется в механизм шаблонов.**
+
+Свойства перенаправления:
+
+В дополнение к предустановленным свойствам, Scaladoc также поддерживает свойства перенаправления,
+которые позволяют вам перенаправлять с одной страницы на другую.
+Это может быть полезно, когда вы перемещаете страницу на новое место,
+но хотите, чтобы старый URL-адрес работал.
+
+- **redirectFrom** - указывает на URL-адрес, с которого вы хотите выполнить перенаправление.
+ Используя свойство `redirectFrom`, Scaladoc создает пустую страницу по этому URL-адресу,
+ который включает браузерное перенаправление на текущую страницу.
+
+Пример:
+
+```
+---
+redirectFrom: /absolute/path/to/old/url.html
+---
+```
+
+В приведенном выше примере,
+если вы перемещаете страницу из `/absolute/path/to/old/url.html` на новое место,
+то вы можете использовать `redirectFrom`, чтобы убедиться,
+что старый URL-адрес по-прежнему перенаправляет на новое место.
+
+Обратите внимание, что свойство `redirectFrom` было вдохновлено плагином Jekyll под названием
+[`jekyll-redirect-from`](https://github.com/jekyll/jekyll-redirect-from).
+
+- **redirectTo** — указывает URL-адрес, на который вы хотите перенаправить с текущей страницы.
+ Это свойство полезно, когда вы хотите перенаправить на внешнюю страницу
+ или когда нельзя использовать `redirectFrom`.
+
+Пример:
+
+```
+---
+redirectTo: https://docs.scala-lang.org/
+---
+```
+
+В приведенном выше примере страница будет перенаправлена на https://docs.scala-lang.org/.
+
+## Использование существующих шаблонов и макетов
+
+Чтобы выполнить расширение шаблона, Dottydoc просматривает поле `layout` во вступительной части.
+Вот простой пример системы шаблонов в действии `index.html`:
+
+```html
+---
+layout: main
+---
+
+
Hello world!
+```
+
+С таким простым основным шаблоном, как этот:
+
+{% raw %}
+
+```html
+
+
+ Hello, world!
+
+
+ {{ content }}
+
+
+```
+
+`{{ content }}` будет заменен на `
Hello world!
` в файле `index.html`.
+{% endraw %}
+
+Макеты должны быть размещены в каталоге `_layouts` в корне сайта:
+
+```
+├── _layouts
+│ └── main.html
+└── _docs
+ ├── getting-started.md
+ └── index.html
+```
+
+## Ресурсы
+
+Чтобы рендерить ассеты вместе со статическим сайтом, их нужно поместить в директорию `_assets` в корне сайта:
+
+```
+├── _assets
+│ └── images
+│ └── myimage.png
+└── _docs
+ └── getting-started.md
+```
+
+Чтобы сослаться на ресурс на странице, необходимо создать ссылку относительно каталога `_assets`.
+
+```
+Take a look at the following image: [My image](images/myimage.png)
+```
+
+## Боковая панель
+
+По умолчанию Scaladoc отображает структуру каталогов из каталога `_docs` на визуализируемом сайте.
+Существует также возможность переопределить его, предоставив файл `sidebar.yml` в корневом каталоге сайта.
+Конфигурационный файл YAML описывает структуру отображаемого статического сайта и оглавление:
+
+```yaml
+index: index.html
+subsection:
+ - title: Usage
+ index: usage/index.html
+ directory: usage
+ subsection:
+ - title: Dottydoc
+ page: usage/dottydoc.html
+ hidden: false
+ - title: sbt-projects
+ page: usage/sbt-projects.html
+ hidden: false
+```
+
+Корневой элемент должен быть `subsection`.
+Вложенные подразделы приведут к древовидной структуре навигации.
+
+Свойства `subsection`:
+
+- `title` - Необязательная строка - заголовок подраздела по умолчанию.
+ Вступительные заголовки имеют более высокий приоритет.
+- `index` - Необязательная строка - Путь к индексной странице подраздела. Путь указан относительно каталога `_docs`.
+- `directory` - Необязательная строка - Имя каталога, в котором будет находиться подраздел сгенерированного сайта.
+ По умолчанию именем каталога является имя подраздела, преобразованное в kebab case.
+- `subsection` - Массив `subsection` или `page`.
+
+Либо `index`, либо `subsection` должны быть определены. Подраздел, определенный с `index` и без `subsection`,
+будет содержать страницы и каталоги, загружаемые рекурсивно из каталога индексной страницы.
+
+Свойства `page`:
+
+- `title` - Необязательная строка - заголовок страницы по умолчанию. Вступительные заголовки имеют более высокий приоритет.
+- `page` - Строка - Путь к странице относительно каталога `_docs`.
+- `hidden` - Необязательное логическое значение. Флаг, указывающий, должна ли страница отображаться на боковой панели навигации.
+ По умолчанию установлено значение `false`.
+
+**Заметка**: Все пути в файле конфигурации YAML относятся к `/_docs`.
+
+## Иерархия title
+
+Если заголовок указан несколько раз, приоритет будет следующим (от высшего к низшему приоритету):
+
+#### Страница
+
+1. `title` из `front-matter` файла markdown/html
+2. `title` свойство из `sidebar.yml`
+3. имя файла
+
+#### Подраздел
+
+1. `title` из `front-matter` индексного файла markdown/html
+2. `title` свойство из `sidebar.yml`
+3. имя файла
+
+Обратите внимание, что если пропустить `index` файл в древовидной структуре или не указать `title` во вступительной части,
+ему будет присвоено общее имя `index`. То же самое относится к использованию `sidebar.yml`,
+но не указанию ни `title`, ни `index`, а только подраздела. Снова появится общее имя `index`.
+
+## Блог
+
+Функция блога описана в [отдельном документе](/ru/scala3/guides/scaladoc/blog.html).
+
+## Расширенная конфигурация
+
+### Полная структура корня сайта
+
+```
+.
+└── /
+ ├── _layouts/
+ │ └── ...
+ ├── _docs/
+ │ └── ...
+ ├── _blog/
+ │ ├── index.md
+ │ └── _posts/
+ │ └── ...
+ └── _assets/
+ ├── js/
+ │ └── ...
+ ├── img/
+ │ └── ...
+ └── ...
+```
+
+В результате получается статический сайт, содержащий документы, а также блог.
+Он также содержит пользовательские макеты и ассеты.
+Структура визуализируемой документации может быть основана на файловой системе, но также может быть переопределена конфигурацией YAML.
+
+### Структура каталогов сопоставления
+
+Используя файл конфигурации YAML, можно определить, как структура исходного каталога должна быть преобразована в структуру выходного каталога.
+
+Взглянем на следующее определение подраздела:
+
+```yaml
+- title: Some other subsection
+ index: abc/index.html
+ directory: custom-directory
+ subsection:
+ - page: abc2/page1.md
+ - page: foo/page2.md
+```
+
+В этом подразделе показана возможность конфигурации YAML отображать структуру каталогов.
+Несмотря на то, что индексная страница и все определенные дочерние элементы находятся в разных каталогах,
+они будут рендериться в `custom-directory`.
+Исходная страница `abc/index.html` будет генерировать страницу `custom-directory/index.html`,
+исходная страница `abc2/page1.md` - `custom-directory/page1.html`,
+а исходная страница `foo/page2.md` - `custom-directory/page2.html`.
diff --git a/_ru/scala3/new-in-scala3.md b/_ru/scala3/new-in-scala3.md
new file mode 100644
index 0000000000..d4d4ce0773
--- /dev/null
+++ b/_ru/scala3/new-in-scala3.md
@@ -0,0 +1,184 @@
+---
+layout: singlepage-overview
+title: Новое в Scala 3
+partof: scala3-scaladoc
+scala3: true
+language: ru
+---
+
+Захватывающая новая версия Scala 3 содержит множество новых функций и улучшений.
+Здесь мы представляем вам краткий обзор наиболее важных изменений.
+Если вы хотите копнуть глубже, то в вашем распоряжении несколько ссылок:
+
+- [Книга Scala 3]({% link _overviews/scala3-book/introduction.md %}) предназначена для разработчиков, только знакомящихся с языком Scala.
+- [Обзор синтаксиса][syntax-summary] содержит формальное описание нового синтаксиса.
+- [Справочник по языку][reference] дает подробное описание изменений Scala 3 по сравнению со Scala 2.
+- [Руководство по миграции][migration] содержит всю информацию, необходимую для перехода со Scala 2 на Scala 3.
+- [Scala 3 Contributing Guide][contribution] более подробно рассказывает о компиляторе, включая руководство по исправлению проблем.
+
+## Что нового Scala 3
+Scala 3 — это полная переработка языка Scala.
+По сути, многие аспекты системы типов были изменены, чтобы сделать их более последовательными.
+Хотя эта версия также приносит интересные новые функции (например, типы объединения),
+в первую очередь это означает, что система типов становится (даже) малозаметнее на вашем пути,
+и, например, [вывод типов][type-inference] с перегрузкой значительно улучшаются.
+
+### Новое и яркое: синтаксис
+Помимо многих (незначительных) чисток, синтаксис Scala 3 предлагает следующие улучшения:
+
+- Новый "тихий" синтаксис для структур управления, таких как `if`, `while` и `for` ([новый синтаксис управления][syntax-control])
+- Ключевое слово `new` теперь является необязательным (_например_ [для создания экземпляров][creator])
+- [Опциональные фигурные скобки][syntax-indentation] поддерживающие стиль программирования, не отвлекающий внимание и чувствительный к отступам
+- Изменение [подстановочных знаков типа][syntax-wildcard] с `_` на `?`.
+- Имплициты (и их синтаксис) были [значительно переработаны][implicits].
+
+### Последовательное: контекстуальные абстракции
+Одной из основных концепций Scala было (и до некоторой степени до сих пор является)
+предоставление пользователям небольшого набора мощных функций,
+которые можно комбинировать для достижения большей (а иногда даже непредусмотренной) выразительности.
+Например, функциональность _имплицитов_ использовалась для моделирования контекстной абстракции,
+для выражения вычислений на уровне типов, моделирования классов типов, выполнения неявных преобразований,
+кодирования методов расширения и многого другого.
+Извлекая уроки из этих вариантов использования, Scala 3 использует несколько иной подход
+и фокусируется на **намерении**, а не на **механизме**.
+Вместо того чтобы предлагать одну очень мощную функцию,
+Scala 3 предлагает несколько специализированных языковых функций,
+позволяющих программистам напрямую выражать свои намерения:
+
+- **Абстрагирование контекстной информации**. [Using предложения][contextual-using] позволяют программистам абстрагироваться от информации,
+ которая доступна в контексте вызова и должна передаваться неявно.
+ В качестве улучшения по сравнению с имплицитами в Scala 2 предложения _using_ могут указываться по типу,
+ освобождая сигнатуры функций от имен переменных, если на них не ссылаются явно.
+
+- **Предоставление экземпляров классов типов**. [Экземпляры given][contextual-givens] позволяют программистам определять
+ каноническое значение определенного типа. Это делает программирование с классами типов более простым без распространения деталей реализации.
+
+- **Расширение классов задним числом**. В Scala 2 методы расширения должны были быть закодированы с использованием
+ неявных преобразований или неявных классов. Напротив, в Scala 3 [методы расширения][contextual-extension]
+ теперь встроены непосредственно в язык, что приводит к более качественным сообщениям об ошибках и улучшенному выводу типов.
+
+- **Просмотр одного типа как другого**. Неявные преобразования между типами были [переработаны][contextual-conversions] с нуля как экземпляры класса типов `Conversion`.
+
+- **Высокоуровневые контекстные абстракции**. _Совершенно новая_ особенность [контекстных функций][contextual-functions] делает контекстные абстракции функциями первого класса.
+ Они являются важным инструментом для авторов библиотек и позволяют кратко выражать предметно-ориентированные языки.
+
+- **Полезная обратная связь от компилятора**. Если компилятор не может разрешить неявный параметр,
+ теперь он предоставляет [предложения по импорту](https://www.scala-lang.org/blog/2020/05/05/scala-3-import-suggestions.html), которые могут решить проблему.
+
+### Говори, что имеешь в виду: улучшения системы типов
+Помимо значительно улучшенного вывода типов, система типов Scala 3 также предлагает множество новых функций,
+предоставляя вам мощные инструменты для статического выражения инвариантов в типах:
+
+- **Перечисления**. [Enums][enums] были переработаны, чтобы хорошо сочетаться с case-классами
+ и формировать новый стандарт для выражения [алгебраических типов данных][enums-adts].
+
+- **Непрозрачные типы**. Скройте детали реализации за [непрозрачными псевдонимами типов][types-opaque], не платя за это производительностью!
+ Непрозрачные типы заменяют классы значений и позволяют установить барьер абстракции, не вызывая дополнительных накладных расходов на упаковку.
+
+- **Типы пересечения и объединения**. Основание системы типов на новом фундаменте привело к введению новых функций системы типов:
+ экземпляры [типов-пересечений][types-intersection], например `A & B`, являются экземплярами обоих типов `A` и `B`.
+ Экземпляры [типов объединения][types-union], например `A | B`, являются экземплярами либо `A`, либо `B`.
+ Обе конструкции позволяют программистам гибко выражать ограничения типов вне иерархии наследования.
+
+- **Зависимые типы функций**. Scala 2 уже позволяла возвращаемым типам зависеть от (значения) аргументов.
+ В Scala 3 теперь можно абстрагироваться от этого шаблона и выразить [зависимые типы функций][types-dependent].
+ В типе `type F = (e: Entry) => e.Key` тип результата зависит от аргумента!
+
+- **Полиморфные типы функций**. Как и в случае с зависимыми типами функций, Scala 2 поддерживала методы,
+ допускающие параметры типа, но не позволяла программистам абстрагироваться от этих методов.
+ В Scala 3 [полиморфные типы функций][types-polymorphic], например, `[A] => List[A] => List[A]`
+ могут абстрагироваться от функций, которые принимают аргументы типа в дополнение к своим аргументам значения.
+
+- **Лямбда-типы**. То, что нужно было выразить с помощью [плагина компилятора](https://github.com/typelevel/kind-projector) в Scala 2,
+ теперь является функцией первого класса в Scala 3: лямбда-выражения типов — это функции уровня типа,
+ которые можно передавать как аргументы (более высокого типа), не требуя определения вспомогательного типа.
+
+- **Сопоставление типов**. Вместо кодирования вычислений на уровне типов с использованием неявного разрешения,
+ Scala 3 предлагает прямую поддержку [сопоставления типов][types-match].
+ Интеграция вычислений на уровне типов в средство проверки типов позволяет улучшить сообщения об ошибках
+ и устраняет необходимость в сложных кодировках.
+
+
+### Переосмысление: объектно-ориентированное программирование
+Scala всегда была на границе между функциональным программированием и объектно-ориентированным программированием,
+а Scala 3 расширяет границы в обоих направлениях!
+Вышеупомянутые изменения системы типов и редизайн контекстных абстракций делают _функциональное программирование_ проще, чем раньше.
+В то же время следующие новые функции позволяют создавать хорошо структурированные _объектно-ориентированные проекты_
+и поддерживают best practices.
+
+- **Передача параметров**. Трейты становятся ближе к классам и теперь также могут принимать [параметры][oo-trait-parameters],
+ что делает их еще более мощным средством модульной декомпозиции программного обеспечения.
+- **Планирование расширения**. Наследование классов, которые не предназначены для расширения,
+ является давней проблемой объектно-ориентированного проектирования.
+ Чтобы решить эту проблему, [открытые классы][oo-open] требуют, чтобы разработчики библиотек _явно_ помечали классы как открытые.
+- **Скрытие деталей реализации**. Вспомогательные трейты, которые реализуют поведение, иногда не должны быть частью вывода типов.
+ В Scala 3 эти трейты могут быть помечены как [прозрачные][oo-transparent], скрывающие наследование от пользователя (в выводимых типах).
+- **Композиция над наследованием**. Эта фраза часто цитируется, но утомительна для реализации.
+ Не так обстоит дело с [export предложениями][oo-export] в Scala 3 : симметричные по отношению к импорту,
+ предложения export позволяют пользователю определять псевдонимы для выбранных членов объекта.
+- **Больше никаких NullPointerException (экспериментально)**. Scala 3 безопаснее, чем когда-либо:
+ [явное значение null][oo-explicit-null] выводит `null` из иерархии типов, помогая статически отлавливать ошибки;
+ дополнительные проверки для [безопасной инициализации][oo-safe-init] обнаруживают попытки доступа к неинициализированным объектам.
+
+### Зарядка в комплекте: метапрограммирование
+В то время как макросы в Scala 2 были только экспериментальной функцией,
+Scala 3 поставляется с мощным арсеналом инструментов для метапрограммирования.
+[Учебник по макросам]({% link _overviews/scala3-macros/tutorial/index.md %}) содержит подробную информацию о различных возможностях.
+В частности, Scala 3 предлагает следующие функциональности для метапрограммирования:
+
+- **Inline**. В качестве базовой отправной точки [функция inline][meta-inline] позволяет редуцировать значения и методы во время компиляции.
+ Эта простая функция уже охватывает множество вариантов использования
+ и в то же время обеспечивает отправную точку для более продвинутых функций.
+- **Операции времени компиляции**. Пакет [`scala.compiletime`][meta-compiletime] содержит дополнительные функции,
+ которые можно использовать для реализации inline методов.
+- **Блоки кода Quoted**. В Scala 3 добавлена новая функция [квазицитирования кода][meta-quotes],
+ обеспечивающая удобный высокоуровневый интерфейс для создания и анализа кода.
+ Создать код для добавления единицы к единице так же просто, как `'{ 1 + 1 }`.
+- **Reflection API**. Для более продвинутых вариантов использования [quotes.reflect][meta-reflection]
+ предоставляет более детализированный контроль для проверки и создания деревьев программ.
+
+Если вы хотите узнать больше о метапрограммировании в Scala 3, приглашаем вас пройти наш [tutorial][meta-tutorial].
+
+
+[enums]: {{ site.scala3ref }}/enums/enums.html
+[enums-adts]: {{ site.scala3ref }}/enums/adts.html
+
+[types-intersection]: {{ site.scala3ref }}/new-types/intersection-types.html
+[types-union]: {{ site.scala3ref }}/new-types/union-types.html
+[types-dependent]: {{ site.scala3ref }}/new-types/dependent-function-types.html
+[types-lambdas]: {{ site.scala3ref }}/new-types/type-lambdas.html
+[types-polymorphic]: {{ site.scala3ref }}/new-types/polymorphic-function-types.html
+[types-match]: {{ site.scala3ref }}/new-types/match-types.html
+[types-opaque]: {{ site.scala3ref }}/other-new-features/opaques.html
+
+[type-inference]: {{ site.scala3ref }}/changed-features/type-inference.html
+[overload-resolution]: {{ site.scala3ref }}/changed-features/overload-resolution.html
+[reference]: {{ site.scala3ref }}/overview.html
+[creator]: {{ site.scala3ref }}/other-new-features/creator-applications.html
+[migration]: {% link _overviews/scala3-migration/compatibility-intro.md %}
+[contribution]: {% link _overviews/scala3-contribution/contribution-intro.md %}
+
+[implicits]: {{ site.scala3ref }}/contextual
+[contextual-using]: {{ site.scala3ref }}/contextual/using-clauses.html
+[contextual-givens]: {{ site.scala3ref }}/contextual/givens.html
+[contextual-extension]: {{ site.scala3ref }}/contextual/extension-methods.html
+[contextual-conversions]: {{ site.scala3ref }}/contextual/conversions.html
+[contextual-functions]: {{ site.scala3ref }}/contextual/context-functions.html
+
+[syntax-summary]: {{ site.scala3ref }}/syntax.html
+[syntax-control]: {{ site.scala3ref }}/other-new-features/control-syntax.html
+[syntax-indentation]: {{ site.scala3ref }}/other-new-features/indentation.html
+[syntax-wildcard]: {{ site.scala3ref }}/changed-features/wildcards.html
+
+[meta-tutorial]: {% link _overviews/scala3-macros/tutorial/index.md %}
+[meta-inline]: {% link _overviews/scala3-macros/tutorial/inline.md %}
+[meta-compiletime]: {% link _overviews/scala3-macros/tutorial/compiletime.md %}
+[meta-quotes]: {% link _overviews/scala3-macros/tutorial/quotes.md %}
+[meta-reflection]: {% link _overviews/scala3-macros/tutorial/reflection.md %}
+
+[oo-explicit-null]: {{ site.scala3ref }}/experimental/explicit-nulls.html
+[oo-safe-init]: {{ site.scala3ref }}/other-new-features/safe-initialization.html
+[oo-trait-parameters]: {{ site.scala3ref }}/other-new-features/trait-parameters.html
+[oo-open]: {{ site.scala3ref }}/other-new-features/open-classes.html
+[oo-transparent]: {{ site.scala3ref }}/other-new-features/transparent-traits.html
+[oo-export]: {{ site.scala3ref }}/other-new-features/export.html
diff --git a/_ru/scala3/scaladoc.md b/_ru/scala3/scaladoc.md
new file mode 100644
index 0000000000..9c3df2e7fe
--- /dev/null
+++ b/_ru/scala3/scaladoc.md
@@ -0,0 +1,108 @@
+---
+layout: singlepage-overview
+title: Новые возможности Scaladoc
+partof: scala3-scaladoc
+scala3: true
+language: ru
+---
+
+Новая версия Scala 3 поставляется со совершенно новой реализацией генератора документации _Scaladoc_, переписанной с нуля.
+В этой статье вы можете найти основные сведения о новых функциях, которые уже есть или будут представлены в Scaladoc.
+Для общей справки см. руководство по [Scaladoc][scaladoc].
+
+## Новая функциональность
+
+### Markdown синтаксис
+
+Самым большим изменением, представленным в новой версии Scaladoc, является изменение языка по умолчанию для строк документации.
+До сих пор Scaladoc поддерживал только синтаксис Wikidoc.
+Новый Scaladoc по-прежнему может анализировать устаревший синтаксис `Wikidoc`,
+однако Markdown был выбран в качестве основного языка для форматирования комментариев.
+Чтобы переключиться обратно на `Wikidoc`, можно передать глобальный параметр перед запуском задачи `doc`
+или определить его для конкретных комментариев с помощью директивы `@syntax wiki`.
+
+Для получения дополнительной информации о том, как использовать все возможности документации,
+ознакомьтесь с [документацией Scaladoc][scaladoc-docstrings].
+
+### Статический сайт
+
+Scaladoc также предоставляет простой способ создания **статических сайтов** как для документации,
+так и для сообщений в блогах, подобно тому, как это делает Jekyll.
+Благодаря этой функциональности вы можете очень удобно хранить свою документацию вместе со сгенерированным Scaladoc API.
+
+Для получения дополнительной информации о том, как настроить создание статических сайтов,
+ознакомьтесь с главой [Статическая документация][static-documentation].
+
+
+
+### Посты в блоге
+
+Посты в блогах — это особый тип статических сайтов. В руководстве по работе со Scaladoc
+вы можете найти дополнительную информацию о том, как работать с [сообщениями в блогах][built-in-blog].
+
+
+
+### Ссылки на соцсети
+
+Кроме того, Scaladoc предоставляет простой способ настроить [ссылки на социальные сети][social-links], например Twitter или Discord.
+
+{: style="width: 180px"}
+
+## Экспериментальные функции
+
+Следующие функции в настоящее время (май 2021 г.) не являются стабильными для выпуска в scaladoc,
+однако мы рады услышать ваши отзывы.
+У каждой функции есть отдельная ветка на сайте авторов scala-lang, где вы можете поделиться своим мнением.
+
+### Компиляция фрагментов
+
+Одной из экспериментальных возможностей Scaladoc является компилятор фрагментов кода.
+Этот инструмент позволит вам компилировать фрагменты, которые вы прикрепляете к своей строке документации,
+чтобы проверить, действительно ли они ведут себя так, как предполагалось, например, правильно ли компилируются.
+Эта функция очень похожа на инструменты `tut` или `mdoc`, но будет поставляться вместе со Scaladoc,
+что упрощает настройку и интеграцию в ваш проект.
+Создание интерактивных фрагментов — например, предоставление пользователям возможности редактировать
+и компилировать их в браузере — находится на рассмотрении. Но в настоящее время эта функция пока не рассматривается.
+
+Демонстрация:
+* Скрытие кода 
+* Проверка ошибок компиляции 
+* Включение фрагментов 
+
+Для получения дополнительной информации см. [Руководства][snippet-compiler]
+или следите за этой веткой [Scala Contributors](https://contributors.scala-lang.org/t/snippet-validation-in-scaladoc-for-scala-3/4976).
+
+### Поиск по типу
+
+Поиск функций по их символическим именам может занять много времени.
+Вот почему новый scaladoc позволяет искать методы и поля по их типам.
+
+Итак, для объявления:
+
+```
+extension [T](arr: IArray[T]) def span(p: T => Boolean): (IArray[T], IArray[T]) = ...
+```
+
+Вместо поиска по `span` мы также можем искать по `IArray[A] => (A => Boolean) => (IArray[A], IArray[A])`.
+
+Чтобы использовать эту функциональность, просто введите сигнатуру функции, которую ищете, в строке поиска scaladoc.
+Вот как это работает:
+
+
+
+Эта функция предоставляется поисковой системой [Inkuire](https://github.com/VirtusLab/Inkuire), которая работает для Scala 3 и Kotlin.
+Чтобы быть в курсе развития этой функции, следите за репозиторием [Inkuire](https://github.com/VirtusLab/Inkuire).
+
+Для получения дополнительной информации см. [соответствующую главу][search-engine]
+
+Обратите внимание, что эта функция все еще находится в разработке, поэтому в нее могут быть внесены значительные изменения.
+Если вы столкнулись с ошибкой или у вас есть идея для улучшения, не стесняйтесь создавать issue на
+[Inkuire](https://github.com/VirtusLab/Inkuire/issues/new) или [dotty](https://github.com/scala/scala3/issues/new).
+
+[scaladoc]: /ru/scala3/guides/scaladoc/index.html
+[scaladoc-docstrings]: /ru/scala3/guides/scaladoc/docstrings.html
+[static-documentation]: /ru/scala3/guides/scaladoc/static-site.html
+[built-in-blog]: /ru/scala3/guides/scaladoc/blog.html
+[social-links]: /ru/scala3/guides/scaladoc/settings.html#-social-links
+[search-engine]: /ru/scala3/guides/scaladoc/search-engine.html
+[snippet-compiler]: /ru/scala3/guides/scaladoc/snippet-compiler.html
diff --git a/_ru/scala3/talks.md b/_ru/scala3/talks.md
new file mode 100644
index 0000000000..25fce82809
--- /dev/null
+++ b/_ru/scala3/talks.md
@@ -0,0 +1,73 @@
+---
+layout: singlepage-overview
+title: Обсуждения
+partof: scala3-scaladoc
+scala3: true
+language: ru
+versionSpecific: true
+---
+
+Серия "Давайте поговорим о Scala 3"
+-------------------------------
+
+[Давайте поговорим о Scala 3](https://www.youtube.com/playlist?list=PLTx-VKTe8yLxYQfX_eGHCxaTuWvvG28Ml) — это серия
+коротких (около 15 минут) докладов о Scala 3. Они охватывают различные темы, например, как начать работу,
+как воспользоваться преимуществами новых языковых функций или как перейти со Scala 2.
+
+Обсуждения Scala 3
+----------------
+- (ScalaDays 2019, Lausanne) [Тур по Scala 3](https://www.youtube.com/watch?v=_Rnrx2lo9cw) от [Martin Odersky](http://x.com/odersky)
+
+- (ScalaDays 2016, Berlin) [Развитие Scala](https://www.youtube.com/watch?v=GHzWqJKFCk4) от [Martin Odersky](http://x.com/odersky) [\[слайды\]](http://www.slideshare.net/Odersky/scala-days-nyc-2016)
+
+- (JVMLS 2015) [Компиляторы — это базы данных](https://www.youtube.com/watch?v=WxyyJyB_Ssc) от [Martin Odersky](http://x.com/odersky) [\[слайды\]](http://www.slideshare.net/Odersky/compilers-are-databases)
+
+- (Scala World 2015) [Dotty: изучение будущего Scala](https://www.youtube.com/watch?v=aftdOFuVU1o) от [Dmitry Petrashko](http://x.com/darkdimius) [\[слайды\]](https://d-d.me/scalaworld2015/#/).
+ Дмитрий рассказывает о многих новых функциях, которые предлагает Dotty, таких как типы пересечения и объединения,
+ улучшенная инициализация lazy val и многое другое. Дмитрий также рассказывает о внутреннем устройстве Dotty
+ и, в частности, о высоком уровне контекстных абстракций Dotty.
+ Вы познакомитесь со многими основными понятиями, такими как `Denotations`, их эволюция во времени (компиляции),
+ их преобразования и многое другое.
+
+Глубокое погружение в Scala 3
+----------------------
+- (ScalaDays 2019, Lausanne) [Метапрограммирование в Dotty](https://www.youtube.com/watch?v=ZfDS_gJyPTc) от [Nicolas Stucki](https://github.com/nicolasstucki).
+
+- (ScalaDays 2019, Lausanne) [Scala, ориентированная на будущее: промежуточное представление TASTY](https://www.youtube.com/watch?v=zQFjC3zLYwo) от [Guillaume Martres](http://guillaume.martres.me/).
+
+- (Mar 21, 2017) [Dotty Internals 1: Trees & Symbols](https://www.youtube.com/watch?v=yYd-zuDd3S8) от [Dmitry Petrashko](http://x.com/darkdimius) [\[заметки\]](https://dotty.epfl.ch/docs/internals/dotty-internals-1-notes.html).
+ Это записанная встреча между EPFL и Waterloo, на которой мы представляем первые понятия внутри Dotty: деревья и символы.
+
+- (Mar 21, 2017) [Dotty Internals 2: Types](https://www.youtube.com/watch?v=3gmLIYlGbKc) от [Martin Odersky](http://x.com/odersky) и [Dmitry Petrashko](http://x.com/darkdimius).
+ Это записанная встреча между EPFL и Waterloo, на которой мы рассказываем, как типы представлены внутри Dotty.
+
+- (Jun 15, 2017) [Dotty Internals 3: Denotations](https://youtu.be/9iPA7zMRGKY) от [Martin Odersky](http://x.com/odersky) и [Dmitry Petrashko](http://x.com/darkdimius).
+ Это записанная встреча между EPFL и Waterloo, где мы вводим обозначения в Dotty.
+
+- (JVM Language Summit) [How do we make the Dotty compiler fast](https://www.youtube.com/watch?v=9xYoSwnSPz0) от [Dmitry Petrashko](http://x.com/darkdimius).
+ [Dmitry Petrashko](http://x.com/darkdimius) в общих чертах рассказывает о том, что было сделано для создания Dotty.
+
+- (Typelevel Summit Oslo, May 2016) [Dotty and types: the story so far](https://www.youtube.com/watch?v=YIQjfCKDR5A) от
+ Guillaume Martres [\[слайды\]](http://guillaume.martres.me/talks/typelevel-summit-oslo/).
+ Guillaume сосредоточился на некоторых практических улучшениях системы типов, реализованных в Dotty,
+ таких как новый алгоритм вывода параметров типа,
+ который может принимать решения о безопасности типов в большем количестве ситуаций, чем scalac.
+
+- (flatMap(Oslo) 2016) [AutoSpecialization in Dotty](https://vimeo.com/165928176) от [Dmitry Petrashko](http://x.com/darkdimius) [\[слайды\]](https://d-d.me/talks/flatmap2016/#/).
+ Dotty Linker анализирует вашу программу и ее зависимости, чтобы применить новую схему специализации.
+ Он основан на нашем опыте Specialization, Miniboxing и проекта Valhalla и значительно уменьшает размер создаваемого байт-кода.
+ И, что лучше всего, он всегда включен, выполняется за кулисами без аннотаций и приводит к ускорению более чем в 20 раз.
+ Кроме того, он "просто работает" с коллекциями Scala.
+
+- (ScalaSphere 2016) [Hacking on Dotty: A live demo](https://www.youtube.com/watch?v=0OOYGeZLHs4) от Guillaume Martres [\[слайды\]](http://guillaume.martres.me/talks/dotty-live-demo/).
+ Guillaume взламывает Dotty: живая демонстрация, во время которой он создает простую фазу компиляции
+ для трассировки вызовов методов во время выполнения.
+
+- (Scala By the Bay 2016) [Dotty: what is it and how it works](https://www.youtube.com/watch?v=wCFbYu7xEJA) от Guillaume
+ Martres [\[слайды\]](http://guillaume.martres.me/talks/dotty-tutorial/#/).
+ Guillaume предоставляет высокоуровневое представление о конвейере компиляции Dotty.
+
+- (ScalaDays 2015, Amsterdam) [Making your Scala applications smaller and faster with the Dotty linker](https://www.youtube.com/watch?v=xCeI1ArdXM4) от Dmitry Petrashko [\[слайды\]](https://d-d.me/scaladays2015/#/).
+ Дмитрий представляет алгоритм анализа графа вызовов, который реализует Dotty, и преимущества производительности,
+ которые мы можем получить с точки зрения количества методов, размера байт-кода, размера кода JVM
+ и количества объектов, выделенных в конце.
diff --git a/_ru/scalacenter-courses.md b/_ru/scalacenter-courses.md
new file mode 100644
index 0000000000..efa09f8254
--- /dev/null
+++ b/_ru/scalacenter-courses.md
@@ -0,0 +1,166 @@
+---
+title: Онлайн курсы (MOOCs) от Scala Center
+layout: singlepage-overview
+language: ru
+testimonials:
+- /resources/images/scalacenter-courses/testimonial000.jpg
+- /resources/images/scalacenter-courses/testimonial001.jpg
+- /resources/images/scalacenter-courses/testimonial002.jpg
+- /resources/images/scalacenter-courses/testimonial003.jpg
+- /resources/images/scalacenter-courses/testimonial004.jpg
+- /resources/images/scalacenter-courses/testimonial005.jpg
+- /resources/images/scalacenter-courses/testimonial006.jpg
+- /resources/images/scalacenter-courses/testimonial007.jpg
+- /resources/images/scalacenter-courses/testimonial008.jpg
+- /resources/images/scalacenter-courses/testimonial009.jpg
+- /resources/images/scalacenter-courses/testimonial010.jpg
+- /resources/images/scalacenter-courses/testimonial011.jpg
+- /resources/images/scalacenter-courses/testimonial012.jpg
+- /resources/images/scalacenter-courses/testimonial013.jpg
+- /resources/images/scalacenter-courses/testimonial014.jpg
+---
+
+[Scala Center] создает онлайн-курсы (также известные как МООК) различного уровня: от начального до продвинутого.
+
+**Если вы программист и хотите изучить Scala**, рекомендуется использовать два подхода.
+Быстрый путь состоит в прохождении курса ["Эффективное программирование на Scala"](#effective-programming-in-scala).
+В противном случае вы можете пройти полную [специализацию Scala][Scala Specialization],
+состоящую из четырех курсов (охватывающих сложные темы, такие как анализ больших данных и параллельное программирование)
+и завершающего проекта.
+
+Подробнее о курсах вы можете узнать из следующего видео:
+
+
+
+
+
+## Путь обучения Scala
+
+На диаграмме ниже показаны возможные пути обучения на наших курсах:
+
+
+
+"Базовые" курсы предназначены для программистов без предварительного опыта работы со Scala,
+тогда как "углубленные" курсы направлены на укрепление навыков программирования на Scala в конкретной области
+(например, параллельном программировании).
+
+Мы рекомендуем начать с "Эффективного программирования на Scala" (Effective Programming in Scala)
+или "Принципов функционального программирования на Scala" (Functional Programming Principles in Scala),
+а затем с "Проектирования функциональных программ" (Functional Program Design).
+Затем вы можете дополнить свои навыки Scala,
+пройдя любой из курсов "Программирование реактивных систем" (Programming Reactive Systems),
+"Параллельное программирование" (Parallel Programming)
+или "Анализ больших данных с помощью Scala и Spark" (Big Data Analysis with Scala and Spark).
+Если вы выберете специализацию Scala, то последним проектом будет Scala Capstone.
+
+## Учебные платформы
+
+В настоящее время все наши МООК доступны на платформе [Coursera](https://coursera.org),
+а некоторые из них доступны на [edX](https://edx.org) или [Extension School](https://extensionschool.ch).
+В этом разделе объясняются различия между этими учебными платформами.
+
+На всех платформах полный материал всегда доступен онлайн.
+Он включает в себя видеолекции, текстовые статьи, опросники и домашние задания с автоматической оценкой.
+Все платформы также предоставляют дискуссионные форумы, где вы можете общаться с другими учащимися.
+
+Отличие Extension School от других платформ заключается в том,
+что она проводит живые встречи с инструкторами и обзоры кода экспертами Scala.
+
+С другой стороны, на Coursera или edX наши курсы можно пройти бесплатно (режим "audit").
+При желании подписка дает вам доступ к сертификату об окончании, подтверждающему ваши результаты.
+
+Узнайте больше о [сертификатах Coursera](https://learners.coursera.help/hc/en-us/articles/209819053-Get-a-Course-Certificate),
+[сертификатах edX](https://support.edx.org/hc/en-us/categories/115002269627-Certificates)
+или [сертификатах Extension School](https://www.extensionschool.ch/faqs#certifying-coursework).
+Обратите внимание, что ваши подписки также поддерживают работу [Scala Center],
+миссией которого является создание качественных учебных материалов.
+
+Если вы предпочитаете самостоятельное обучение, мы рекомендуем вам выбрать платформу Coursera или edX,
+но если вам нужна дополнительная поддержка, рекомендуем вам выбрать Extension School.
+Ниже приведена таблица, в которой сравниваются платформы обучения:
+
+| | Coursera / edX (аудит) | Coursera / edX (подписка) | Extension School |
+| ------------------------------------------------ | ---------------------- | ------------------------- | ---------------- |
+| Видео-лекции, тесты | Да | Да | Да |
+| Домашние задания с автоматической оценкой | Да | Да | Да |
+| Дискуссионные форумы | Да | Да | Да |
+| Самостоятельный темп | Да | Да | Да |
+| Стоимость | $0 | от $50 до $100 за курс | $420 в месяц |
+| Сертификат об окончании | Нет | Да | Да |
+| Поддерживает Scala Center | Нет | Да | Да |
+| 30 минут живого занятия с инструкторами в неделю | Нет | Нет | Да |
+| Code reviews экспертами Scala | Нет | Нет | Да |
+
+## Effective Programming in Scala
+
+Этот курс доступен на [Coursera](https://coursera.org/learn/effective-scala) и [Extension School](https://extensionschool.ch/learn/effective-programming-in-scala).
+Пожалуйста, обратитесь к [этому разделу](#учебные-платформы), чтобы узнать о различиях между обеими учебными платформами.
+
+["Эффективное программирование на Scala"][Effective Programming in Scala] обучает программистов, не владеющих Scala,
+всему, что им нужно для подготовки к работе в Scala.
+В конце этого практического курса вы узнаете, как решать общие задачи программирования на Scala
+(например, моделирование бизнес-областей, реализацию бизнес-логики,
+проектирование больших систем, состоящих из компонентов,
+обработку ошибок, обработка данных, параллельное выполнение задач, тестирование вашего кода).
+Подробнее об этом курсе вы можете узнать из следующего видео:
+
+
+
+
+
+Этот курс также является хорошим способом улучшить свои знания Scala 2 до Scala 3.
+
+После прохождения этого курса вам может быть интересно улучшить свои навыки в конкретных областях,
+пройдя курсы ["Параллельное программирование"][Parallel Programming],
+["Анализ больших данных с помощью Scala и Spark"][Big Data Analysis with Scala and Spark]
+или ["Программирование реактивных систем"][Programming Reactive Systems].
+
+## Специализация Scala
+
+[Специализация Scala][Scala Specialization] обеспечивает практическое введение в функциональное программирование с использованием Scala.
+Вы можете получить доступ к материалам и упражнениям курса, зарегистрировавшись на специализацию или прослушав курсы индивидуально.
+Специализация состоит из следующих курсов:
+
+- [Принципы функционального программирования на Scala][Functional Programming Principles in Scala],
+- [Функциональный дизайн программ на Scala][Functional Program Design in Scala],
+- [Параллельное программирование][Parallel programming],
+- [Анализ больших данных с помощью Scala и Spark][Big Data Analysis with Scala and Spark],
+- [Функциональное программирование в Scala Capstone][Functional Programming in Scala Capstone].
+
+Эти курсы обеспечивают глубокое понимание самого языка Scala, а также погружаются в более конкретные темы,
+такие как параллельное программирование и Spark.
+
+## Программирование реактивных систем
+
+[Программирование реактивных систем][Programming Reactive Systems]
+(также доступно на [edX](https://www.edx.org/course/scala-akka-reactive))
+обучает писать адаптивные, масштабируемые и отказоустойчивые системы с помощью библиотеки Akka.
+
+## Курсы по Скала 2
+
+Все вышеперечисленные курсы используют Scala 3.
+При необходимости вы можете найти (устаревшую) версию наших курсов Scala 2 здесь:
+
+- [Принципы функционального программирования на Scala (версия Scala 2)](https://www.coursera.org/learn/scala2-functional-programming)
+- [Функциональный дизайн программ на Scala (версия Scala 2)](https://www.coursera.org/learn/scala2-functional-program-design)
+- [Параллельное программирование (версия Scala 2)](https://www.coursera.org/learn/scala2-parallel-programming)
+- [Анализ больших данных с помощью Scala и Spark (версия Scala 2)](https://www.coursera.org/learn/scala2-spark-big-data)
+- [Программирование реактивных систем (версия Scala 2)](https://www.coursera.org/learn/scala2-akka-reactive)
+
+## Отзывы
+
+{% include carousel.html images=page.testimonials number=0 height="50" unit="%" duration="10" %}
+
+## Другие онлайн-ресурсы
+
+[На этой странице]({% link online-courses.md %}) вы можете найти другие онлайн-ресурсы, предоставленные сообществом.
+
+[Scala Center]: https://scala.epfl.ch
+[Scala Specialization]: https://www.coursera.org/specializations/scala
+[Effective Programming in Scala]: https://www.coursera.org/learn/effective-scala
+[Functional Programming Principles in Scala]: https://www.coursera.org/learn/scala-functional-programming
+[Functional Program Design in Scala]: https://www.coursera.org/learn/scala-functional-program-design
+[Parallel programming]: https://www.coursera.org/learn/scala-parallel-programming
+[Big Data Analysis with Scala and Spark]: https://www.coursera.org/learn/scala-spark-big-data
+[Functional Programming in Scala Capstone]: https://www.coursera.org/learn/scala-capstone
+[Programming Reactive Systems]: https://www.coursera.org/learn/scala-akka-reactive
diff --git a/_ru/toolkit/OrderedListOfMdFiles b/_ru/toolkit/OrderedListOfMdFiles
new file mode 100644
index 0000000000..b2790bd58a
--- /dev/null
+++ b/_ru/toolkit/OrderedListOfMdFiles
@@ -0,0 +1,36 @@
+introduction.md
+testing-intro.md
+testing-suite.md
+testing-run.md
+testing-run-only.md
+testing-exceptions.md
+testing-asynchronous.md
+testing-resources.md
+testing-what-else.md
+os-intro.md
+os-read-directory.md
+os-read-file.md
+os-write-file.md
+os-run-process.md
+os-what-else.md
+json-intro.md
+json-parse.md
+json-modify.md
+json-deserialize.md
+json-serialize.md
+json-files.md
+json-what-else.md
+http-client-intro.md
+http-client-request.md
+http-client-uris.md
+http-client-request-body.md
+http-client-json.md
+http-client-upload-file.md
+http-client-what-else.md
+web-server-intro.md
+web-server-static.md
+web-server-dynamic.md
+web-server-query-parameters.md
+web-server-input.md
+web-server-websockets.md
+web-server-cookies-and-decorators.md
diff --git a/_ru/toolkit/http-client-intro.md b/_ru/toolkit/http-client-intro.md
new file mode 100644
index 0000000000..6e552acecd
--- /dev/null
+++ b/_ru/toolkit/http-client-intro.md
@@ -0,0 +1,24 @@
+---
+layout: multipage-overview
+partof: toolkit
+overview-name: "Scala инструментарий"
+title: Отправка HTTP-запросов с помощью sttp
+type: chapter
+description: Введение в библиотеку sttp
+language: ru
+num: 23
+previous-page:
+next-page:
+---
+
+sttp — популярная и многофункциональная библиотека для выполнения HTTP-запросов к веб-серверам.
+
+Она предоставляет как синхронный API, так и асинхронный API, основанный на `Future`. Она также поддерживает WebSockets.
+
+Доступны расширения, добавляющие такие возможности, как потоковая передача, логирование, телеметрия и сериализация.
+
+sttp предлагает одинаковые API на всех платформах (JVM, Scala.js и Scala Native).
+
+sttp — хороший выбор для небольших синхронных скриптов, а также для крупномасштабных, высококонкурентных, асинхронных приложений.
+
+{% include markdown.html path="_markdown/_ru/install-sttp.md" %}
diff --git a/_ru/toolkit/introduction.md b/_ru/toolkit/introduction.md
new file mode 100644
index 0000000000..f6a216e298
--- /dev/null
+++ b/_ru/toolkit/introduction.md
@@ -0,0 +1,88 @@
+---
+layout: multipage-overview
+partof: toolkit
+overview-name: "Scala инструментарий"
+title: Введение
+type: chapter
+description: Знакомство с учебными пособиями по Scala инструментариям
+language: ru
+num: 1
+previous-page:
+next-page: testing-intro
+toolkit-index:
+ - title: Тесты
+ description: Тестирование кода с помощью MUnit.
+ icon: "fa fa-vial-circle-check"
+ link: /ru/toolkit/testing-intro.html
+ - title: Файлы и процессы
+ description: Запись файлов и запуск процессов с помощью OS-Lib.
+ icon: "fa fa-folder-open"
+ link: /ru/toolkit/os-intro.html
+ - title: JSON
+ description: Парсинг JSON и сериализация объектов в JSON с помощью uPickle.
+ icon: "fa fa-file-code"
+ link: /ru/toolkit/json-intro.html
+ - title: HTTP-запросы
+ description: Отправка HTTP-запросов и загрузка файлов с помощью sttp.
+ icon: "fa fa-globe"
+ link: /ru/toolkit/http-client-intro.html
+ - title: Веб-серверы
+ description: Создание веб-серверов с помощью Cask.
+ icon: "fa fa-server"
+ link: /ru/toolkit/web-server-intro.html
+---
+
+## Что такое набор инструментов Scala?
+
+Scala Toolkit — это набор библиотек, предназначенных для эффективного выполнения типичных задач программирования.
+Он включает в себя инструменты для работы с файлами и процессами, парсинга JSON, отправки HTTP-запросов и модульного тестирования.
+
+Инструментарий поддерживает:
+
+- Scala 3 и Scala 2
+- JVM, Scala.js и Scala Native
+
+Варианты использования набора инструментов включают в себя:
+
+- кратковременные программы, работающие на JVM, для сканирования веб-сайта, сбора и преобразования данных
+ или для извлечения и обработки некоторых файлов,
+- скрипты интерфейса, которые запускаются в браузере и обеспечивают работу ваших веб-сайтов,
+- инструменты командной строки, упакованные в виде собственных двоичных файлов для мгновенного запуска
+
+{% include inner-documentation-sections.html links=page.toolkit-index %}
+
+## Что это за руководства?
+
+В этой серии руководств основное внимание уделяется кратким примерам кода, которые помогут вам быстро приступить к работе.
+
+Если вам нужна более подробная информация, в руководствах содержатся ссылки на дополнительную документацию
+по всем библиотекам в наборе инструментов.
+
+## Как запустить код?
+
+Вы можете следовать руководствам независимо от того, как решите запустить свой Scala код.
+Руководства фокусируются на самом коде, а не на процессе его запуска.
+
+Способы запуска кода на Scala включают:
+
+- В вашем **браузере** с помощью [Scastie](https://scastie.scala-lang.org)
+ - Плюсы: не требует установки, возможность делиться кодом онлайн
+ - Минусы: только один файл, доступно только онлайн
+- Интерактивно в **REPL** Scala (Read/Eval/Print/Loop)
+ - Плюсы: интерактивное исследование в терминале
+ - Минусы: не сохраняет ваш код
+- Интерактивно в **worksheet** в вашей IDE, например [IntelliJ](https://www.jetbrains.com/help/idea/discover-intellij-idea-for-scala.html) или [Metals](http://scalameta.org/metals/)
+ - Плюсы: интерактивное исследование в графическом интерфейсе
+ - Минусы: требует для запуска среды worksheet
+- В **скриптах** с использованием [Scala CLI](https://scala-cli.virtuslab.com)
+ - Плюсы: рабочий процесс в терминале с минимальной настройкой
+ - Минусы: может не подходить для крупных проектов
+- С использованием **инструмента сборки** (например, [sbt](https://www.scala-sbt.org) или [mill](https://com-lihaoyi.github.io/mill/))
+ - Плюсы: рабочий процесс в терминале для проектов любого размера
+ - Минусы: требует дополнительной настройки и обучения
+- С использованием **IDE**, например [IntelliJ](https://www.jetbrains.com/help/idea/discover-intellij-idea-for-scala.html) или [Metals](http://scalameta.org/metals/)
+ - Плюсы: рабочий процесс в графическом интерфейсе для проектов любого размера
+ - Минусы: требует дополнительной настройки и обучения
+
+Эти варианты, с их плюсами и минусами, характерны для большинства языков программирования.
+Вы можете использовать любой из них, в зависимости от того варианта, который вам удобен.
diff --git a/_ru/toolkit/json-intro.md b/_ru/toolkit/json-intro.md
new file mode 100644
index 0000000000..c91f04b075
--- /dev/null
+++ b/_ru/toolkit/json-intro.md
@@ -0,0 +1,23 @@
+---
+layout: multipage-overview
+partof: toolkit
+overview-name: "Scala инструментарий"
+title: Обработка JSON с помощью uPickle
+type: chapter
+description: Описание библиотеки uPickle.
+language: ru
+num: 16
+previous-page:
+next-page:
+---
+
+uPickle — это облегченная библиотека сериализации для Scala.
+
+В его состав входит uJson — библиотека для работы с JSON, которая может анализировать строки JSON,
+получать доступ к их значениям в памяти или изменять их, а также записывать их обратно.
+
+uPickle может сериализовать и десериализовать объекты Scala напрямую в JSON и из него.
+Он знает, как обрабатывать коллекции Scala, такие как `Map` и `Seq`,
+а также ваши собственные типы данных, такие как case class-ы и перечисления Scala 3.
+
+{% include markdown.html path="_markdown/_ru/install-upickle.md" %}
diff --git a/_ru/toolkit/os-intro.md b/_ru/toolkit/os-intro.md
new file mode 100644
index 0000000000..4e5cb4fd2a
--- /dev/null
+++ b/_ru/toolkit/os-intro.md
@@ -0,0 +1,25 @@
+---
+layout: multipage-overview
+partof: toolkit
+overview-name: "Scala инструментарий"
+title: Работа с файлами и процессами с помощью OS-Lib
+type: chapter
+description: Введение в библиотеку OS-lib
+language: ru
+num: 10
+previous-page:
+next-page:
+---
+
+OS-Lib — это библиотека для работы с файлами и процессами. Она является частью Scala Toolkit.
+
+OS-Lib стремится заменить API `java.nio.file` и `java.lang.ProcessBuilder`.
+Скорее всего, вам не понадобиться напрямую использовать какие-либо низкоуровневые Java API.
+
+OS-Lib также нацелена на то, чтобы вытеснить устаревшие API `scala.io` и `scala.sys` из стандартной библиотеки Scala.
+
+OS-Lib не имеет зависимостей.
+
+Весь функционал OS-Lib находится в пространстве имён `os.*`.
+
+{% include markdown.html path="_markdown/_ru/install-os-lib.md" %}
diff --git a/_ru/toolkit/testing-intro.md b/_ru/toolkit/testing-intro.md
new file mode 100644
index 0000000000..3fa905ddb3
--- /dev/null
+++ b/_ru/toolkit/testing-intro.md
@@ -0,0 +1,28 @@
+---
+layout: multipage-overview
+partof: toolkit
+overview-name: "Scala инструментарий"
+title: Тестирование с помощью MUnit
+type: chapter
+description: Введение в библиотеку MUnit
+language: ru
+num: 2
+previous-page: introduction
+next-page:
+---
+
+MUnit — легковесная библиотека для тестирования. Она предоставляет единый стиль написания тестов, который можно быстро освоить.
+
+Несмотря на свою простоту, MUnit обладает такими полезными функциями, как:
+
+- **утверждения (assertions)** для проверки поведения программы,
+- **фикстуры (fixtures)**, чтобы гарантировать, что тесты имеют доступ ко всем необходимым ресурсам,
+- **поддержка асинхронности** для тестирования параллельных (concurrent) и распределённых приложений.
+
+MUnit создаёт полезные отчёты об ошибках с указанием различий и местоположения в исходном коде, что помогает быстро понять причины сбоев.
+
+Тестирование является важной частью любого процесса разработки программного обеспечения,
+так как оно помогает находить ошибки на ранних этапах,
+улучшает качество кода и облегчает совместную работу.
+
+{% include markdown.html path="_markdown/_ru/install-munit.md" %}
diff --git a/_ru/toolkit/web-server-intro.md b/_ru/toolkit/web-server-intro.md
new file mode 100644
index 0000000000..6afdebab4f
--- /dev/null
+++ b/_ru/toolkit/web-server-intro.md
@@ -0,0 +1,30 @@
+---
+layout: multipage-overview
+partof: toolkit
+overview-name: "Scala инструментарий"
+title: Создание веб-серверов с помощью Cask
+type: chapter
+description: Введение в библиотеку Cask
+language: ru
+num: 30
+previous-page:
+next-page:
+---
+
+Cask — это микрофреймворк HTTP, предоставляющий простой и гибкий способ создания веб-приложений.
+
+Основное внимание уделяется простоте использования, что делает его идеальным для новичков,
+но при этом приходится отказываться от некоторых функций, предоставляемых другими фреймворками, например, асинхронности.
+
+Чтобы определить endpoint, достаточно аннотировать функцию аннотацией, указывающей путь запроса.
+Cask позволяет вручную строить ответ с помощью инструментов, предоставляемых библиотекой,
+указывая содержимое, заголовки, код статуса и т.д.
+Функция endpoint также может возвращать строку, JSON тип [uPickle](https://com-lihaoyi.github.io/upickle/)
+или шаблон [Scalatags](https://com-lihaoyi.github.io/scalatags/).
+В этом случае Cask автоматически создаст ответ с соответствующими заголовками.
+
+Cask поставляется в комплекте с библиотекой uPickle для обработки JSON, поддерживает WebSockets
+и позволяет расширять конечные точки с помощью декораторов,
+которые можно использовать для обработки аутентификации или ограничения скорости.
+
+{% include markdown.html path="_markdown/_ru/install-cask.md" %}
diff --git a/_ru/tour/abstract-type-members.md b/_ru/tour/abstract-type-members.md
index cb2a2ecc1e..537ebf80f4 100644
--- a/_ru/tour/abstract-type-members.md
+++ b/_ru/tour/abstract-type-members.md
@@ -1,9 +1,6 @@
---
layout: tour
title: Члены Абстрактного Типа
-
-discourse: true
-
partof: scala-tour
num: 23
language: ru
@@ -11,52 +8,110 @@ next-page: compound-types
previous-page: inner-classes
topics: abstract type members
prerequisite-knowledge: variance, upper-type-bound
-
---
-Абстрактные типы, такие как трейты и абстрактные классы, могут содержать членов абстрактного типа.
+Абстрактные типы, такие как трейты и абстрактные классы, могут содержать члены абстрактного типа.
Абстрактный означает, что только конкретный экземпляр определяет, каким именно будет тип.
Вот пример:
-```tut
+{% tabs abstract-types_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=abstract-types_1 %}
+
+```scala mdoc
trait Buffer {
type T
val element: T
}
```
-Здесь мы определили абстрактный тип `T`, который используется для описания типа члена `element`. Мы можем расширить его в абстрактном классе, добавив верхнюю границу нового типа `U` связанного с `T`, делая описание типа более конкретным.
-```tut
+{% endtab %}
+{% tab 'Scala 3' for=abstract-types_1 %}
+
+```scala
+trait Buffer:
+ type T
+ val element: T
+```
+
+{% endtab %}
+{% endtabs %}
+
+Здесь мы определили абстрактный тип `T`, который используется для описания типа члена `element`. Мы можем расширить его в абстрактном классе, добавив верхнюю границу нового типа `U`, связанного с `T`, делая описание типа более конкретным.
+
+{% tabs abstract-types_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=abstract-types_2 %}
+
+```scala mdoc
abstract class SeqBuffer extends Buffer {
type U
type T <: Seq[U]
def length = element.length
}
```
+
+{% endtab %}
+{% tab 'Scala 3' for=abstract-types_2 %}
+
+```scala
+abstract class SeqBuffer extends Buffer:
+ type U
+ type T <: Seq[U]
+ def length = element.length
+```
+
+{% endtab %}
+{% endtabs %}
+
Обратите внимание, как мы можем использовать новый абстрактный тип `U` в качестве верхней границы типа. Класс `SeqBuffer` позволяет хранить в буфере только последовательности, указывая, что тип `T` должен быть подтипом `Seq[U]` для нового абстрактного типа `U`.
-[Трейты](traits.html) или [классы](classes.html) с членами абстрактного типа часто используются в сочетании с анонимными экземплярами классов. Чтобы проиллюстрировать это рассмотрим программу, которая имеет дело с буфером, который ссылается на список целых чисел:
+[Трейты](traits.html) или [классы](classes.html) с членами абстрактного типа часто используются в сочетании с анонимными экземплярами классов. Чтобы проиллюстрировать это рассмотрим программу, имеющую дело с буфером, который ссылается на список целых чисел:
+
+{% tabs abstract-types_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=abstract-types_3 %}
-```tut
+```scala mdoc
abstract class IntSeqBuffer extends SeqBuffer {
type U = Int
}
-
def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
new IntSeqBuffer {
- type T = List[U]
- val element = List(elem1, elem2)
- }
+ type T = List[U]
+ val element = List(elem1, elem2)
+ }
+val buf = newIntSeqBuf(7, 8)
+println("length = " + buf.length)
+println("content = " + buf.element)
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=abstract-types_3 %}
+
+```scala
+abstract class IntSeqBuffer extends SeqBuffer:
+ type U = Int
+
+def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
+ new IntSeqBuffer:
+ type T = List[U]
+ val element = List(elem1, elem2)
+
val buf = newIntSeqBuf(7, 8)
println("length = " + buf.length)
println("content = " + buf.element)
```
-Здесь класс `newIntSeqBuf` создает экземпляры `IntSeqBuffer`, используя анонимную реализацию класса `IntSeqBuffer` (т.е. `new IntSeqBuffer`), устанавливая тип `T` как `List[Int]`.
-Мы можем вывести тип класса из типа его членов и наоборот. Приведем версию кода, в которой выводится тип класса из типа его члена:
+{% endtab %}
+{% endtabs %}
+
+Здесь метод `newIntSeqBuf` создает экземпляры `IntSeqBuffer`, используя анонимную реализацию класса `IntSeqBuffer` (т.е. `new IntSeqBuffer`), устанавливая тип `T` как `List[Int]`.
+
+Мы можем вывести тип класса из типа его членов и наоборот. Приведем версию кода, в которой выводится тип класса из типов его члена:
-```tut
+{% tabs abstract-types_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=abstract-types_4 %}
+
+```scala mdoc:nest
abstract class Buffer[+T] {
val element: T
}
@@ -74,4 +129,26 @@ println("length = " + buf.length)
println("content = " + buf.element)
```
-Обратите внимание, что здесь необходимо использовать [вариантность в описании типа](variances.html) (`+T <: Seq[U]`) для того, чтобы скрыть конкретный тип реализации списка, возвращаемого из метода `newIntSeqBuf`.
\ No newline at end of file
+{% endtab %}
+{% tab 'Scala 3' for=abstract-types_4 %}
+
+```scala
+abstract class Buffer[+T]:
+ val element: T
+
+abstract class SeqBuffer[U, +T <: Seq[U]] extends Buffer[T]:
+ def length = element.length
+
+def newIntSeqBuf(e1: Int, e2: Int): SeqBuffer[Int, Seq[Int]] =
+ new SeqBuffer[Int, List[Int]]:
+ val element = List(e1, e2)
+
+val buf = newIntSeqBuf(7, 8)
+println("length = " + buf.length)
+println("content = " + buf.element)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Обратите внимание, что здесь необходимо использовать [вариантность в описании типа](variances.html) (`+T <: Seq[U]`) для того, чтобы скрыть конкретный тип реализации списка, возвращаемого из метода `newIntSeqBuf`.
diff --git a/_ru/tour/annotations.md b/_ru/tour/annotations.md
index 50829901d4..0af144139d 100644
--- a/_ru/tour/annotations.md
+++ b/_ru/tour/annotations.md
@@ -1,35 +1,53 @@
---
layout: tour
title: Аннотации
-
-discourse: true
-
partof: scala-tour
-
num: 32
language: ru
-next-page: default-parameter-values
+next-page: packages-and-imports
previous-page: by-name-parameters
-
---
Аннотации используются для передачи метаданных при объявлении. Например, аннотация `@deprecated` перед объявлением метода, заставит компилятор вывести предупреждение, если этот метод будет использован.
-```
+
+{% tabs annotations_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=annotations_1 %}
+
+```scala mdoc:fail
object DeprecationDemo extends App {
@deprecated("deprecation message", "release # which deprecates method")
def hello = "hola"
- hello
+ hello
}
```
+
+{% endtab %}
+{% tab 'Scala 3' for=annotations_1 %}
+
+```scala
+object DeprecationDemo extends App:
+ @deprecated("deprecation message", "release # which deprecates method")
+ def hello = "hola"
+
+ hello
+```
+
+{% endtab %}
+{% endtabs %}
+
Такой код скомпилируется, но компилятор выдаст предупреждение: "there was one deprecation warning".
Аннотация применяется к первому идущему после нее объявлению или определению. Допускается использование сразу нескольких аннотаций следующих друг за другом. Порядок, в котором приводятся аннотации, не имеет значения.
## Аннотации, обеспечивающие корректность работы кода
+
Некоторые аннотации приводят к невозможности компиляции, если условие (условия) не выполняется. Например, аннотация `@tailrec` гарантирует, что метод является [хвостовой рекурсией](https://ru.wikipedia.org/wiki/%D0%A5%D0%B2%D0%BE%D1%81%D1%82%D0%BE%D0%B2%D0%B0%D1%8F_%D1%80%D0%B5%D0%BA%D1%83%D1%80%D1%81%D0%B8%D1%8F). Хвостовая рекурсия помогает держать потребление памяти на постоянном уровне. Вот как она используется в методе, который вычисляет факториал:
-```tut
+{% tabs annotations_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=annotations_2 %}
+
+```scala mdoc
import scala.annotation.tailrec
def factorial(x: Int): Int = {
@@ -41,8 +59,30 @@ def factorial(x: Int): Int = {
factorialHelper(x, 1)
}
```
-Метод `factorialHelper` имеет аннотацию `@tailrec`, которая гарантирует, что метод действительно является хвостовой рекурсией. Если бы мы изменили реализацию `factorialHelper` так как указано далее, то компиляция бы провалилась:
+
+{% endtab %}
+{% tab 'Scala 3' for=annotations_2 %}
+
+```scala
+import scala.annotation.tailrec
+
+def factorial(x: Int): Int =
+
+ @tailrec
+ def factorialHelper(x: Int, accumulator: Int): Int =
+ if x == 1 then accumulator else factorialHelper(x - 1, accumulator * x)
+ factorialHelper(x, 1)
```
+
+{% endtab %}
+{% endtabs %}
+
+Метод `factorialHelper` имеет аннотацию `@tailrec`, которая гарантирует, что метод действительно является хвостовой рекурсией. Если бы мы изменили реализацию `factorialHelper` так как указано далее, то компиляция бы провалилась:
+
+{% tabs annotations_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=annotations_3 %}
+
+```scala mdoc:fail
import scala.annotation.tailrec
def factorial(x: Int): Int = {
@@ -53,77 +93,155 @@ def factorial(x: Int): Int = {
factorialHelper(x)
}
```
-Мы бы получили сообщение "Recursive call not in tail position"(Рекурсивный вызов не в хвостовой позиции).
+{% endtab %}
+{% tab 'Scala 3' for=annotations_3 %}
+
+```scala
+import scala.annotation.tailrec
+
+def factorial(x: Int): Int =
+ @tailrec
+ def factorialHelper(x: Int): Int =
+ if x == 1 then 1 else x * factorialHelper(x - 1)
+ factorialHelper(x)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Мы бы получили сообщение "Recursive call not in tail position"(Рекурсивный вызов не в хвостовой позиции).
## Аннотации, влияющие на генерацию кода
+
+{% tabs annotations_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=annotations_4 %}
+
Некоторые аннотации типа `@inline` влияют на сгенерированный код (т.е. в результате сам код вашего jar-файл может отличаться). Такая аннотация означает вставку всего кода в тело метода вместо вызова. Полученный байт-код длиннее, но, надеюсь, работает быстрее. Использование аннотации `@inline` не гарантирует, что метод будет встроен, но заставит компилятор сделать это, если и только если будут соблюдены некоторые разумные требования к размеру сгенерированного кода.
-### Java аннотации ###
-Есть некоторые отличий синтаксиса аннотаций, если пишется Scala код, который взаимодействует с Java.
+{% endtab %}
+{% tab 'Scala 3' for=annotations_4 %}
+
+Некоторые аннотации типа `@main` влияют на сгенерированный код (т.е. в результате сам код вашего jar-файл может отличаться).
+Аннотация `@main` к методу создает исполняемую программу, которая вызывает метод как точку входа.
+
+{% endtab %}
+{% endtabs %}
+
+### Java аннотации
+
+Есть некоторые отличия синтаксиса аннотаций, если пишется Scala код, который взаимодействует с Java.
**Примечание:**Убедитесь, что вы используете опцию `-target:jvm-1.8` с аннотациями Java.
Java имеет определяемые пользователем метаданные в виде [аннотаций](https://docs.oracle.com/javase/tutorial/java/annotations/). Ключевой особенностью аннотаций является то, что они задаются в виде пар ключ-значение для инициализации своих элементов. Например, если нам нужна аннотация для отслеживания источника какого-то класса, мы можем определить её как
-```
+{% tabs annotations_5 %}
+{% tab 'Java' for=annotations_5 %}
+
+```java
@interface Source {
- public String URL();
+ public String url();
public String mail();
}
```
+{% endtab %}
+{% endtabs %}
+
А затем использовать следующим образом
-```
-@Source(URL = "https://coders.com/",
+{% tabs annotations_6 %}
+{% tab 'Java' for=annotations_6 %}
+
+```java
+@Source(url = "https://coders.com/",
mail = "support@coders.com")
-public class MyClass extends HisClass ...
+public class MyJavaClass extends TheirClass ...
```
+{% endtab %}
+{% endtabs %}
+
Использование аннотации в Scala похоже на вызов конструктора. Для создания экземпляра из Java аннотации необходимо использовать именованные аргументы:
-```
-@Source(URL = "https://coders.com/",
+{% tabs annotations_7 %}
+{% tab 'Scala 2 и 3' for=annotations_7 %}
+
+```scala
+@Source(url = "https://coders.com/",
mail = "support@coders.com")
class MyScalaClass ...
```
+{% endtab %}
+{% endtabs %}
+
Этот синтаксис достаточно перегруженный, если аннотация содержит только один элемент (без значения по умолчанию), поэтому, если имя указано как `value`, оно может быть применено в Java с помощью конструктора-подобного синтаксиса:
-```
+{% tabs annotations_8 %}
+{% tab 'Java' for=annotations_8 %}
+
+```java
@interface SourceURL {
public String value();
public String mail() default "";
}
```
+{% endtab %}
+{% endtabs %}
+
А затем можно использовать следующим образом
-```
+{% tabs annotations_9 %}
+{% tab 'Java' for=annotations_9 %}
+
+```java
@SourceURL("https://coders.com/")
-public class MyClass extends HisClass ...
+public class MyJavaClass extends TheirClass ...
```
+{% endtab %}
+{% endtabs %}
+
В этом случае Scala предоставляет такую же возможность
-```
+{% tabs annotations_10 %}
+{% tab 'Scala 2 и 3' for=annotations_10 %}
+
+```scala
@SourceURL("https://coders.com/")
class MyScalaClass ...
```
+{% endtab %}
+{% endtabs %}
+
Элемент `mail` был указан со значением по умолчанию, поэтому нам не нужно явно указывать его значение. Мы не можем смешивать эти два стиля в Java:
-```
+{% tabs annotations_11 %}
+{% tab 'Java' for=annotations_11 %}
+
+```java
@SourceURL(value = "https://coders.com/",
mail = "support@coders.com")
-public class MyClass extends HisClass ...
+public class MyJavaClass extends TheirClass ...
```
+{% endtab %}
+{% endtabs %}
+
Scala обеспечивает большую гибкость в этом отношении
-```
+{% tabs annotations_12 %}
+{% tab 'Scala 2 и 3' for=annotations_12 %}
+
+```scala
@SourceURL("https://coders.com/",
mail = "support@coders.com")
- class MyScalaClass ...
+class MyScalaClass ...
```
+
+{% endtab %}
+{% endtabs %}
diff --git a/_ru/tour/automatic-closures.md b/_ru/tour/automatic-closures.md
deleted file mode 100644
index 7de83279d8..0000000000
--- a/_ru/tour/automatic-closures.md
+++ /dev/null
@@ -1,63 +0,0 @@
----
-layout: tour
-title: Конструкция Автоматического Замыкания Зависимого Типа
-
-discourse: true
-language: ru
-partof: scala-tour
-num: 14
----
-
-Scala допускает использование в качестве параметров методов имена беспараметрических функций. При вызове такого метода фактические параметры для беспараметрических функций не вычисляются, а передается функция с нулем аргументов, которая захватывает вычисление соответствующего параметра (так называемый *вызов по имени*).
-
-Следующий код демонстрирует этот механизм:
-
- object TargetTest1 extends Application {
- def whileLoop(cond: => Boolean)(body: => Unit): Unit =
- if (cond) {
- body
- whileLoop(cond)(body)
- }
- var i = 10
- whileLoop (i > 0) {
- println(i)
- i -= 1
- }
- }
-
-Функция whileLoop принимает два параметра `cond` и `body`. При использовании функции значения этих параметров не вычисляются. Но всякий раз, когда параметры используются в теле `whileLoop`, их значение будет вычисляться заново через использование автоматически созданных неявно вызываемых функций. Таким образом, наш метод `whileLoop` реализует Java-подобный цикл while-loop со схемой рекурсивной реализации.
-
-Мы можем комбинировать использование [инфиксных/постфиксных операторов](operators.html) с этим механизмом для создания более сложных выражений (с хорошим синтаксисом).
-
-Вот реализация loop-unless выражения:
-
- object TargetTest2 extends Application {
- def loop(body: => Unit): LoopUnlessCond =
- new LoopUnlessCond(body)
- protected class LoopUnlessCond(body: => Unit) {
- def unless(cond: => Boolean) {
- body
- if (!cond) unless(cond)
- }
- }
- var i = 10
- loop {
- println("i = " + i)
- i -= 1
- } unless (i == 0)
- }
-Функция `loop` принимает только тело цикла и возвращает экземпляр класса `LoopUnlessCond` (который захватывает это тело цикла). Обратите внимание, что тело еще не вычислено. Класс `LoopUnlessCond` имеет метод `unless`, который мы можем использовать как *инфиксный оператор*. Таким образом, мы получаем вполне естественный синтаксис для нашего нового цикла: `loop { < выражение > } unless ( < условие > )`.
-
-
-Ниже приведен вывод выполнения `TargetTest2`:
-
- i = 10
- i = 9
- i = 8
- i = 7
- i = 6
- i = 5
- i = 4
- i = 3
- i = 2
- i = 1
diff --git a/_ru/tour/basics.md b/_ru/tour/basics.md
index 6fab580323..3d8590bfe7 100644
--- a/_ru/tour/basics.md
+++ b/_ru/tour/basics.md
@@ -1,92 +1,125 @@
---
layout: tour
title: Основы
-
-discourse: true
-
partof: scala-tour
-
num: 2
language: ru
next-page: unified-types
previous-page: tour-of-scala
-
---
На этой странице мы расскажем об основах Scala.
## Попробовать Scala в браузере.
-Вы можете запустить Scala в браузере с помощью ScalaFiddle.
+Вы можете запустить Scala в браузере с помощью Scastie.
-1. Зайдите на [https://scalafiddle.io](https://scalafiddle.io).
+1. Зайдите на [Scastie](https://scastie.scala-lang.org/).
2. Вставьте `println("Hello, world!")` в левую панель.
3. Нажмите кнопку "Run". Вывод отобразится в правой панели.
Это простой способ поэкспериментировать со Scala кодом без всяких настроек.
-Большинство примеров кода в этой документации также интегрированы с ScalaFiddle,
-поэтому вы можете поэкспериментировать с ними, просто нажав кнопку Run.
-
## Выражения
Выражения — это вычислимые утверждения.
-```
+
+{% tabs expression %}
+{% tab 'Scala 2 и 3' for=expression %}
+
+```scala mdoc
1 + 1
```
+
+{% endtab %}
+{% endtabs %}
+
Вы можете выводить результаты выражений, используя `println`.
-{% scalafiddle %}
-```tut
+{% tabs println %}
+{% tab 'Scala 2 и 3' for=println %}
+
+```scala mdoc
println(1) // 1
println(1 + 1) // 2
println("Hello!") // Hello!
println("Hello," + " world!") // Hello, world!
```
-{% endscalafiddle %}
+
+{% endtab %}
+{% endtabs %}
### Значения
Результаты выражений можно присваивать именам с помощью ключевого слова `val`.
-```tut
+{% tabs val %}
+{% tab 'Scala 2 и 3' for=val %}
+
+```scala mdoc
val x = 1 + 1
println(x) // 2
```
-Названные результаты, такие как `x` в примере, называются значениями.
+{% endtab %}
+{% endtabs %}
+
+Названные результаты, такие как `x` в примере, называются значениями.
Вызов значения не приводит к его повторному вычислению.
Значения не изменяемы и не могут быть переназначены.
-```tut:fail
+{% tabs val-error %}
+{% tab 'Scala 2 и 3' for=val-error %}
+
+```scala mdoc:fail
x = 3 // Не компилируется.
```
+{% endtab %}
+{% endtabs %}
+
Типы значений могут быть выведены автоматически, но можно и явно указать тип, как показано ниже:
-```tut
+{% tabs type-inference %}
+{% tab 'Scala 2 и 3' for=type-inference %}
+
+```scala mdoc:nest
val x: Int = 1 + 1
```
-Обратите внимание, что объявление типа `Int` происходит после идентификатора `x`, следующим за `:`.
+{% endtab %}
+{% endtabs %}
+
+Обратите внимание, что объявление типа `Int` происходит после идентификатора `x`, следующим за `:`.
### Переменные
Переменные похожи на значения константы, за исключением того, что их можно присваивать заново. Вы можете объявить переменную с помощью ключевого слова `var`.
-```tut
+{% tabs var %}
+{% tab 'Scala 2 и 3' for=var %}
+
+```scala mdoc:nest
var x = 1 + 1
x = 3 // Компилируется потому что "x" объявлен с ключевым словом "var".
println(x * x) // 9
```
+{% endtab %}
+{% endtabs %}
+
Как и в случае со значениями, вы можете явно указать тип, если захотите:
-```tut
+{% tabs type-inference-2 %}
+{% tab 'Scala 2 и 3' for=type-inference-2 %}
+
+```scala mdoc:nest
var x: Int = 1 + 1
```
+{% endtab %}
+{% endtabs %}
## Блоки
@@ -94,94 +127,152 @@ var x: Int = 1 + 1
Результат последнего выражения в блоке будет результатом всего блока в целом.
-```tut
+{% tabs blocks %}
+{% tab 'Scala 2 и 3' for=blocks %}
+
+```scala mdoc
println({
val x = 1 + 1
x + 1
}) // 3
```
+{% endtab %}
+{% endtabs %}
+
## Функции
Функции — это выражения, которые принимают параметры.
Вы можете определить анонимную функцию (т.е. без имени), которая возвращает переданное число, прибавив к нему единицу:
-```tut
+{% tabs anonymous-function %}
+{% tab 'Scala 2 и 3' for=anonymous-function %}
+
+```scala mdoc
(x: Int) => x + 1
```
+{% endtab %}
+{% endtabs %}
+
Слева от `=>` находится список параметров. Справа — выражение, связанное с параметрами.
Вы также можете назвать функции.
-{% scalafiddle %}
-```tut
+{% tabs named-function %}
+{% tab 'Scala 2 и 3' for=named-function %}
+
+```scala mdoc
val addOne = (x: Int) => x + 1
println(addOne(1)) // 2
```
-{% endscalafiddle %}
+
+{% endtab %}
+{% endtabs %}
Функции могут принимать множество параметров.
-{% scalafiddle %}
-```tut
+{% tabs multiple-parameters %}
+{% tab 'Scala 2 и 3' for=multiple-parameters %}
+
+```scala mdoc
val add = (x: Int, y: Int) => x + y
println(add(1, 2)) // 3
```
-{% endscalafiddle %}
+
+{% endtab %}
+{% endtabs %}
Или вообще не принимать никаких параметров.
-```tut
+{% tabs no-parameters %}
+{% tab 'Scala 2 и 3' for=no-parameters %}
+
+```scala mdoc
val getTheAnswer = () => 42
println(getTheAnswer()) // 42
```
+{% endtab %}
+{% endtabs %}
+
## Методы
Методы выглядят и ведут себя очень похоже на функции, но между ними есть несколько принципиальных различий.
-Методы задаются ключевым словом `def`. За `def` следует имя, список параметров, возвращаемый тип и тело.
+Методы задаются ключевым словом `def`. За `def` следует имя, список параметров, возвращаемый тип и тело.
+
+{% tabs method %}
+{% tab 'Scala 2 и 3' for=method %}
-{% scalafiddle %}
-```tut
+```scala mdoc:nest
def add(x: Int, y: Int): Int = x + y
println(add(1, 2)) // 3
```
-{% endscalafiddle %}
+
+{% endtab %}
+{% endtabs %}
Обратите внимание, как объявлен возвращаемый тип сразу _после_ списка параметров и двоеточия `: Int`.
Методы могут принимать несколько списков параметров.
-{% scalafiddle %}
-```tut
+{% tabs multiple-parameter-lists %}
+{% tab 'Scala 2 и 3' for=multiple-parameter-lists %}
+
+```scala mdoc
def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier
println(addThenMultiply(1, 2)(3)) // 9
```
-{% endscalafiddle %}
+
+{% endtab %}
+{% endtabs %}
Или вообще ни одного списка параметров.
-```tut
+{% tabs no-parameter-lists %}
+{% tab 'Scala 2 и 3' for=no-parameter-lists %}
+
+```scala mdoc
def name: String = System.getProperty("user.name")
println("Hello, " + name + "!")
```
+{% endtab %}
+{% endtabs %}
+
Есть некоторые отличия от функций, но пока что их можно рассматривать как нечто похожее.
Методы также могут иметь многострочные выражения.
-{% scalafiddle %}
-```tut
+{% tabs get-square-string class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=get-square-string %}
+
+```scala mdoc
def getSquareString(input: Double): String = {
val square = input * input
square.toString
}
println(getSquareString(2.5)) // 6.25
```
-{% endscalafiddle %}
+
+{% endtab %}
+
+{% tab 'Scala 3' for=get-square-string %}
+
+```scala
+def getSquareString(input: Double): String =
+ val square = input * input
+ square.toString
+
+println(getSquareString(2.5)) // 6.25
+```
+
+{% endtab %}
+
+{% endtabs %}
Последнее выражение в теле становится возвращаемым значением метода (у Scala есть ключевое слово `return`, но оно практически не используется).
@@ -189,55 +280,129 @@ println(getSquareString(2.5)) // 6.25
Вы можете объявлять классы используя ключевое слово `class`, за которым следует его имя и параметры конструктора.
-```tut
+{% tabs greeter-definition class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=greeter-definition %}
+
+```scala mdoc
class Greeter(prefix: String, suffix: String) {
def greet(name: String): Unit =
println(prefix + name + suffix)
}
```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=greeter-definition %}
+
+```scala
+class Greeter(prefix: String, suffix: String):
+ def greet(name: String): Unit =
+ println(prefix + name + suffix)
+```
+
+{% endtab %}
+
+{% endtabs %}
+
Возвращаемый тип метода `greet` это `Unit`, используется тогда, когда не имеет смысла что-либо возвращать. Аналогично `void` в Java и C. Поскольку каждое выражение Scala должно иметь какое-то значение, то при отсутствии возвращающегося значения возвращается экземпляр типа Unit. Явным образом его можно задать как `()`, он не несет какой-либо информации.
Вы можете создать экземпляр класса, используя ключевое слово `new`.
-```tut
+{% tabs greeter-usage class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=greeter-usage %}
+
+```scala mdoc:nest
val greeter = new Greeter("Hello, ", "!")
greeter.greet("Scala developer") // Hello, Scala developer!
```
+{% endtab %}
+
+{% tab 'Scala 3' for=greeter-usage %}
+
+```scala
+val greeter = Greeter("Hello, ", "!")
+greeter.greet("Scala developer") // Hello, Scala developer!
+```
+
+{% endtab %}
+
+{% endtabs %}
+
Позже мы рассмотрим классы [подробнее](classes.html).
## Классы-образцы (Case Class)
В Scala есть специальный тип класса, который называется классом-образцом (case class). По умолчанию такие классы неизменны и сравниваются по значению из конструктора. Вы можете объявлять классы-образцы с помощью ключевых слов `case class`.
-```tut
+{% tabs case-class-definition %}
+{% tab 'Scala 2 и 3' for=case-class-definition %}
+
+```scala mdoc
case class Point(x: Int, y: Int)
```
+{% endtab %}
+{% endtabs %}
+
Можно создавать экземпляры класса-образца без использования ключевого слова `new`.
-```tut
+{% tabs case-class-creation %}
+{% tab 'Scala 2 и 3' for=case-class-creation %}
+
+```scala mdoc
val point = Point(1, 2)
val anotherPoint = Point(1, 2)
val yetAnotherPoint = Point(2, 2)
```
+{% endtab %}
+{% endtabs %}
+
Они сравниваются по значению.
-```tut
+{% tabs compare-case-class-equality class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=compare-case-class-equality %}
+
+```scala mdoc
if (point == anotherPoint) {
- println(point + " and " + anotherPoint + " are the same.")
+ println(s"$point and $anotherPoint are the same.")
} else {
- println(point + " and " + anotherPoint + " are different.")
+ println(s"$point and $anotherPoint are different.")
} // Point(1,2) и Point(1,2) одни и те же.
if (point == yetAnotherPoint) {
- println(point + " and " + yetAnotherPoint + " are the same.")
+ println(s"$point and $yetAnotherPoint are the same.")
} else {
- println(point + " and " + yetAnotherPoint + " are different.")
+ println(s"$point and $yetAnotherPoint are different.")
} // Point(1,2) и Point(2,2) разные.
```
+{% endtab %}
+
+{% tab 'Scala 3' for=compare-case-class-equality %}
+
+```scala
+if point == anotherPoint then
+ println(s"$point and $anotherPoint are the same.")
+else
+ println(s"$point and $anotherPoint are different.")
+// Point(1,2) и Point(1,2) одни и те же.
+
+if point == yetAnotherPoint then
+ println(s"$point and $yetAnotherPoint are the same.")
+else
+ println(s"$point and $yetAnotherPoint are different.")
+// Point(1,2) и Point(2,2) разные.
+```
+
+{% endtab %}
+
+{% endtabs %}
+
Есть еще много деталей, которые мы бы хотели рассказать про классы-образцы; мы уверены, что вы влюбитесь в них! Обязательно рассмотрим их [позже](case-classes.html).
## Объекты
@@ -246,7 +411,11 @@ if (point == yetAnotherPoint) {
Вы можете задать объекты при помощи ключевого слова `object`.
-```tut
+{% tabs id-factory-definition class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=id-factory-definition %}
+
+```scala mdoc
object IdFactory {
private var counter = 0
def create(): Int = {
@@ -256,15 +425,37 @@ object IdFactory {
}
```
+{% endtab %}
+
+{% tab 'Scala 3' for=id-factory-definition %}
+
+```scala
+object IdFactory:
+ private var counter = 0
+ def create(): Int =
+ counter += 1
+ counter
+```
+
+{% endtab %}
+
+{% endtabs %}
+
Вы можете сразу получить доступ к объекту, ссылаясь на его имя.
-```tut
+{% tabs id-factory-usage %}
+{% tab 'Scala 2 и 3' for=id-factory-usage %}
+
+```scala mdoc
val newId: Int = IdFactory.create()
println(newId) // 1
val newerId: Int = IdFactory.create()
println(newerId) // 2
```
+{% endtab %}
+{% endtabs %}
+
Позже мы рассмотрим объекты [подробнее](singleton-objects.html).
## Трейты
@@ -273,25 +464,63 @@ println(newerId) // 2
Объявить трейт можно с помощью ключевого слова `trait`.
-```tut
+{% tabs greeter-trait-def class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=greeter-trait-def %}
+
+```scala mdoc:nest
trait Greeter {
def greet(name: String): Unit
}
```
+{% endtab %}
+
+{% tab 'Scala 3' for=greeter-trait-def %}
+
+```scala
+trait Greeter:
+ def greet(name: String): Unit
+```
+
+{% endtab %}
+
+{% endtabs %}
+
Трейты также могут иметь реализации методов и полей, которые предполагается использовать умолчанию.
-{% scalafiddle %}
-```tut
+{% tabs greeter-trait-def-impl class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=greeter-trait-def-impl %}
+
+```scala mdoc:reset
trait Greeter {
def greet(name: String): Unit =
println("Hello, " + name + "!")
}
```
+{% endtab %}
+
+{% tab 'Scala 3' for=greeter-trait-def-impl %}
+
+```scala
+trait Greeter:
+ def greet(name: String): Unit =
+ println("Hello, " + name + "!")
+```
+
+{% endtab %}
+
+{% endtabs %}
+
Вы можете наследовать свойства трейтов, используя ключевое слово `extends` и переопределять реализацию с помощью ключевого слова `override`.
-```tut
+{% tabs greeter-implementations class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=greeter-implementations %}
+
+```scala mdoc
class DefaultGreeter extends Greeter
class CustomizableGreeter(prefix: String, postfix: String) extends Greeter {
@@ -306,7 +535,28 @@ greeter.greet("Scala developer") // Hello, Scala developer!
val customGreeter = new CustomizableGreeter("How are you, ", "?")
customGreeter.greet("Scala developer") // How are you, Scala developer?
```
-{% endscalafiddle %}
+
+{% endtab %}
+
+{% tab 'Scala 3' for=greeter-implementations %}
+
+```scala
+class DefaultGreeter extends Greeter
+
+class CustomizableGreeter(prefix: String, postfix: String) extends Greeter:
+ override def greet(name: String): Unit =
+ println(prefix + name + postfix)
+
+val greeter = DefaultGreeter()
+greeter.greet("Scala developer") // Hello, Scala developer!
+
+val customGreeter = CustomizableGreeter("How are you, ", "?")
+customGreeter.greet("Scala developer") // How are you, Scala developer?
+```
+
+{% endtab %}
+
+{% endtabs %}
Здесь `DefaultGreeter` наследуется только от одного трейта, но можно наследоваться от нескольких.
@@ -314,14 +564,38 @@ customGreeter.greet("Scala developer") // How are you, Scala developer?
## Главный метод
-Главный метод является отправной точкой в программе.
+Главный метод является отправной точкой в программе.
Для Виртуальной Машины Java требуется, чтобы главный метод назывался `main` и принимал один аргумент, массив строк.
Используя объект, можно задать главный метод следующим образом:
-```tut
+{% tabs hello-world-demo class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=hello-world-demo %}
+
+In Scala 2 you must define a main method manually. Using an object, you can define the main method as follows:
+
+```scala mdoc
object Main {
def main(args: Array[String]): Unit =
println("Hello, Scala developer!")
}
```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=hello-world-demo %}
+
+In Scala 3, with the `@main` annotation, a main method is automatically generated from a method as follows:
+
+```scala
+@main def hello() = println("Hello, Scala developer!")
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+## Дополнительные ресурсы
+
+- Обзор [Scala book](/ru/scala3/book/taste-intro.html)
diff --git a/_ru/tour/by-name-parameters.md b/_ru/tour/by-name-parameters.md
index 9cd798b2ee..06c9a32063 100644
--- a/_ru/tour/by-name-parameters.md
+++ b/_ru/tour/by-name-parameters.md
@@ -1,27 +1,33 @@
---
layout: tour
title: Вызов по имени
-
-discourse: true
-
partof: scala-tour
-
num: 31
language: ru
next-page: annotations
previous-page: operators
-
---
_Вызов параметров по имени_ - это когда значение параметра вычисляется только в момент вызова параметра. Этот способ противоположен _вызову по значению_. Чтоб вызов параметра был по имени, необходимо просто указать `=>` перед его типом.
-```tut
+
+{% tabs by-name-parameters_1 %}
+{% tab 'Scala 2 и 3' for=by-name-parameters_1 %}
+
+```scala mdoc
def calculate(input: => Int) = input * 37
```
+
+{% endtab %}
+{% endtabs %}
+
Преимущество вызова параметров по имени заключается в том, что они не вычисляются если не используются в теле функции. С другой стороны плюсы вызова параметров по значению в том, что они вычисляются только один раз.
Вот пример того, как мы можем реализовать условный цикл:
-```tut
+{% tabs by-name-parameters_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=by-name-parameters_2 %}
+
+```scala mdoc
def whileLoop(condition: => Boolean)(body: => Unit): Unit =
if (condition) {
body
@@ -35,8 +41,29 @@ whileLoop (i > 0) {
i -= 1
} // выведет 2 1
```
-Метод `whileLoop` использует несколько списков параметров - условие и тело цикла. Если `condition` является верным, выполняется `body`, а затем выполняется рекурсивный вызов whileLoop. Если `condition` является ложным, то тело никогда не вычисляется, тк у нас стоит `=>` перед типом `body`.
+
+{% endtab %}
+{% tab 'Scala 3' for=by-name-parameters_2 %}
+
+```scala
+def whileLoop(condition: => Boolean)(body: => Unit): Unit =
+ if condition then
+ body
+ whileLoop(condition)(body)
+
+var i = 2
+
+whileLoop (i > 0) {
+ println(i)
+ i -= 1
+} // выведет 2 1
+```
+
+{% endtab %}
+{% endtabs %}
+
+Метод `whileLoop` использует несколько списков параметров - условие и тело цикла. Если `condition` является верным, выполняется `body`, а затем выполняется рекурсивный вызов whileLoop. Если `condition` является ложным, то тело никогда не вычисляется, тк у нас стоит `=>` перед типом `body`.
Теперь, когда мы передаем `i > 0` как наше условие `condition` и `println(i); i-= 1` как тело `body`, код ведет себя также как обычный цикл в большинстве языков программирования.
-Такая возможность откладывать вычисления параметра до его использования может помочь повысить производительность, отсекая не нужные вычисления при определенных условиях.
+Такая возможность откладывать вычисления параметра до его использования может помочь повысить производительность, отсекая не нужные вычисления при определенных условиях.
diff --git a/_ru/tour/case-classes.md b/_ru/tour/case-classes.md
index 13c3622587..467fc0655e 100644
--- a/_ru/tour/case-classes.md
+++ b/_ru/tour/case-classes.md
@@ -1,53 +1,90 @@
---
layout: tour
title: Классы Образцы
-
-discourse: true
-
partof: scala-tour
-
num: 11
language: ru
next-page: pattern-matching
previous-page: multiple-parameter-lists
prerequisite-knowledge: classes, basics, mutability
-
---
-Классы образцы (Case classes) похожи на обычные классы с несколькими ключевыми отличиями, о которых мы поговорим ниже. Классы образцы хороши для моделирования неизменяемых данных. На следующей странице обзора вы увидите, насколько они полезны для участия в [сопоставлении с примером](pattern-matching.html).
+Классы образцы (Case classes) похожи на обычные классы с несколькими ключевыми отличиями, о которых мы поговорим ниже.
+Классы образцы хороши для моделирования неизменяемых данных.
+На следующей странице обзора вы увидите, насколько они полезны для участия в [сопоставлении с примером](pattern-matching.html).
## Объявление класса образца
+
Минимальный вариант объявления класса образца: указание ключевого слова `case class`, название и список параметров (которые могут быть пустыми). Пример:
-```tut
+
+{% tabs case-classe_Book %}
+
+{% tab 'Scala 2 и 3' for=case-classe_Book %}
+
+```scala mdoc
case class Book(isbn: String)
val frankenstein = Book("978-0486282114")
```
-Обратите внимание, что ключевое слово `new` не было использовано для создания экземпляра класса `Book`. Это связано с тем, что классы образцы по умолчанию имеют объект компаньон с методом `apply`, который берет на себя заботу о создании экземпляра класса.
+
+{% endtab %}
+
+{% endtabs %}
+
+Обратите внимание, что ключевое слово `new` не было использовано для создания экземпляра класса `Book`.
+Это связано с тем, что классы образцы по умолчанию имеют объект компаньон с методом `apply`,
+который берет на себя заботу о создании экземпляра класса.
При создании класса образца с параметрами, эти параметры являются публичными и неизменяемыми.
+
+{% tabs case-classe_Message_define %}
+
+{% tab 'Scala 2 и 3' for=case-classe_Message_define %}
+
```
case class Message(sender: String, recipient: String, body: String)
val message1 = Message("guillaume@quebec.ca", "jorge@catalonia.es", "Ça va ?")
-println(message1.sender) // prints guillaume@quebec.ca
+println(message1.sender) // печатает guillaume@quebec.ca
message1.sender = "travis@washington.us" // эта строка не компилируется
```
-Вы не можете переназначить `message1.sender`, потому что это `val` (т.е. константа). Возможно использовать `var`s в классах образцах, но это не рекомендуется.
+
+{% endtab %}
+
+{% endtabs %}
+
+Вы не можете переназначить `message1.sender`, потому что это `val` (т.е. константа). Возможно использовать `var` в классах образцах, но это не рекомендуется.
## Сравнение
+
Классы образцы сравниваются по структуре, а не по ссылкам:
-```
+
+{% tabs case-classe_Message_compare %}
+
+{% tab 'Scala 2 и 3' for=case-classe_Message_compare %}
+
+```scala mdoc
case class Message(sender: String, recipient: String, body: String)
val message2 = Message("jorge@catalonia.es", "guillaume@quebec.ca", "Com va?")
val message3 = Message("jorge@catalonia.es", "guillaume@quebec.ca", "Com va?")
val messagesAreTheSame = message2 == message3 // true
```
-Даже если `message2` и `message3` ссылаются на разные объекты, значения каждого из них равна.
+
+{% endtab %}
+
+{% endtabs %}
+
+Даже если `message2` и `message3` ссылаются на разные объекты, значения каждого из них равны.
## Копирование
+
Вы можете создать копию экземпляра класса образца, просто воспользовавшись методом `copy`. При этом по желанию можно изменить аргументы конструктора.
+
+{% tabs case-classe_Message_copy %}
+
+{% tab 'Scala 2 и 3' for=case-classe_Message_copy %}
+
```
case class Message(sender: String, recipient: String, body: String)
val message4 = Message("julien@bretagne.fr", "travis@washington.us", "Me zo o komz gant ma amezeg")
@@ -56,4 +93,13 @@ message5.sender // travis@washington.us
message5.recipient // claire@bourgogne.fr
message5.body // "Me zo o komz gant ma amezeg"
```
+
+{% endtab %}
+
+{% endtabs %}
+
Получатель `message4` использует в качестве отправителя `message5`, кроме параметра `body` который был скопирован из `message4`.
+
+## Дополнительные ресурсы
+
+- Дополнительная информация о классах образцах доступна в [Scala Book](/ru/scala3/book/domain-modeling-tools.html#case-class-ы)
diff --git a/_ru/tour/classes.md b/_ru/tour/classes.md
index 0b5a7e0bec..75701bb107 100644
--- a/_ru/tour/classes.md
+++ b/_ru/tour/classes.md
@@ -1,32 +1,55 @@
---
layout: tour
title: Классы
-
-discourse: true
-
partof: scala-tour
-
num: 4
language: ru
next-page: traits
previous-page: unified-types
topics: classes
prerequisite-knowledge: no-return-keyword, type-declaration-syntax, string-interpolation, procedures
-
---
Классы в Scala являются основами для создания объектов. Они могут содержать методы, константы, переменные, типы, объекты, трейты и классы, которые в совокупности называются _членами_. Типы, объекты и трейты будут рассмотрены позже в ходе нашего обзора.
## Объявление класса
+
Минимальное объявление класса - это просто ключевое слово `class` и его имя. Имена классов должны быть написаны с заглавной буквы.
-```tut
+
+{% tabs class-minimal-user class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=class-minimal-user %}
+
+```scala mdoc
class User
val user1 = new User
```
-Ключевое слово `new` используется для создания экземпляра класса. `User` имеет конструктор по умолчанию, который не принимает аргументов, так как конструктор не был определен. Однако обычно используется и конструктор, и тело класса. Пример объявления класса Point приведен ниже:
-```tut
+Ключевое слово `new` используется для создания экземпляра класса.
+{% endtab %}
+
+{% tab 'Scala 3' for=class-minimal-user %}
+
+```scala
+class User
+
+val user1 = User()
+```
+
+Чтобы создать экземпляр класса, мы вызываем его как функцию: `User()`.
+Также можно явно использовать ключевое слово `new`: `new User()` - хотя обычно это опускается.
+{% endtab %}
+
+{% endtabs %}
+
+`User` имеет конструктор по умолчанию, который не принимает аргументов, так как конструктор не был определен. Однако обычно используется и конструктор, и тело класса. Пример объявления класса Point приведен ниже:
+
+{% tabs class-point-example class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=class-point-example %}
+
+```scala mdoc
class Point(var x: Int, var y: Int) {
def move(dx: Int, dy: Int): Unit = {
@@ -39,10 +62,34 @@ class Point(var x: Int, var y: Int) {
}
val point1 = new Point(2, 3)
-point1.x // 2
-println(point1) // prints (2, 3)
+println(point1.x) // выводит 2
+println(point1) // выводит (2, 3)
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=class-point-example %}
+
+```scala
+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 =
+ s"($x, $y)"
+end Point
+
+val point1 = Point(2, 3)
+println(point1.x) // выводит 2
+println(point1) // выводит (2, 3)
```
+{% endtab %}
+
+{% endtabs %}
+
В этом классе у `Point` есть четыре члена: переменные `x` и `y` и методы `move` и `toString`.
В отличие от многих других языков, основной конструктор находится в сигнатуре класса `(var x: Int, var y: Int)`. Метод `move` принимает два целочисленных аргумента и возвращает значение Unit `()` - это пустое множество, которое не содержит никакой информации. Примерно соответствует `void` в Java-подобных языках. С другой стороны, `toString` не принимает никаких аргументов, а возвращает значение `String`. Поскольку `toString` переопределяет `toString` из [`AnyRef`](unified-types.html), он помечается ключевым словом `override`.
@@ -50,61 +97,193 @@ println(point1) // prints (2, 3)
Конструкторы могут иметь необязательные параметры, если указать их значения по умолчанию как в примере:
-```tut
+{% tabs class-point-with-default-values class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=class-point-with-default-values %}
+
+```scala mdoc:nest
class Point(var x: Int = 0, var y: Int = 0)
-val origin = new Point // x и y оба равны 0
-val point1 = new Point(1)
-println(point1.x) // выводит 1
+val origin = new Point // x и y оба равны 0
+val point1 = new Point(1) // x равен 1, а y равен 0
+println(point1) // выводит (1, 0)
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=class-point-with-default-values %}
+
+```scala
+class Point(var x: Int = 0, var y: Int = 0)
+
+val origin = Point() // x и y оба равны 0
+val point1 = Point(1) // x равен 1, а y равен 0
+println(point1) // выводит (1, 0)
```
+{% endtab %}
+
+{% endtabs %}
+
В этой версии класса `Point`, `x` и `y` имеют значение по умолчанию `0`, поэтому аргументов не требуется. Однако, поскольку конструктор считывает аргументы слева направо, если вы просто хотите передать значение `y`, то вам нужно будет указать задаваемый параметр.
+
+{% tabs class-point-named-argument class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=class-point-named-argument %}
+
+```scala mdoc:nest
+class Point(var x: Int = 0, var y: Int = 0)
+val point2 = new Point(y = 2)
+println(point2) // выводит (0, 2)
```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=class-point-named-argument %}
+
+```scala
class Point(var x: Int = 0, var y: Int = 0)
-val point2 = new Point(y=2)
-println(point2.y) // выводит 2
+val point2 = Point(y = 2)
+println(point2) // выводит (0, 2)
```
+{% endtab %}
+
+{% endtabs %}
+
Что также является хорошей практикой для повышения ясности кода.
## Скрытые члены и синтаксис Геттер/Сеттер (получатель/установщик значений)
+
По умолчанию члены класса являются открытыми для внешнего доступа (публичными). Используйте модификатор `private`, чтобы скрыть их от внешнего доступа.
-```tut
+
+{% tabs class-point-private-getter-setter class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=class-point-private-getter-setter %}
+
+```scala mdoc:reset
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 x: Int = _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
+ def y: Int = _y
+ def y_=(newValue: Int): Unit = {
+ if (newValue < bound)
+ _y = newValue
+ else
+ printWarning()
}
- private def printWarning = println("WARNING: Out of bounds")
+ private def printWarning(): Unit =
+ println("WARNING: Out of bounds")
}
val point1 = new Point
point1.x = 99
point1.y = 101 // выводит предупреждение (printWarning)
```
-В данной версии класса `Point` данные хранятся в скрытых переменных `_x` и `_y`. Существуют методы `def x` и `def y` для доступа к скрытым данным. Методы `def x_=` и `def y_=` (сеттеры) предназначены для проверки и установки значения `_x` и `_y`. Обратите внимание на специальный синтаксис для сеттеров: метод `_=` применяется к имени геттера.
-Первичные параметры конструктора с параметрами `val` и `var` являются общедоступными. Однако, поскольку `val` - это константа, то нельзя писать следующее.
+{% endtab %}
+
+{% tab 'Scala 3' for=class-point-private-getter-setter %}
+
+```scala
+class Point:
+ private var _x = 0
+ private var _y = 0
+ private val bound = 100
+
+ def x: Int = _x
+ def x_=(newValue: Int): Unit =
+ if newValue < bound then
+ _x = newValue
+ else
+ printWarning()
+
+ def y: Int = _y
+ def y_=(newValue: Int): Unit =
+ if newValue < bound then
+ _y = newValue
+ else
+ printWarning()
+
+ private def printWarning(): Unit =
+ println("WARNING: Out of bounds")
+end Point
+
+val point1 = Point()
+point1.x = 99
+point1.y = 101 // выводит предупреждение (printWarning)
```
+
+{% endtab %}
+
+{% endtabs %}
+
+В данной версии класса `Point` данные хранятся в скрытых переменных `_x` и `_y`. Существуют методы `def x` и `def y` для доступа к скрытым данным. Методы `def x_=` и `def y_=` (сеттеры) предназначены для проверки и установки значения `_x` и `_y`. Обратите внимание на специальный синтаксис для сеттеров: метод `_=` применяется к имени геттера.
+
+Первичные параметры конструктора с параметрами `val` и `var` являются общедоступными. Однако, поскольку `val` - это константа, то нельзя писать следующее.
+
+{% tabs class-point-cannot-set-val class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=class-point-cannot-set-val %}
+
+```scala mdoc:fail
class Point(val x: Int, val y: Int)
val point = new Point(1, 2)
point.x = 3 // <-- не компилируется
```
-Параметры без `val` или `var` являются скрытыми от внешнего доступа и видимы только внутри класса.
+{% endtab %}
+
+{% tab 'Scala 3' for=class-point-cannot-set-val %}
+
+```scala
+class Point(val x: Int, val y: Int)
+val point = Point(1, 2)
+point.x = 3 // <-- не компилируется
```
+
+{% endtab %}
+
+{% endtabs %}
+
+Параметры без `val` или `var` являются скрытыми от внешнего доступа и видимы только внутри класса.
+
+{% tabs class-point-non-val-ctor-param class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=class-point-non-val-ctor-param %}
+
+```scala mdoc:fail
class Point(x: Int, y: Int)
val point = new Point(1, 2)
point.x // <-- не компилируется
```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=class-point-non-val-ctor-param %}
+
+```scala
+class Point(x: Int, y: Int)
+val point = Point(1, 2)
+point.x // <-- не компилируется
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+## Дополнительные ресурсы
+
+- Узнайте больше о классах в [Scala Book](/ru/scala3/book/domain-modeling-tools.html#классы)
+- Как использовать [вспомогательные конструкторы классов](/ru/scala3/book/domain-modeling-tools.html#вспомогательные-конструкторы)
diff --git a/_ru/tour/compound-types.md b/_ru/tour/compound-types.md
index 988900cab4..876bbaf42a 100644
--- a/_ru/tour/compound-types.md
+++ b/_ru/tour/compound-types.md
@@ -1,25 +1,26 @@
---
layout: tour
title: Составные Типы
-
-discourse: true
-
partof: scala-tour
-
num: 24
language: ru
next-page: self-types
previous-page: abstract-type-members
-
---
-Иногда необходимо выразить, то что тип объекта является подтипом нескольких других типов. В Scala это можно выразить с помощью *составных типов*, которые являются объединением нескольких типов объектов.
+Иногда необходимо выразить, то что тип объекта является подтипом нескольких других типов.
+
+В Scala это можно выразить с помощью _типов пересечений_ (или _составных типов_ в Scala 2),
+которые являются объединением нескольких типов объектов.
Предположим, у нас есть два трейта: `Cloneable` и `Resetable`:
-```tut
+{% tabs compound-types_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=compound-types_1 %}
+
+```scala mdoc
trait Cloneable extends java.lang.Cloneable {
- override def clone(): Cloneable = {
+ override def clone(): Cloneable = { // создает публичный метод 'clone'
super.clone().asInstanceOf[Cloneable]
}
}
@@ -28,9 +29,26 @@ trait Resetable {
}
```
-Теперь предположим, что мы хотим написать функцию `cloneAndReset`, которая берет объект, клонирует его и сбрасывает (Reset) состояние исходного объекта:
+{% endtab %}
+{% tab 'Scala 3' for=compound-types_1 %}
+```scala
+trait Cloneable extends java.lang.Cloneable:
+ override def clone(): Cloneable = // создает публичный метод 'clone'
+ super.clone().asInstanceOf[Cloneable]
+trait Resetable:
+ def reset: Unit
```
+
+{% endtab %}
+{% endtabs %}
+
+Теперь предположим, что мы хотим написать функцию `cloneAndReset`, которая берет объект, клонирует его и сбрасывает (Reset) состояние исходного объекта:
+
+{% tabs compound-types_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=compound-types_2 %}
+
+```scala mdoc:fail
def cloneAndReset(obj: ?): Cloneable = {
val cloned = obj.clone()
obj.reset
@@ -38,17 +56,49 @@ def cloneAndReset(obj: ?): Cloneable = {
}
```
-Возникает вопрос, какой тип параметр `obj` должна принимать наша объединённая функция. Если это `Cloneable`, то объект может использовать метод `clone`, но не `reset`; если это `Resetable` мы можем использовать метод `reset`, но нет операции `clone`. Чтобы избежать приведения типа в такой ситуации, мы можем указать, что тип `obj` является и `Cloneable`, и `Resetable`. Этот совместный тип в Scala записывается как: `Cloneable with Resetable`.
+{% endtab %}
+{% tab 'Scala 3' for=compound-types_2 %}
+
+```scala
+def cloneAndReset(obj: ?): Cloneable =
+ val cloned = obj.clone()
+ obj.reset
+ cloned
+```
+
+{% endtab %}
+{% endtabs %}
+
+Возникает вопрос, какой тип параметра `obj` должна принимать наша объединённая функция. Если это `Cloneable`, то объект может использовать метод `clone`, но не `reset`; если это `Resetable` мы можем использовать метод `reset`, но нет операции `clone`. Чтобы избежать приведения типа в такой ситуации, мы можем указать, что тип `obj` является и `Cloneable`, и `Resetable`.
+
+{% tabs compound-types_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=compound-types_3 %}
+Этот совместный тип в Scala записывается как: `Cloneable with Resetable`.
Вот обновленная функция:
-```
+```scala mdoc:fail
def cloneAndReset(obj: Cloneable with Resetable): Cloneable = {
//...
}
```
-Составные типы могут состоять из нескольких типов объектов, и они могут содержать единый доработанный объект, в котором будут доработаны характеристики существующих членов объекта.
-Общая форма записи: `A with B with C ... { доработанный объект }`
+Обратите внимание, что у вас может быть более двух типов: `A with B with C with ...`.
+Это означает то же самое, что и: `(...(A with B) with C) with ... )`
+
+{% endtab %}
+{% tab 'Scala 3' for=compound-types_3 %}
+Этот совместный тип в Scala записывается как: `Cloneable & Resetable`.
+
+Вот обновленная функция:
+
+```scala
+def cloneAndReset(obj: Cloneable & Resetable): Cloneable = {
+ //...
+}
+```
-Пример использования таких доработок приведен на странице об [объединении классов с примесями](mixin-class-composition.html).
+Обратите внимание, что у вас может быть более двух типов: `A & B & C & ...`.
+`&` является ассоциативным, поэтому скобки могут быть добавлены вокруг любой части без изменения значения.
+{% endtab %}
+{% endtabs %}
diff --git a/_ru/tour/default-parameter-values.md b/_ru/tour/default-parameter-values.md
index 7bf61e5430..c45b5dd419 100644
--- a/_ru/tour/default-parameter-values.md
+++ b/_ru/tour/default-parameter-values.md
@@ -1,44 +1,61 @@
---
layout: tour
title: Значения Параметров По умолчанию
-
-discourse: true
-
partof: scala-tour
-
num: 33
language: ru
next-page: named-arguments
-previous-page: annotations
+previous-page: classes
prerequisite-knowledge: named-arguments, function syntax
-
---
-Scala предоставляет возможность задавать значения параметров по умолчанию, что позволяет лишний раз не указывать параметры.
+Scala предоставляет возможность задавать значения параметров по умолчанию, что позволяет лишний раз не указывать параметры.
+
+{% tabs default-parameter-values-1 %}
+{% tab 'Scala 2 и 3' for=default-parameter-values-1 %}
-```tut
+```scala mdoc
def log(message: String, level: String = "INFO") = println(s"$level: $message")
log("System starting") // выведет "INFO: System starting"
log("User not found", "WARNING") // выведет "WARNING: User not found"
```
+{% endtab %}
+{% endtabs %}
+
У параметра `level` есть значение по умолчанию, поэтому он необязателен. В последней строке аргумент `"WARNING"` переназначает аргумент по умолчанию `"INFO"`. Вместо того чтоб использовать перегруженные методы в Java, вы можете просто указать дополнительные параметры как параметры по умолчанию для достижения того же эффекта. Однако, если при вызове пропущен хотя бы один аргумент, все остальные аргументы должны вызываться с указанием конкретного имени аргумента.
-```tut
+{% tabs default-parameter-values-2 %}
+{% tab 'Scala 2 и 3' for=default-parameter-values-2 %}
+
+```scala mdoc
class Point(val x: Double = 0, val y: Double = 0)
val point1 = new Point(y = 1)
```
+
+{% endtab %}
+{% endtabs %}
+
Так мы можем указать что `y = 1`.
Обратите внимание, что параметры по умолчанию в Scala, при вызове из Java кода, являются обязательными:
-```tut
+{% tabs default-parameter-values-3 %}
+{% tab 'Scala 2 и 3' for=default-parameter-values-3 %}
+
+```scala mdoc:reset
// Point.scala
class Point(val x: Double = 0, val y: Double = 0)
```
+{% endtab %}
+{% endtabs %}
+
+{% tabs default-parameter-values-4 %}
+{% tab 'Java' for=default-parameter-values-4 %}
+
```java
// Main.java
public class Main {
@@ -47,3 +64,37 @@ public class Main {
}
}
```
+
+{% endtab %}
+{% endtabs %}
+
+### Параметры по умолчанию для перегруженных методов
+
+Scala не позволяет определять два метода с параметрами по умолчанию и с одинаковым именем (перегруженные методы).
+Важная причина этого - избежание двусмысленности, которая может быть вызвана наличием параметров по умолчанию.
+Чтобы проиллюстрировать проблему, давайте рассмотрим определение методов, представленных ниже:
+
+{% tabs default-parameter-values-5 class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+
+```scala mdoc:fail
+object A {
+ def func(x: Int = 34): Unit
+ def func(y: String = "abc"): Unit
+}
+```
+
+{% endtab %}
+{% tab 'Scala 3' %}
+
+```scala
+object A:
+ def func(x: Int = 34): Unit
+ def func(y: String = "abc"): Unit
+```
+
+{% endtab %}
+{% endtabs %}
+
+Если мы вызываем `A.func()`, компилятор не может узнать,
+намеревался ли программист вызвать `func(x: Int = 34)` или `func(y: String = "abc")`.
diff --git a/_ru/tour/extractor-objects.md b/_ru/tour/extractor-objects.md
index d3824e69c3..f93981cd6c 100644
--- a/_ru/tour/extractor-objects.md
+++ b/_ru/tour/extractor-objects.md
@@ -1,26 +1,25 @@
---
layout: tour
title: Объект Экстрактор
-
-discourse: true
-
partof: scala-tour
-
num: 16
language: ru
next-page: for-comprehensions
previous-page: regular-expression-patterns
-
---
Объект Экстрактор (объект распаковщик или extractor object) - это объект с методом `unapply`. В то время как метод `apply` обычно действует как конструктор, который принимает аргументы и создает объект, метод `unapply` действует обратным образом, он принимает объект и пытается извлечь и вернуть аргументы из которых он (возможно) был создан. Чаще всего этот метод используется в функциях сопоставления с примером и в частично определенных функциях.
-```tut
+{% tabs extractor-objects_definition class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=extractor-objects_definition %}
+
+```scala mdoc
import scala.util.Random
object CustomerID {
- def apply(name: String) = s"$name--${Random.nextLong}"
+ def apply(name: String) = s"$name--${Random.nextLong()}"
def unapply(customerID: String): Option[String] = {
val stringArray: Array[String] = customerID.split("--")
@@ -34,32 +33,82 @@ customer1ID match {
case _ => println("Could not extract a CustomerID")
}
```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=extractor-objects_definition %}
+
+```scala
+import scala.util.Random
+
+object CustomerID:
+
+ def apply(name: String) = s"$name--${Random.nextLong()}"
+
+ def unapply(customerID: String): Option[String] =
+ val stringArray: Array[String] = customerID.split("--")
+ if stringArray.tail.nonEmpty then Some(stringArray.head) else None
+
+val customer1ID = CustomerID("Sukyoung") // Sukyoung--23098234908
+customer1ID match
+ case CustomerID(name) => println(name) // выведет Sukyoung
+ case _ => println("Could not extract a CustomerID")
+```
+
+{% endtab %}
+
+{% endtabs %}
+
Метод `apply` создает `CustomerID` из строки `name`. `unapply` делает обратное, чтобы вернуть `name` обратно. Когда мы вызываем `CustomerID("Sukyoung")`, это сокращенный синтаксис вызова `CustomerID.apply("Sukyoung")`. Когда мы вызываем `case CustomerID(name) => println(name)`, мы на самом деле вызываем метод `unapply`.
При объявлении нового значения можно использовать пример, в котором значение для инициализации переменной получается через извлечение, используя метод `unapply`.
-```tut
+{% tabs extractor-objects_use-case-1 %}
+
+{% tab 'Scala 2 и 3' for=extractor-objects_use-case-1 %}
+
+```scala mdoc
val customer2ID = CustomerID("Nico")
val CustomerID(name) = customer2ID
println(name) // выведет Nico
```
+{% endtab %}
+
+{% endtabs %}
+
Что эквивалентно `val name = CustomerID.unapply(customer2ID).get`.
-```tut
+{% tabs extractor-objects_use-case-2 %}
+
+{% tab 'Scala 2 и 3' for=extractor-objects_use-case-2 %}
+
+```scala mdoc
val CustomerID(name2) = "--asdfasdfasdf"
```
+{% endtab %}
+
+{% endtabs %}
+
Если совпадений нет, то бросается `scala.MatchError`:
-```tut:fail
+{% tabs extractor-objects_use-case-3 %}
+
+{% tab 'Scala 2 и 3' for=extractor-objects_use-case-3 %}
+
+```scala mdoc:crash
val CustomerID(name3) = "-asdfasdfasdf"
```
+{% endtab %}
+
+{% endtabs %}
+
Возвращаемый тип `unapply` выбирается следующим образом:
-* Если это всего лишь тест, возвращается `Boolean`. Например `case even()`.
-* Если в результате найдено одно значение типа `T`, то возвращается `Option[T]`.
-* Если вы хотите получить несколько значений `T1,..., Tn`, то ответ необходимо группировать в дополнительный кортеж `Option[(T1,..., Tn)]`.
+- Если это всего лишь тест, возвращается `Boolean`. Например `case even()`.
+- Если в результате найдено одно значение типа `T`, то возвращается `Option[T]`.
+- Если вы хотите получить несколько значений `T1,..., Tn`, то ответ необходимо группировать в дополнительный кортеж `Option[(T1,..., Tn)]`.
-Иногда количество извлекаемых значений не является фиксированным. Если в зависимости от входа мы хотим вернуть произвольное количество значений, то для этого случая мы можем определить экстрактор методом `unapplySeq`, который возвращает `Option[Seq[T]]`. Характерным примером такого подхода является разложение `List` с помощью `case List(x, y, z) =>` и разложение `String` с помощью регулярного выражения `Regex`, такого как `case r(name, remainingFields @ _*) =>`.
+Иногда количество извлекаемых значений не является фиксированным. Если в зависимости от входа мы хотим вернуть произвольное количество значений, то для этого случая мы можем определить экстрактор методом `unapplySeq`, который возвращает `Option[Seq[T]]`. Характерным примером такого подхода является разложение `List` с помощью `case List(x, y, z) =>` и разложение `String` с помощью регулярного выражения `Regex`, такого как `case r(name, remainingFields @ _*) =>`.
diff --git a/_ru/tour/for-comprehensions.md b/_ru/tour/for-comprehensions.md
index 5c79ca062c..8f6ae91bba 100644
--- a/_ru/tour/for-comprehensions.md
+++ b/_ru/tour/for-comprehensions.md
@@ -1,66 +1,132 @@
---
layout: tour
title: Сложные for-выражения
-
-discourse: true
-
partof: scala-tour
-
num: 17
language: ru
next-page: generic-classes
previous-page: extractor-objects
-
---
-Scala предлагает простую запись для выражения *последовательных преобразований*. Эти преобразования можно упростить используя специальный синтаксис `for выражения` (for comprehension), который записывается как `for (enumerators) yield e`, где `enumerators` относятся к списку перечислителей, разделенных точкой с запятой. Где отдельный такой "перечислитель" (*enumerator*) является либо генератором, который вводит новые переменные, либо фильтром. For-выражение вычисляет тело `e` (которое связанно с тем что генерирует *enumerator*) и возвращает последовательность вычислений.
+Scala предлагает простую запись для выражения _последовательных преобразований_. Эти преобразования можно упростить используя специальный синтаксис `for выражения` (for comprehension), который записывается как `for (enumerators) yield e`, где `enumerators` относятся к списку перечислителей, разделенных точкой с запятой. Где отдельный такой "перечислитель" (_enumerator_) является либо генератором, который вводит новые переменные, либо фильтром. For-выражение вычисляет тело `e` (которое связанно с тем что генерирует _enumerator_) и возвращает последовательность вычислений.
Вот пример:
-```tut
+{% tabs for-comprehensions-01 class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-comprehensions-01 %}
+
+```scala mdoc
case class User(name: String, age: Int)
-val userBase = List(User("Travis", 28),
+val userBase = List(
+ User("Travis", 28),
User("Kelly", 33),
User("Jennifer", 44),
User("Dennis", 23))
-val twentySomethings = for (user <- userBase if (user.age >=20 && user.age < 30))
- yield user.name // т. е. добавить результат к списку
+val twentySomethings =
+ for (user <- userBase if user.age >=20 && user.age < 30)
+ yield user.name // т. е. добавить результат к списку
-twentySomethings.foreach(name => println(name)) // выводит "Travis Dennis"
+twentySomethings.foreach(println) // выводит "Travis Dennis"
```
- `for`-выражение, используется с оператором `yield`, на самом деле создает `List`. Потому что мы указали `yield user.name` (то есть вывести имя пользователя), получаем `List[String]`. `user <- userBase` и есть наш генератор, а `if (user.age >=20 && user.age < 30)` - это фильтр который отфильтровывает пользователей, не достигших 20-летнего возраста.
+
+{% endtab %}
+{% tab 'Scala 3' for=for-comprehensions-01 %}
+
+```scala
+case class User(name: String, age: Int)
+
+val userBase = List(
+ User("Travis", 28),
+ User("Kelly", 33),
+ User("Jennifer", 44),
+ User("Dennis", 23))
+
+val twentySomethings =
+ for user <- userBase if user.age >=20 && user.age < 30
+ yield user.name // т. е. добавить результат к списку
+
+twentySomethings.foreach(println) // выводит "Travis Dennis"
+```
+
+{% endtab %}
+{% endtabs %}
+
+`for`-выражение, используется с оператором `yield`, на самом деле создает `List`. Потому что мы указали `yield user.name` (то есть вывести имя пользователя), получаем `List[String]`. `user <- userBase` и есть наш генератор, а `if (user.age >=20 && user.age < 30)` - это фильтр который отфильтровывает пользователей, не достигших 30-летнего возраста.
Ниже приведен более сложный пример использования двух генераторов. Он вычисляет все пары чисел между `0` и `n-1`, сумма которых равна заданному значению `v`:
-```tut
+{% tabs for-comprehensions-02 class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-comprehensions-02 %}
+
+```scala mdoc
def foo(n: Int, v: Int) =
for (i <- 0 until n;
- j <- i until n if i + j == v)
+ j <- 0 until n if i + j == v)
yield (i, j)
-foo(10, 10) foreach {
+foo(10, 10).foreach {
case (i, j) =>
- println(s"($i, $j) ") // выводит (1, 9) (2, 8) (3, 7) (4, 6) (5, 5)
+ println(s"($i, $j) ") // выводит (1, 9) (2, 8) (3, 7) (4, 6) (5, 5) (6, 4) (7, 3) (8, 2) (9, 1)
}
+```
+{% endtab %}
+{% tab 'Scala 3' for=for-comprehensions-02 %}
+
+```scala
+def foo(n: Int, v: Int) =
+ for i <- 0 until n
+ j <- 0 until n if i + j == v
+ yield (i, j)
+
+foo(10, 10).foreach {
+ (i, j) => println(s"($i, $j) ") // выводит (1, 9) (2, 8) (3, 7) (4, 6) (5, 5) (6, 4) (7, 3) (8, 2) (9, 1)
+}
```
+
+{% endtab %}
+{% endtabs %}
+
Здесь `n == 10` и `v == 10`. На первой итерации `i == 0` и `j == 0` так `i + j != v` и поэтому ничего не выдается. `j` увеличивается еще в 9 раз, прежде чем `i` увеличивается до `1`. Без фильтра `if` будет просто напечатано следующее:
-```
-(0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (0, 5) (0, 6) (0, 7) (0, 8) (0, 9) (1, 1) ...
+```scala
+(0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (0, 5) (0, 6) (0, 7) (0, 8) (0, 9) (1, 0) ...
```
Обратите внимание, что for-выражение не ограничивается только работой со списками. Каждый тип данных, поддерживающий операции `withFilter`, `map`, and `flatMap` (с соответствующими типами), может быть использован в for-выражении.
Вы можете обойтись без `yield` в for-выражении. В таком случае, результатом будет `Unit`. Это может быть полезным для выполнения кода основанного на побочных эффектах. Вот программа, эквивалентная предыдущей, но без использования `yield`:
-```tut
+{% tabs for-comprehensions-03 class=tabs-scala-version %}
+{% tab 'Scala 2' for=for-comprehensions-03 %}
+
+```scala mdoc:nest
def foo(n: Int, v: Int) =
for (i <- 0 until n;
- j <- i until n if i + j == v)
+ j <- 0 until n if i + j == v)
println(s"($i, $j)")
foo(10, 10)
```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=for-comprehensions-03 %}
+
+```scala
+def foo(n: Int, v: Int) =
+ for i <- 0 until n
+ j <- 0 until n if i + j == v
+ do println(s"($i, $j)")
+
+foo(10, 10)
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Дополнительные ресурсы
+
+- Другие примеры "For comprehension" доступны [в книге Scala](/ru/scala3/book/control-structures.html#выражение-for)
diff --git a/_ru/tour/generic-classes.md b/_ru/tour/generic-classes.md
index 30587567ca..591f810cfd 100644
--- a/_ru/tour/generic-classes.md
+++ b/_ru/tour/generic-classes.md
@@ -1,26 +1,28 @@
---
layout: tour
title: Обобщенные Классы
-
-discourse: true
-
partof: scala-tour
-
num: 18
language: ru
next-page: variances
previous-page: for-comprehensions
assumed-knowledge: classes unified-types
-
---
+
Обобщенные классы (Generic classes) - это классы, обладающие параметрическим полиморфизмом (т. е. классы, которые изменяют свое поведение в зависимости от приписываемого им типа. Этот тип указывается в квадратных скобках `[]` сразу после имени класса). Они особенно полезны для создания коллекций.
## Объявление обобщенного класса
+
Для объявления обобщенного класса необходимо после имени добавить тип в квадратных скобках `[]` как еще один параметр класса. По соглашению обычно используют заглавные буквы `A`, хотя можно использовать любые имена.
-```tut
+
+{% tabs generic-classes-1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=generic-classes-1 %}
+
+```scala mdoc
class Stack[A] {
private var elements: List[A] = Nil
- def push(x: A) { elements = x :: elements }
+ def push(x: A): Unit =
+ elements = x :: elements
def peek: A = elements.head
def pop(): A = {
val currentTop = peek
@@ -29,20 +31,64 @@ class Stack[A] {
}
}
```
-Данная реализация класса `Stack` принимает в качестве параметра любой тип `A`. Это означает что список, `var elements: List[A] = Nil`, может хранить только элементы типа `A`. Процедура `def push` принимает только объекты типа `A` (примечание: `elements = x :: elements` переназначает `elements` в новый список, созданный путем добавления `x`а к текущим `elements`).
+
+{% endtab %}
+{% tab 'Scala 3' for=generic-classes-1 %}
+
+```scala
+class Stack[A]:
+ private var elements: List[A] = Nil
+ def push(x: A): Unit =
+ elements = x :: elements
+ def peek: A = elements.head
+ def pop(): A =
+ val currentTop = peek
+ elements = elements.tail
+ currentTop
+```
+
+{% endtab %}
+{% endtabs %}
+
+Данная реализация класса `Stack` принимает в качестве параметра любой тип `A`. Это означает что список, `var elements: List[A] = Nil`, может хранить только элементы типа `A`. Процедура `def push` принимает только объекты типа `A` (примечание: `elements = x :: elements` переназначает `elements` в новый список, созданный путем добавления `x` к текущим `elements`).
+
+Здесь `Nil` — это пустой `List`, и его не следует путать с `null`.
## Использование
Чтобы использовать обобщенный класс, поместите конкретный тип в квадратные скобки вместо `A`.
-```
+
+{% tabs generic-classes-2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=generic-classes-2 %}
+
+```scala mdoc
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
-println(stack.pop) // выведет 2
-println(stack.pop) // выведет 1
+println(stack.pop()) // выведет 2
+println(stack.pop()) // выведет 1
```
-Экземпляр `stack` может принимать только Intы. Однако, если тип имеет подтипы, то они также могут быть приняты:
+
+{% endtab %}
+{% tab 'Scala 3' for=generic-classes-2 %}
+
+```scala
+val stack = Stack[Int]
+stack.push(1)
+stack.push(2)
+println(stack.pop()) // выведет 2
+println(stack.pop()) // выведет 1
```
+
+{% endtab %}
+{% endtabs %}
+
+Экземпляр `stack` может принимать элементы типа `Int`. Однако, если тип имеет подтипы, то они также могут быть приняты:
+
+{% tabs generic-classes-3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=generic-classes-3 %}
+
+```scala mdoc:nest
class Fruit
class Apple extends Fruit
class Banana extends Fruit
@@ -54,6 +100,25 @@ val banana = new Banana
stack.push(apple)
stack.push(banana)
```
+
+{% endtab %}
+{% tab 'Scala 3' for=generic-classes-3 %}
+
+```scala
+class Fruit
+class Apple extends Fruit
+class Banana extends Fruit
+
+val stack = Stack[Fruit]
+val apple = Apple()
+val banana = Banana()
+
+stack.push(apple)
+stack.push(banana)
+```
+
+{% endtab %}
+{% endtabs %}
Классы `Apple` и `Banana` наследуются от `Fruit` так, что мы можем засунуть экземпляры `Apple` и `Banana` в пачку `Fruit`.
_Примечание: подтипы обобщенных типов - *инвариантны*. Это означает, что если у нас есть стэк символов типа `Stack[Char]`, то он не может быть использован как стек интов типа `Stack[Int]`. Это нежелательное поведение, потому как позволило бы нам добавлять в стек символов целые числа. В заключение, `Stack[A]` является подтипом `Stack[B]` тогда и только тогда, когда `B = A`. Поскольку это может быть довольно строгим ограничением, Scala предлагает [механизм вариативного описания параметров типа](variances.html) для контроля за поведением подтипов._
diff --git a/_ru/tour/higher-order-functions.md b/_ru/tour/higher-order-functions.md
index 6df55532e9..b55b4d9b24 100644
--- a/_ru/tour/higher-order-functions.md
+++ b/_ru/tour/higher-order-functions.md
@@ -1,47 +1,81 @@
---
layout: tour
title: Функции Высшего Порядка
-
-discourse: true
-
partof: scala-tour
-
num: 8
language: ru
next-page: nested-functions
previous-page: mixin-class-composition
-
---
-Функции высшего порядка могут принимать другие функции в качестве параметров или возвращать функцию в качестве результата
-Такое возможно поскольку функции являются объектами первого класса в Scala.
-На текущем этапе терминология может казаться немного запутанной, мы используем следующую фразу "функция высшего порядка" как для методов, так и для функций, которые могут принимать другие функции в качестве параметров, или возвращать функции в качестве результата.
+Функции высшего порядка могут принимать другие функции в качестве параметров или возвращать функцию в качестве результата.
+Такое возможно поскольку функции являются объектами первого класса в Scala.
+На текущем этапе терминология может казаться немного запутанной, мы используем следующую фразу "функция высшего порядка" как для методов, так и для функций, которые могут принимать другие функции в качестве параметров, или возвращать функции в качестве результата.
+
+В чисто объектно-ориентированном мире рекомендуется избегать раскрытия методов,
+параметризованных функциями, которые могут привести к утечке внутреннего состояния объекта.
+Утечка внутреннего состояния может нарушить инварианты самого объекта, тем самым нарушив инкапсуляцию.
-Одним из наиболее распространенных примеров функции высшего порядка
+Одним из наиболее распространенных примеров функции высшего порядка
является функция `map`, которая доступна в коллекциях Scala.
-```tut
-val salaries = Seq(20000, 70000, 40000)
+
+{% tabs map_example_1 %}
+
+{% tab 'Scala 2 и 3' for=map_example_1 %}
+
+```scala mdoc:nest
+val salaries = Seq(20_000, 70_000, 40_000)
val doubleSalary = (x: Int) => x * 2
val newSalaries = salaries.map(doubleSalary) // List(40000, 140000, 80000)
```
+
+{% endtab %}
+
+{% endtabs %}
+
`doubleSalary` - это функция, которая принимает один Int `x` и возвращает `x * 2`. В общем случае, кортеж (список имен в скобках) слева от стрелки `=>` - это список параметров, а значение выражения следует справа. Это же значение возвращается в качестве результата. В строке 3 к каждому элементу списка зарплат (salaries) применяется функция `doubleSalary`.
Чтобы сократить код, мы можем сделать функцию анонимной и передать ее напрямую в качестве аргумента в map:
-```
-val salaries = Seq(20000, 70000, 40000)
+
+{% tabs map_example_2 %}
+
+{% tab 'Scala 2 и 3' for=map_example_2 %}
+
+```scala mdoc:nest
+val salaries = Seq(20_000, 70_000, 40_000)
val newSalaries = salaries.map(x => x * 2) // List(40000, 140000, 80000)
```
+
+{% endtab %}
+
+{% endtabs %}
+
Обратите внимание, что в приведенном выше примере `x`не объявлен как `Int`. Это потому, что компилятор может вывести тип, основываясь на типе который ожидает функция map. Еще более элегантным способом написания этого же кода было бы таким:
-```tut
-val salaries = Seq(20000, 70000, 40000)
+{% tabs map_example_3 %}
+
+{% tab 'Scala 2 и 3' for=map_example_3 %}
+
+```scala mdoc:nest
+val salaries = Seq(20_000, 70_000, 40_000)
val newSalaries = salaries.map(_ * 2)
```
+
+{% endtab %}
+
+{% endtabs %}
+
Поскольку компилятор Scala уже знает тип параметров (Int), вам нужно только указать правую часть функции. Единственное условие заключается в том, что вместо имени параметра необходимо использовать `_` (в предыдущем примере это было `x`).
## Преобразование методов в функции
+
Также возможно передавать методы в качестве аргументов функциям более высокого порядка, поскольку компилятор Scala может преобразовать метод в функцию.
-```
+
+{% tabs Coercing_methods_into_functions class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=Coercing_methods_into_functions %}
+
+```scala mdoc
case class WeeklyWeatherForecast(temperatures: Seq[Double]) {
private def convertCtoF(temp: Double) = temp * 1.8 + 32
@@ -49,12 +83,34 @@ case class WeeklyWeatherForecast(temperatures: Seq[Double]) {
def forecastInFahrenheit: Seq[Double] = temperatures.map(convertCtoF) // <-- передается метод convertCtoF
}
```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=Coercing_methods_into_functions %}
+
+```scala
+case class WeeklyWeatherForecast(temperatures: Seq[Double]):
+
+ private def convertCtoF(temp: Double) = temp * 1.8 + 32
+
+ def forecastInFahrenheit: Seq[Double] = temperatures.map(convertCtoF) // <-- передается метод convertCtoF
+```
+
+{% endtab %}
+
+{% endtabs %}
+
Здесь метод `convertCtoF` передается в `forecastInFahrenheit`. Это возможно, потому что компилятор преобразовывает `convertCtoF` в функцию `x => ConvertCtoF(x)` (примечание: `x` будет сгенерированным именем, которое гарантированно будет уникальным в рамках своей области видимости).
## Функции, которые принимают функции
+
Одной из причин использования функций высшего порядка является сокращение избыточного кода. Допустим, вам нужны какие-то методы, которые могли бы повышать чью-то зарплату по разным условиям. Без создания функции высшего порядка это могло бы выглядеть примерно так:
-```tut
+{% tabs Functions_that_accept_functions_1 class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=Functions_that_accept_functions_1 %}
+
+```scala mdoc
object SalaryRaiser {
def smallPromotion(salaries: List[Double]): List[Double] =
@@ -68,9 +124,34 @@ object SalaryRaiser {
}
```
+{% endtab %}
+
+{% tab 'Scala 3' for=Functions_that_accept_functions_1 %}
+
+```scala
+object SalaryRaiser:
+
+ def smallPromotion(salaries: List[Double]): List[Double] =
+ salaries.map(salary => salary * 1.1)
+
+ def greatPromotion(salaries: List[Double]): List[Double] =
+ salaries.map(salary => salary * math.log(salary))
+
+ def hugePromotion(salaries: List[Double]): List[Double] =
+ salaries.map(salary => salary * salary)
+```
+
+{% endtab %}
+
+{% endtabs %}
+
Обратите внимание, что каждый из этих трех методов отличается только коэффициентом умножения. Для упрощения можно перенести повторяющийся код в функцию высшего порядка:
-```tut
+{% tabs Functions_that_accept_functions_2 class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=Functions_that_accept_functions_2 %}
+
+```scala mdoc:nest
object SalaryRaiser {
private def promotion(salaries: List[Double], promotionFunction: Double => Double): List[Double] =
@@ -79,7 +160,7 @@ object SalaryRaiser {
def smallPromotion(salaries: List[Double]): List[Double] =
promotion(salaries, salary => salary * 1.1)
- def bigPromotion(salaries: List[Double]): List[Double] =
+ def greatPromotion(salaries: List[Double]): List[Double] =
promotion(salaries, salary => salary * math.log(salary))
def hugePromotion(salaries: List[Double]): List[Double] =
@@ -87,13 +168,45 @@ object SalaryRaiser {
}
```
+{% endtab %}
+
+{% tab 'Scala 3' for=Functions_that_accept_functions_2 %}
+
+```scala
+object SalaryRaiser:
+
+ private def promotion(salaries: List[Double], promotionFunction: Double => Double): List[Double] =
+ salaries.map(promotionFunction)
+
+ def smallPromotion(salaries: List[Double]): List[Double] =
+ promotion(salaries, salary => salary * 1.1)
+
+ def greatPromotion(salaries: List[Double]): List[Double] =
+ promotion(salaries, salary => salary * math.log(salary))
+
+ def hugePromotion(salaries: List[Double]): List[Double] =
+ promotion(salaries, salary => salary * salary)
+```
+
+{% endtab %}
+
+{% endtabs %}
+
Новый метод, `promotion`, берет зарплату и функцию типа `Double => Double` (т.е. функция, которая берет Double и возвращает Double) и возвращает их произведение.
+Методы и функции обычно выражают поведение или преобразование данных, поэтому наличие функций,
+которые компонуются на основе других функций, может помочь в создании общих механизмов.
+Эти типовые функции откладывают блокировку всего поведения операции,
+предоставляя клиентам возможность контролировать или дополнительно настраивать части самой операции.
## Функции, возвращающие функции
Есть определенные случаи, когда вы хотите сгенерировать функцию. Вот пример метода, который возвращает функцию.
-```tut
+{% tabs Functions_that_return_functions class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=Functions_that_return_functions %}
+
+```scala mdoc
def urlBuilder(ssl: Boolean, domainName: String): (String, String) => String = {
val schema = if (ssl) "https://" else "http://"
(endpoint: String, query: String) => s"$schema$domainName/$endpoint?$query"
@@ -106,4 +219,24 @@ val query = "id=1"
val url = getURL(endpoint, query) // "https://www.example.com/users?id=1": String
```
-Обратите внимание, что возвращаемый тип urlBuilder`(String, String) => String`. Это означает, что возвращаемая анонимная функция принимает две строки и возвращает строку. В нашем случае возвращаемая анонимная функция `(endpoint: String, query: String) => s"https://www.example.com/$endpoint?$query"`.
\ No newline at end of file
+{% endtab %}
+
+{% tab 'Scala 3' for=Functions_that_return_functions %}
+
+```scala
+def urlBuilder(ssl: Boolean, domainName: String): (String, String) => String =
+ val schema = if ssl then "https://" else "http://"
+ (endpoint: String, query: String) => s"$schema$domainName/$endpoint?$query"
+
+val domainName = "www.example.com"
+def getURL = urlBuilder(ssl=true, domainName)
+val endpoint = "users"
+val query = "id=1"
+val url = getURL(endpoint, query) // "https://www.example.com/users?id=1": String
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+Обратите внимание, что возвращаемый тип urlBuilder`(String, String) => String`. Это означает, что возвращаемая анонимная функция принимает две строки и возвращает строку. В нашем случае возвращаемая анонимная функция `(endpoint: String, query: String) => s"https://www.example.com/$endpoint?$query"`.
diff --git a/_ru/tour/implicit-conversions.md b/_ru/tour/implicit-conversions.md
index 1040f47f9b..5e3001862d 100644
--- a/_ru/tour/implicit-conversions.md
+++ b/_ru/tour/implicit-conversions.md
@@ -1,63 +1,52 @@
---
layout: tour
title: Неявные Преобразования
-
-discourse: true
-
partof: scala-tour
-
num: 27
language: ru
next-page: polymorphic-methods
previous-page: implicit-parameters
-
---
-Неявные преобразование типа `S` к типу `T` задается неявным значением функционального типа `S =>T`, или неявным методом, который способен преобразовывать к значению требуемого типа.
+Неявные преобразования — это мощная функция Scala, применяемая в двух распространенных вариантах:
-Неявное преобразование применяются в двух случаях:
+- разрешить пользователям предоставлять аргумент одного типа так, как если бы это был другой тип, чтобы избежать шаблонного.
+- в Scala 2 для предоставления дополнительных членов запечатанным классам (заменены [методами расширения][exts] в Scala 3).
-* Если выражение `e` типа `S` не подходит под ожидаемый тип выражения `T`.
-* Если мы выбирая член `e.m`, где `e` является представителем типа `S`, при этом выбранное имя `m` не найдено среди доступных селекторов принадлежащих типу `S`.
-
-В первом случае выполняется поиск приведения `c`, которое можно применить к `e` чтоб тип результата стал соответствовать ожидаемому `T`.
-Во втором случае выполняется поиск преобразования `c`, которое применимо к `e` и результат которого бы содержал член с именем `m`.
+### Детальный разбор
-Если неявный метод `List[A] => Ordered[List[A]]` находится в области видимости, также как и неявный метод `Int => Ordered[Int]`, то следующая операция с двумя списками типа `List[Int]` является допустимой:
+{% tabs implicit-conversion-defn class=tabs-scala-version %}
+{% tab 'Scala 2' %}
-```
-List(1, 2, 3) <= List(4, 5)
-```
+В Scala 2 неявное преобразование из типа `S` в тип `T` определяется либо [неявным классом]({% link _overviews/core/implicit-classes.md %}) `T`
+с одним параметром типа `S`, [неявным значением](implicit-parameters.html), которое имеет тип функции `S => T`,
+либо неявным методом, преобразуемым в значение этого типа.
-Неявный метод `Int => Ordered[Int]` предоставляется автоматически через `scala.Predef.intWrapper`. Ниже приведен пример объявления неявного метода `List[A] => Ordered[List[A]]`.
+{% endtab %}
+{% tab 'Scala 3' %}
-```tut
-import scala.language.implicitConversions
+В Scala 3 неявное преобразование из типа `S` в тип `T` определяется [экземпляром `given`](implicit-parameters.html), который имеет тип `scala.Conversion[S, T]`.
+Для совместимости со Scala 2 их также можно определить неявным методом (подробнее читайте во вкладке Scala 2).
-implicit def list2ordered[A](x: List[A])
- (implicit elem2ordered: A => Ordered[A]): Ordered[List[A]] =
- new Ordered[List[A]] {
- //заменить на более полезную реализацию
- def compare(that: List[A]): Int = 1
- }
-```
+{% endtab %}
+{% endtabs %}
-Неявно импортируемый объект `scala.Predef` объявляет ряд псевдонимов для часто используемым типов (например, `scala.collection.immutable.Map` использует псевдоним `Map`) и методов (например, `assert`), а также делает доступным целую серию неявных преобразований.
+Неявные преобразования применяются в двух случаях:
-Например, при вызове Java метода, который ожидает `java.lang.Integer`, вместо него вы можете свободно использовать `scala.Int`. Потому что Predef включает в себя следующие неявные преобразования:
+1. Если выражение `e` имеет тип `S` и `S` не соответствует ожидаемому типу выражения `T`.
+2. При выборе `e.m`, где `e` типа `S`, если селектор `m` не указывает на элемент `S`.
-```tut
-import scala.language.implicitConversions
+В первом случае ищется конверсия `c`, применимая к `e` и тип результата которой соответствует `T`.
-implicit def int2Integer(x: Int) =
- java.lang.Integer.valueOf(x)
-```
+Примером является передача `scala.Int`, например `x`, методу, который ожидает `scala.Long`.
+В этом случае вставляется неявное преобразование `Int.int2long(x)`.
-Компилятор предупреждает при компиляции об обнаружении неявных преобразований, тк неявные преобразования могут иметь разные подводные камни (особенно если использовать их без разбора).
+Во втором случае ищется преобразование `c`, применимое к `e` и результат которого содержит элемент с именем `m`.
-Чтоб отключить предупреждения выполните одно из следующих действий:
+Примером является сравнение двух строк `"foo" < "bar"`.
+В этом случае `String` не имеет члена `<`, поэтому вставляется неявное преобразование `Predef.augmentString("foo") < "bar"`
+(`scala.Predef` автоматически импортируется во все программы Scala).
-* Импортируйте `scala.language.implicitConversions` в области видимости, где объявлены неявные преобразования.
-* Вызывайте компилятор с ключом `-language:implicitConversions`.
+Дополнительная литература: [Неявные преобразования (в книге Scala)](/ru/scala3/book/ca-implicit-conversions.html).
-В таком случае при преобразовании компилятором не будет выдаваться никаких предупреждений.
+[exts]: /ru/scala3/book/ca-extension-methods.html
diff --git a/_ru/tour/implicit-parameters.md b/_ru/tour/implicit-parameters.md
index e9f7756e15..14f11c299c 100644
--- a/_ru/tour/implicit-parameters.md
+++ b/_ru/tour/implicit-parameters.md
@@ -1,73 +1,111 @@
---
layout: tour
-title: Неявные Параметры
-
-discourse: true
-
+title: Контекстные параметры, также известные, как неявные параметры
partof: scala-tour
-
num: 26
language: ru
next-page: implicit-conversions
previous-page: self-types
-
---
-Метод может иметь список _неявных_ параметров, помеченный ключевым словом _implicit_ в начале списка параметров. Если параметры в этом списке не передаются как обычно, то Scala будет искать, где можно получить неявное значение требуемого типа, и если найдет, то передаст его автоматически.
-
-Места, где Scala будет искать эти параметры, делятся на две категории:
+Метод может иметь список _контекстных параметров_ (_contextual parameters_),
+также называемых _неявными параметрами_ (_implicit parameters_) или, точнее, _имплицитами_ (_implicits_).
+Списки параметров, начинающиеся с ключевого слова `using` (или `implicit` в Scala 2), задают контекстные параметры.
+Если сторона вызова явно не предоставляет аргументы для таких параметров,
+Scala будет искать неявно доступные `given` (или `implicit` в Scala 2) значения правильного типа.
+Если можно найти подходящие значения, то они автоматически передаются.
-* Скала сначала будет искать неявные параметры, доступ к которым можно получить напрямую (без префикса) в месте вызова метода в котором запрошены неявные параметры.
-* Затем он ищет членов, помеченных как implicit во всех объектах компаньонах, связанных с типом неявного параметра.
+Лучше всего вначале показать это на небольшом примере.
+Мы определяем интерфейс `Comparator[A]`, который может сравнивать элементы типа `A`,
+и предоставляем две реализации для `Int`-ов и `String`-ов.
+Затем мы определяем метод `max[A](x: A, y: A)`, который возвращает больший из двух аргументов.
+Так как `x` и `y` имеют абстрактный тип, в общем случае мы не знаем, как их сравнивать, но можем запросить соответствующий компаратор.
+Поскольку обычно для любого заданного типа существует канонический компаратор `A`,
+то мы можем объявить их как _заданные_ (_given_) или _неявно_ (_implicitly_) доступные.
-Более подробное руководство, о том где scala ищет неявные значения можно найти в [FAQ](//docs.scala-lang.org/tutorials/FAQ/finding-implicits.html)
+{% tabs implicits-comparator class=tabs-scala-version %}
-В следующем примере мы определяем метод `sum`, который вычисляет сумму элементов списка, используя операции `add` и `unit` моноида. Обратите внимание, что неявные значения не могут находится выше уровнем.
+{% tab 'Scala 2' for=implicits-comparator %}
-```tut
-abstract class Monoid[A] {
- def add(x: A, y: A): A
- def unit: A
+```scala mdoc
+trait Comparator[A] {
+ def compare(x: A, y: A): Int
}
-object ImplicitTest {
- implicit val stringMonoid: Monoid[String] = new Monoid[String] {
- def add(x: String, y: String): String = x concat y
- def unit: String = ""
- }
-
- implicit val intMonoid: Monoid[Int] = new Monoid[Int] {
- def add(x: Int, y: Int): Int = x + y
- def unit: Int = 0
+object Comparator {
+ implicit object IntComparator extends Comparator[Int] {
+ def compare(x: Int, y: Int): Int = Integer.compare(x, y)
}
-
- def sum[A](xs: List[A])(implicit m: Monoid[A]): A =
- if (xs.isEmpty) m.unit
- else m.add(xs.head, sum(xs.tail))
-
- def main(args: Array[String]): Unit = {
- println(sum(List(1, 2, 3))) // использует intMonoid неявно
- println(sum(List("a", "b", "c"))) // использует stringMonoid неявно
+
+ implicit object StringComparator extends Comparator[String] {
+ def compare(x: String, y: String): Int = x.compareTo(y)
}
}
+
+def max[A](x: A, y: A)(implicit comparator: Comparator[A]): A =
+ if (comparator.compare(x, y) >= 0) x
+ else y
+
+println(max(10, 6)) // 10
+println(max("hello", "world")) // world
```
-`Monoid` определяет здесь операцию под названием `add`, которая сочетает два элемента типа `A` и возвращает сумму типа `A`, операция `unit` позволяет вернуть отдельный (специфичный) элемент типа `A`.
+```scala mdoc:fail
+// не компилируется:
+println(max(false, true))
+// ^
+// error: could not find implicit value for parameter comparator: Comparator[Boolean]
+```
+
+Параметр `comparator` автоматически заполняется значением `Comparator.IntComparator` для `max(10, 6)`
+и `Comparator.StringComparator` для `max("hello", "world")`.
+Поскольку нельзя найти неявный `Comparator[Boolean]`, вызов `max(false, true)` не компилируется.
-Чтобы показать, как работают неявные параметры, сначала определим моноиды `stringMonoid` и `intMonoid` для строк и целых чисел, соответственно. Ключевое слово `implicit` указывает на то, что этот объект может быть использован неявно.
+{% endtab %}
-Метод `sum` принимает `List[A]` и возвращает `A`, который берет начальное `A` из `unit` и объединяет каждое следующее `A` в списке используя `add` метод. Указание параметра `m` в качестве неявного параметра подразумевает, что `xs` параметр будет обеспечен тогда, когда при вызове параметра метода Scala сможет найти неявный `Monoid[A]` чтоб его передать в качестве параметра `m`.
+{% tab 'Scala 3' for=implicits-comparator %}
-В нашем `main` методе мы вызываем `sum` дважды и предоставляем только `xs` параметр. Теперь Scala будет искать неявное значение в указанных ранее областях видимости. Первый вызов `sum` проходит с использованием `List[Int]` в качестве `xs`, это означает, что элемент `A` имеет тип `Int`. Неявный список параметров с `m` опущен, поэтому Scala будет искать неявное значение типа `Monoid[Int]`. Первое правило поиска гласит
+```scala
+trait Comparator[A]:
+def compare(x: A, y: A): Int
-> Скала сначала будет искать неявные параметры, доступ к которым можно получить напрямую (без префикса) в месте вызова метода в котором запрошены неявные параметры.
+object Comparator:
+given Comparator[Int] with
+def compare(x: Int, y: Int): Int = Integer.compare(x, y)
-`intMonoid` - это задание неявного значения, доступ к которому можно получить непосредственно в `main`. Оно имеет подходящий тип, поэтому передается методу `sum` автоматически.
+given Comparator[String] with
+def compare(x: String, y: String): Int = x.compareTo(y)
+end Comparator
-Второй вызов `sum` проходит используя `List[String]`, что означает, что `A` - это `String`. Неявный поиск будет идти так же, как и в случае с `Int`, но на этот раз будет найден `stringMonoid`, и передан автоматически в качестве `m`.
+def max[A](x: A, y: A)(using comparator: Comparator[A]): A =
+ if comparator.compare(x, y) >= 0 then x
+ else y
-Программа выведет на экран
+println(max(10, 6)) // 10
+println(max("hello", "world")) // world
```
-6
-abc
+
+```scala
+// не компилируется:
+println(max(false, true))
+-- Error: ----------------------------------------------------------------------
+1 |println(max(false, true))
+ | ^
+ |no given instance of type Comparator[Boolean] was found for parameter comparator of method max
```
+
+Параметр `comparator` автоматически заполняется значением `given Comparator[Int]` для `max(10, 6)`
+и `given Comparator[String]` для `max("hello", "world")`.
+Поскольку нельзя найти `given Comparator[Boolean]`, вызов `max(false, true)` не компилируется.
+
+{% endtab %}
+
+{% endtabs %}
+
+Места, где Scala будет искать эти параметры, делятся на две категории:
+
+- Вначале Scala будет искать `given` параметры, доступ к которым можно получить напрямую (без префикса) в месте вызова `max`.
+- Затем он ищет членов, помеченных как given/implicit во всех объектах компаньонах,
+ связанных с типом неявного параметра (например: `object Comparator` для типа-кандидата `Comparator[Int]`).
+
+Более подробное руководство, о том где scala ищет неявные значения можно найти в [FAQ](/tutorials/FAQ/finding-implicits.html)
diff --git a/_ru/tour/inner-classes.md b/_ru/tour/inner-classes.md
index d56cdcdd32..15a1a2882d 100644
--- a/_ru/tour/inner-classes.md
+++ b/_ru/tour/inner-classes.md
@@ -1,27 +1,25 @@
---
layout: tour
title: Внутренние классы
-
-discourse: true
-
partof: scala-tour
-
num: 22
language: ru
next-page: abstract-type-members
previous-page: lower-type-bounds
-
---
-В Scala классам можно иметь в качестве членов другие классы. В отличие от Java-подобных языков, где такие внутренние классы являются членами окружающего класса, в Scala такие внутренние классы привязаны к содержащему его объекту. Предположим, мы хотим, чтобы компилятор не позволял нам на этапе компиляции смешивать узлы этого графа. Для решения этой задачи нам подойдут типы, зависящие от своего расположения.
+В Scala классам можно иметь в качестве членов другие классы. В отличие от Java-подобных языков, где такие внутренние классы являются членами окружающего класса, в Scala такие внутренние классы привязаны к содержащему его объекту. Предположим, мы хотим, чтобы компилятор не позволял нам на этапе компиляции смешивать узлы этого графа. Для решения этой задачи нам подойдут типы, зависящие от своего расположения.
Чтобы проиллюстрировать суть подхода, мы быстро набросаем реализацию такого графа:
-```tut
+{% tabs inner-classes_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=inner-classes_1 %}
+
+```scala mdoc
class Graph {
class Node {
var connectedNodes: List[Node] = Nil
- def connectTo(node: Node) {
+ def connectTo(node: Node): Unit = {
if (!connectedNodes.exists(node.equals)) {
connectedNodes = node :: connectedNodes
}
@@ -35,9 +33,34 @@ class Graph {
}
}
```
+
+{% endtab %}
+{% tab 'Scala 3' for=inner-classes_1 %}
+
+```scala
+class Graph:
+ class Node:
+ var connectedNodes: List[Node] = Nil
+ def connectTo(node: Node): Unit =
+ if !connectedNodes.exists(node.equals) then
+ connectedNodes = node :: connectedNodes
+
+ var nodes: List[Node] = Nil
+ def newNode: Node =
+ val res = Node()
+ nodes = res :: nodes
+ res
+```
+
+{% endtab %}
+{% endtabs %}
+
Данная программа представляет собой граф в составленного из списка узлов (`List[Node]`). Каждый узел имеет список других узлов, с которым он связан (`connectedNodes`). Класс `Node` является _зависимым от месторасположения типом_, поскольку он вложен в `Class Graph`. Поэтому все узлы в `connectedNodes` должны быть созданы с использованием `newNode` из одного и того же экземпляра `Graph`.
-```tut
+{% tabs inner-classes_2 %}
+{% tab 'Scala 2 и 3' for=inner-classes_2 %}
+
+```scala mdoc
val graph1: Graph = new Graph
val node1: graph1.Node = graph1.newNode
val node2: graph1.Node = graph1.newNode
@@ -45,12 +68,19 @@ val node3: graph1.Node = graph1.newNode
node1.connectTo(node2)
node3.connectTo(node1)
```
+
+{% endtab %}
+{% endtabs %}
+
Мы явно объявили тип `node1`, `node2` и `node3` как `graph1.Node` для ясности, хотя компилятор мог определить это самостоятельно. Это потому, что когда мы вызываем `graph1.newNode`, вызывающий `new Node`, метод использует экземпляр `Node`, специфичный экземпляру `graph1`.
Если у нас есть два графа, то система типов Scala не позволит смешивать узлы, определенные в рамках одного графа, с узлами другого, так как узлы другого графа имеют другой тип.
Вот некорректная программа:
-```
+{% tabs inner-classes_3 %}
+{% tab 'Scala 2 и 3' for=inner-classes_3 %}
+
+```scala mdoc:fail
val graph1: Graph = new Graph
val node1: graph1.Node = graph1.newNode
val node2: graph1.Node = graph1.newNode
@@ -59,13 +89,20 @@ val graph2: Graph = new Graph
val node3: graph2.Node = graph2.newNode
node1.connectTo(node3) // не работает!
```
+
+{% endtab %}
+{% endtabs %}
+
Тип `graph1.Node` отличается от типа `graph2.Node`. В Java последняя строка в предыдущем примере программы была бы правильной. Для узлов обоих графов Java будет присваивать один и тот же тип `Graph.Node`, т.е. `Node` имеет префикс класса `Graph`. В Скале такой тип также может быть выражен, он записывается `Graph#Node`. Если мы хотим иметь возможность соединять узлы разных графов, то вам нужно изменить описание первоначальной реализации графов следующим образом:
-```tut
+{% tabs inner-classes_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=inner-classes_4 %}
+
+```scala mdoc:nest
class Graph {
class Node {
var connectedNodes: List[Graph#Node] = Nil
- def connectTo(node: Graph#Node) {
+ def connectTo(node: Graph#Node): Unit = {
if (!connectedNodes.exists(node.equals)) {
connectedNodes = node :: connectedNodes
}
@@ -79,3 +116,24 @@ class Graph {
}
}
```
+
+{% endtab %}
+{% tab 'Scala 3' for=inner-classes_4 %}
+
+```scala
+class Graph:
+ class Node:
+ var connectedNodes: List[Graph#Node] = Nil
+ def connectTo(node: Graph#Node): Unit =
+ if !connectedNodes.exists(node.equals) then
+ connectedNodes = node :: connectedNodes
+
+ var nodes: List[Node] = Nil
+ def newNode: Node =
+ val res = Node()
+ nodes = res :: nodes
+ res
+```
+
+{% endtab %}
+{% endtabs %}
diff --git a/_ru/tour/lower-type-bounds.md b/_ru/tour/lower-type-bounds.md
index 27000cc863..3d3b22edb9 100644
--- a/_ru/tour/lower-type-bounds.md
+++ b/_ru/tour/lower-type-bounds.md
@@ -1,70 +1,115 @@
---
layout: tour
title: Нижнее Ограничение Типа
-
-discourse: true
-
partof: scala-tour
-
num: 21
language: ru
next-page: inner-classes
previous-page: upper-type-bounds
prerequisite-knowledge: upper-type-bounds, generics, variance
-
---
-В то время как [верхнее ограничение типа](upper-type-bounds.html) ограничивает тип до подтипа стороннего типа, *нижнее ограничение типа* объявляют тип супертипом стороннего типа. Термин `B >: A` выражает, то что параметр типа `B` или абстрактный тип `B` относится к супертипу типа `A`. В большинстве случаев `A` будет задавать тип класса, а `B` задавать тип метода.
+В то время как [верхнее ограничение типа](upper-type-bounds.html) ограничивает тип до подтипа стороннего типа, _нижнее ограничение типа_ объявляют тип супертипом стороннего типа. Термин `B >: A` выражает, то что параметр типа `B` или абстрактный тип `B` относится к супертипу типа `A`. В большинстве случаев `A` будет задавать тип класса, а `B` задавать тип метода.
Вот пример, где это полезно:
-```tut:fail
-trait Node[+B] {
- def prepend(elem: B): Node[B]
-}
+{% tabs upper-type-bounds_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=upper-type-bounds_1 %}
-case class ListNode[+B](h: B, t: Node[B]) extends Node[B] {
- def prepend(elem: B): ListNode[B] = ListNode(elem, this)
- def head: B = h
- def tail: Node[B] = t
+```scala mdoc:fail
+trait List[+A] {
+ def prepend(elem: A): NonEmptyList[A] = NonEmptyList(elem, this)
}
-case class Nil[+B]() extends Node[B] {
- def prepend(elem: B): ListNode[B] = ListNode(elem, this)
-}
+case class NonEmptyList[+A](head: A, tail: List[A]) extends List[A]
+
+object Nil extends List[Nothing]
```
-В данной программе реализован связанный список. `Nil` представляет пустой список. Класс `ListNode` - это узел, который содержит элемент типа `B` (`head`) и ссылку на остальную часть списка (`tail`). Класс `Node` и его подтипы ковариантны, потому что у нас указанно `+B`.
+{% endtab %}
+{% tab 'Scala 3' for=upper-type-bounds_1 %}
-Однако эта программа _не компилируется_, потому что параметр `elem` в `prepend` имеет тип `B`, который мы объявили *ко*вариантным. Так это не работает, потому что функции *контр*вариантны в типах своих параметров и *ко*вариантны в типах своих результатов.
+```scala
+trait List[+A]:
+ def prepend(elem: A): NonEmptyList[A] = NonEmptyList(elem, this)
-Чтобы исправить это, необходимо перевернуть вариантность типа параметра `elem` в `prepend`. Для этого мы вводим новый тип для параметра `U`, у которого тип `B` указан в качестве нижней границы типа.
+case class NonEmptyList[+A](head: A, tail: List[A]) extends List[A]
-```tut
-trait Node[+B] {
- def prepend[U >: B](elem: U): Node[U]
-}
+object Nil extends List[Nothing]
+```
-case class ListNode[+B](h: B, t: Node[B]) extends Node[B] {
- def prepend[U >: B](elem: U): ListNode[U] = ListNode(elem, this)
- def head: B = h
- def tail: Node[B] = t
-}
+{% endtab %}
+{% endtabs %}
+
+В данной программе реализован связанный список. `Nil` представляет пустой список. Класс `NonEmptyList` - это узел, который содержит элемент типа `A` (`head`) и ссылку на остальную часть списка (`tail`). `trait List` и его подтипы ковариантны, потому что у нас указанно `+A`.
+
+Однако эта программа _не компилируется_, потому что параметр `elem` в `prepend` имеет тип `A`, который мы объявили *ко*вариантным. Так это не работает, потому что функции *контр*вариантны в типах своих параметров и *ко*вариантны в типах своих результатов.
-case class Nil[+B]() extends Node[B] {
- def prepend[U >: B](elem: U): ListNode[U] = ListNode(elem, this)
+Чтобы исправить это, необходимо перевернуть вариантность типа параметра `elem` в `prepend`. Для этого мы вводим новый тип для параметра `B`, у которого тип `A` указан в качестве нижней границы типа.
+
+{% tabs upper-type-bounds_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=upper-type-bounds_2 %}
+
+```scala mdoc
+trait List[+A] {
+ def prepend[B >: A](elem: B): NonEmptyList[B] = NonEmptyList(elem, this)
}
+
+case class NonEmptyList[+A](head: A, tail: List[A]) extends List[A]
+
+object Nil extends List[Nothing]
```
+{% endtab %}
+{% tab 'Scala 3' for=upper-type-bounds_2 %}
+
+```scala
+trait List[+A]:
+ def prepend[B >: A](elem: B): NonEmptyList[B] = NonEmptyList(elem, this)
+
+case class NonEmptyList[+A](head: A, tail: List[A]) extends List[A]
+
+object Nil extends List[Nothing]
+```
+
+{% endtab %}
+{% endtabs %}
+
Теперь мы можем сделать следующее:
-```tut
+
+{% tabs upper-type-bounds_3 %}
+{% tab 'Scala 2 и 3' for=upper-type-bounds_3 %}
+
+```scala mdoc
trait Bird
case class AfricanSwallow() extends Bird
case class EuropeanSwallow() extends Bird
+val africanSwallows: List[AfricanSwallow] = Nil.prepend(AfricanSwallow())
+val swallowsFromAntarctica: List[Bird] = Nil
+val someBird: Bird = EuropeanSwallow()
-val africanSwallowList= ListNode[AfricanSwallow](AfricanSwallow(), Nil())
-val birdList: Node[Bird] = africanSwallowList
-birdList.prepend(EuropeanSwallow())
+// присвоить птицам (birds) африканских ласточек (swallows)
+val birds: List[Bird] = africanSwallows
+
+// добавляем новую птицу к африканским ласточкам, `B` - это `Bird`
+val someBirds = africanSwallows.prepend(someBird)
+
+// добавляем европейскую ласточку к птицам
+val moreBirds = birds.prepend(EuropeanSwallow())
+
+// соединяем вместе различных ласточек, `B` - это `Bird`, потому что это общий супертип для обоих типов ласточек
+val allBirds = africanSwallows.prepend(EuropeanSwallow())
+
+// но тут ошибка! добавление списка птиц слишком расширяет тип аргументов. -Xlint предупредит!
+val error = moreBirds.prepend(swallowsFromAntarctica) // List[Object]
```
-`Node[Bird]` может быть присвоен `africanSwallowList` , но затем может добавлять и `EuropeanSwallow`.
+
+{% endtab %}
+{% endtabs %}
+
+Параметр ковариантного типа позволяет `birds` получать значение `africanSwallows`.
+
+Тип, связанный с параметром типа `prepend`, позволяет добавлять различные разновидности ласточек и получать более абстрактный тип: вместо `List[AfricanSwallow]`, мы получаем `List[Bird]`.
+
+Используйте `-Xlint`, чтобы предупредить, если аргумент предполагаемого типа слишком абстрактен.
diff --git a/_ru/tour/mixin-class-composition.md b/_ru/tour/mixin-class-composition.md
index 4c528ca3c9..d8cbb24f30 100644
--- a/_ru/tour/mixin-class-composition.md
+++ b/_ru/tour/mixin-class-composition.md
@@ -1,21 +1,21 @@
---
layout: tour
-title: Композиция классов с примесями
-
-discourse: true
-
+title: Композиция классов с трейтами
partof: scala-tour
-
num: 7
language: ru
next-page: higher-order-functions
previous-page: tuples
prerequisite-knowledge: inheritance, traits, abstract-classes, unified-types
-
---
+
Примеси (Mixin) - это трейты, которые используются для создания класса.
-```tut
+{% tabs mixin-first-exemple class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=mixin-first-exemple %}
+
+```scala mdoc
abstract class A {
val message: String
}
@@ -31,22 +31,76 @@ val d = new D
println(d.message) // I'm an instance of class B
println(d.loudMessage) // I'M AN INSTANCE OF CLASS B
```
-У класса `D` есть суперкласс `B` и примесь `C`. Классы могут иметь только один суперкласс, но много примесей (используя ключевыое слово `extends` и `with` соответственно). Примеси и суперкласс могут иметь один и тот же супертип.
+
+У класса `D` есть суперкласс `B` и трейт `C`.
+Классы могут иметь только один суперкласс, но много трейтов (используя ключевое слово `extends` и `with` соответственно).
+Трейты и суперкласс могут иметь один и тот же супертип.
+
+{% endtab %}
+
+{% tab 'Scala 3' for=mixin-first-exemple %}
+
+```scala
+abstract class A:
+ val message: String
+class B extends A:
+ val message = "I'm an instance of class B"
+trait C extends A:
+ def loudMessage = message.toUpperCase()
+class D extends B, C
+
+val d = D()
+println(d.message) // I'm an instance of class B
+println(d.loudMessage) // I'M AN INSTANCE OF CLASS B
+```
+
+У класса `D` есть суперкласс `B` и трейт `C`.
+Классы могут иметь только один суперкласс, но много трейтов
+(используя ключевое слово `extends` и разделитель `,` соответственно).
+Трейты и суперкласс могут иметь один и тот же супертип.
+
+{% endtab %}
+
+{% endtabs %}
Теперь давайте рассмотрим более интересный пример, начиная с абстрактного класса:
-```tut
+{% tabs mixin-abstract-iterator class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=mixin-abstract-iterator %}
+
+```scala mdoc
abstract class AbsIterator {
type T
def hasNext: Boolean
def next(): T
}
```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=mixin-abstract-iterator %}
+
+```scala
+abstract class AbsIterator:
+ type T
+ def hasNext: Boolean
+ def next(): T
+```
+
+{% endtab %}
+
+{% endtabs %}
+
Класс имеет абстрактный тип `T` и методы стандартного итератора.
Далее создаем конкретную реализацию класса (все абстрактные члены `T`, `hasNext`, и `next` должны быть реализованы):
-```tut
+{% tabs mixin-concrete-string-iterator class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=mixin-concrete-string-iterator %}
+
+```scala mdoc
class StringIterator(s: String) extends AbsIterator {
type T = Char
private var i = 0
@@ -58,26 +112,87 @@ class StringIterator(s: String) extends AbsIterator {
}
}
```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=mixin-concrete-string-iterator %}
+
+```scala
+class StringIterator(s: String) extends AbsIterator:
+ type T = Char
+ private var i = 0
+ def hasNext = i < s.length
+ def next() =
+ val ch = s charAt i
+ i += 1
+ ch
+```
+
+{% endtab %}
+
+{% endtabs %}
+
`StringIterator` принимает `String` и может быть использован для обхода по строке (например, чтоб проверить содержит ли строка определенный символ).
Теперь давайте создадим трейт который тоже наследуется от `AbsIterator`.
-```tut
+{% tabs mixin-extended-abstract-iterator class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=mixin-extended-abstract-iterator %}
+
+```scala mdoc
trait RichIterator extends AbsIterator {
def foreach(f: T => Unit): Unit = while (hasNext) f(next())
}
```
-У этого трейта реализован метод `foreach` который постоянно вызывает переданную ему функцию `f: T => Unit` на каждом новом элементе (`next()`) до тех пор пока в итераторе содержатся элементы (`while (hasNext)`). Поскольку `RichIterator` это трейт, ему не нужно реализовывать членов абстрактного класса `AbsIterator`.
-Мы бы хотели объединить функциональность `StringIterator` и `RichIterator` в один класс.
+У этого трейта реализован метод `foreach`, который постоянно вызывает переданную ему функцию `f: T => Unit`
+на каждом новом элементе (`next()`) до тех пор пока в итераторе содержатся элементы (`while (hasNext)`).
+Поскольку `RichIterator` - это трейт, ему не нужно реализовывать элементы абстрактного класса `AbsIterator`.
-```tut
-object StringIteratorTest extends App {
- class RichStringIter extends StringIterator("Scala") with RichIterator
- val richStringIter = new RichStringIter
- richStringIter foreach println
-}
+{% endtab %}
+
+{% tab 'Scala 3' for=mixin-extended-abstract-iterator %}
+
+```scala
+trait RichIterator extends AbsIterator:
+ def foreach(f: T => Unit): Unit = while hasNext do f(next())
```
-Новый класс `RichStringIter` включает `StringIterator` как суперкласс и `RichIterator` как примесь.
-Используя только одиночное наследование мы бы не могли добиться того же уровня гибкости.
+У этого трейта реализован метод `foreach`, который постоянно вызывает переданную ему функцию `f: T => Unit`
+на каждом новом элементе (`next()`) до тех пор пока в итераторе содержатся элементы (`while hasNext`).
+Поскольку `RichIterator` - это трейт, ему не нужно реализовывать элементы абстрактного класса `AbsIterator`.
+
+{% endtab %}
+
+{% endtabs %}
+
+Мы бы хотели объединить функциональность `StringIterator` и `RichIterator` в один класс.
+
+{% tabs mixin-combination-class class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=mixin-combination-class %}
+
+```scala mdoc
+class RichStringIter extends StringIterator("Scala") with RichIterator
+val richStringIter = new RichStringIter
+richStringIter.foreach(println)
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=mixin-combination-class %}
+
+```scala
+class RichStringIter extends StringIterator("Scala"), RichIterator
+val richStringIter = RichStringIter()
+richStringIter.foreach(println)
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+Новый класс `RichStringIter` включает `StringIterator` как суперкласс и `RichIterator` как трейт.
+
+Используя только одиночное наследование мы бы не смогли добиться того же уровня гибкости.
diff --git a/_ru/tour/multiple-parameter-lists.md b/_ru/tour/multiple-parameter-lists.md
index 6b5e5008df..99f84700d5 100644
--- a/_ru/tour/multiple-parameter-lists.md
+++ b/_ru/tour/multiple-parameter-lists.md
@@ -1,89 +1,231 @@
---
layout: tour
title: Множественные списки параметров (Каррирование)
-
-discourse: true
-
partof: scala-tour
-
num: 10
language: ru
next-page: case-classes
previous-page: nested-functions
-
---
-Методы могут объявляться с несколькими списками параметров. При этом когда такой метод вызывается с меньшим количеством списков параметров, это приводит к созданию новой функции, которая ожидает на вход не достающий список параметров. Формально это называется [частичное применение](https://en.wikipedia.org/wiki/Partial_application).
+Методы могут объявляться с несколькими списками параметров.
-Например,
-
- ```tut
- val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
- val numberFunc = numbers.foldLeft(List[Int]()) _
-
- val squares = numberFunc((xs, x) => xs :+ x*x)
- print(squares) // List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
-
- val cubes = numberFunc((xs, x) => xs :+ x*x*x)
- print(cubes) // List(1, 8, 27, 64, 125, 216, 343, 512, 729, 1000)
- ```
-
-Рассмотрим такие примеры из класса [Traversable](/overviews/collections/trait-traversable.html) коллекции Scala:
+### Пример
+Вот пример, определенный для трейта `Iterable` из API Scala коллекций:
+
+{% tabs foldLeft_definition class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=foldLeft_definition %}
+
+```scala
+trait Iterable[A] {
+ ...
+ def foldLeft[B](z: B)(op: (B, A) => B): B
+ ...
+}
```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=foldLeft_definition %}
+
+```scala
+trait Iterable[A]:
+...
def foldLeft[B](z: B)(op: (B, A) => B): B
+...
```
-`foldLeft` применяет бинарный оператор `op` к начальному значению `z` и ко всем остальным элементам этого класса слева направо. Ниже приведен пример его использования.
+{% endtab %}
+
+{% endtabs %}
+
+`foldLeft` применяет бинарный оператор `op` к начальному значению `z` и ко всем остальным элементам коллекции слева направо.
+Ниже приведен пример его использования.
+
+Начиная с начального значения `0`, `foldLeft` применяет функцию `(m, n) => m + n` к каждому элементу списка
+и предыдущему накопленному значению.
+
+{% tabs foldLeft_use %}
-Начиная с начального значения 0, `foldLeft` применяет функцию `(m, n) => m + n` к каждому элементу списка и предыдущему накопленному значению.
+{% tab 'Scala 2 и 3' for=foldLeft_use %}
-```tut
+```scala mdoc
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val res = numbers.foldLeft(0)((m, n) => m + n)
-print(res) // 55
+println(res) // 55
```
-Множественные списки параметров имеют избыточный синтаксис, поэтому их следует использоваться экономно. Можем предложить следующие варианты для использования множественных списков (каррирования):
+{% endtab %}
+
+{% endtabs %}
+
+### Варианты для использования
+
+Предлагаемые варианты для использования множественных списков параметров включают:
+
+#### Вывод типа
-#### Отдельный функциональный параметр
- Функцию `op` можно выделить в отдельный функциональный параметр у `foldLeft`, благодаря такому выделению становится возможен более элегантный стиль передачи анонимной функции в метод. Без такого выделения код выглядел бы следующим образом:
+Исторически сложилось, что в Scala вывод типов происходит по одному списку параметров за раз.
+Скажем, у вас есть следующий метод:
+
+{% tabs foldLeft1_definition %}
+
+{% tab 'Scala 2 и 3' for=foldLeft1_definition %}
+
+```scala mdoc
+def foldLeft1[A, B](as: List[A], b0: B, op: (B, A) => B) = ???
```
-numbers.foldLeft(0, {(m: Int, n: Int) => m + n})
+
+{% endtab %}
+
+{% endtabs %}
+
+Затем при желании вызвать его следующим образом, можно обнаружить, что метод не компилируется:
+
+{% tabs foldLeft1_wrong_use %}
+
+{% tab 'Scala 2 и 3' for=foldLeft1_wrong_use %}
+
+```scala mdoc:fail
+def notPossible = foldLeft1(numbers, 0, _ + _)
```
-
- Обратите внимание, что использование отдельного функционального параметра позволяет нам использовать автоматическое выведение типа для него, что делает код еще более кратким, это было бы невозможно без каррирования.
-
+
+{% endtab %}
+
+{% endtabs %}
+
+вам нужно будет вызвать его одним из следующих способов:
+
+{% tabs foldLeft1_good_use %}
+
+{% tab 'Scala 2 и 3' for=foldLeft1_good_use %}
+
+```scala mdoc
+def firstWay = foldLeft1[Int, Int](numbers, 0, _ + _)
+def secondWay = foldLeft1(numbers, 0, (a: Int, b: Int) => a + b)
```
-numbers.foldLeft(0)(_ + _)
+
+{% endtab %}
+
+{% endtabs %}
+
+Это связано с тем, что Scala не может вывести тип функции `_ + _`, так как она все еще выводит `A` и `B`.
+Путем перемещения параметра `op` в собственный список параметров, `A` и `B` выводятся в первом списке.
+Затем эти предполагаемые типы будут доступны для второго списка параметров
+и `_ + _` станет соответствовать предполагаемому типу `(Int, Int) => Int`.
+
+{% tabs foldLeft2_definition_and_use %}
+
+{% tab 'Scala 2 и 3' for=foldLeft2_definition_and_use %}
+
+```scala mdoc
+def foldLeft2[A, B](as: List[A], b0: B)(op: (B, A) => B) = ???
+def possible = foldLeft2(numbers, 0)(_ + _)
```
- Если в утверждении `numbers.foldLeft(0)(_ + _)` зафиксировать отдельный параметр `z`, мы получим частично определенную функцию, которую можно переиспользовать, как показано ниже:
-```tut
-val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
-val numberFunc = numbers.foldLeft(List[Int]())_ // z = Empty.List[Int]
-val squares = numberFunc((xs, x) => xs:+ x*x)
-print(squares.toString()) // List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
+{% endtab %}
+
+{% endtabs %}
+
+Последнее определение метода не нуждается в подсказках типа и может вывести все типы своих параметров.
+
+#### Неявные параметры
+
+Чтоб указать что параметр используется [_неявно_ (_implicit_)](/ru/tour/implicit-parameters.html)
+необходимо задавать несколько списков параметров.
+Примером может служить следующее:
+
+{% tabs execute_definition class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=execute_definition %}
-val cubes = numberFunc((xs, x) => xs:+ x*x*x)
-print(cubes.toString()) // List(1, 8, 27, 64, 125, 216, 343, 512, 729, 1000)
+```scala mdoc
+def execute(arg: Int)(implicit ec: scala.concurrent.ExecutionContext) = ???
```
- `foldLeft` и `foldRight` может быть использован в любой из следующих вариаций,
-```tut
-val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+{% endtab %}
-numbers.foldLeft(0)((sum, item) => sum + item) // Общая Форма
-numbers.foldRight(0)((sum, item) => sum + item) // Общая Форма
+{% tab 'Scala 3' for=execute_definition %}
-numbers.foldLeft(0)(_+_) // Форма с каррированием
-numbers.foldRight(0)(_+_) // Форма с каррированием
+```scala
+def execute(arg: Int)(using ec: scala.concurrent.ExecutionContext) = ???
```
-
-#### Неявные параметры
- Чтоб указать что параметр используется неявно (`implicit`) необходимо задавать несколько списков параметров. Примером может служить следующее:
+{% endtab %}
+
+{% endtabs %}
+
+#### Частичное применение
+
+Методы могут объявляться с несколькими списками параметров.
+При этом когда такой метод вызывается с меньшим количеством списков параметров,
+это приводит к созданию новой функции,
+которая ожидает на вход недостающий список параметров.
+Формально это называется [частичное применение](https://ru.wikipedia.org/wiki/%D0%A7%D0%B0%D1%81%D1%82%D0%B8%D1%87%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5).
+
+Например,
+
+{% tabs foldLeft_partial %}
+
+{% tab 'Scala 2 и 3' for=foldLeft_partial %}
+```scala mdoc:nest
+val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+val numberFunc = numbers.foldLeft(List[Int]()) _
+
+val squares = numberFunc((xs, x) => xs :+ x*x)
+println(squares) // List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
+
+val cubes = numberFunc((xs, x) => xs :+ x*x*x)
+println(cubes) // List(1, 8, 27, 64, 125, 216, 343, 512, 729, 1000)
```
-def execute(arg: Int)(implicit ec: ExecutionContext) = ???
+
+{% endtab %}
+
+{% endtabs %}
+
+### Сравнение с «каррированием»
+
+Иногда можно встретить, что метод с несколькими списками параметров называется «каррированный».
+
+Как говорится [в статье на Википедии о каррировании](https://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D1%80%D1%80%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5),
+
+> Каррирование — преобразование функции от многих аргументов в набор вложенных функций,
+> каждая из которых является функцией от одного аргумента.
+
+Мы не рекомендуем использовать слово «каррирование» в отношении множественных списков параметров Scala по двум причинам:
+
+1. В Scala множественные параметры и множественные списки параметров задаются
+ и реализуются непосредственно как часть языка, а не преобразуются из функций с одним параметром.
+
+2. Существует опасность путаницы с методами из стандартной Scala библиотеки
+ [`curried`]()
+ и [`uncurried`](),
+ которые вообще не включают множественные списки параметров.
+
+Тем не менее, несомненно, есть сходство между множественными списками параметров и каррированием.
+Хотя они различаются в месте определения,
+в месте вызова могут тем не менее выглядеть одинаково, как в этом примере:
+
+{% tabs about_currying %}
+
+{% tab 'Scala 2 и 3' for=about_currying %}
+
+```scala mdoc
+// версия с множественными списками параметров
+def addMultiple(n1: Int)(n2: Int) = n1 + n2
+// два различных способа получить каррированную версию
+def add(n1: Int, n2: Int) = n1 + n2
+val addCurried1 = (add _).curried
+val addCurried2 = (n1: Int) => (n2: Int) => n1 + n2
+// независимо от определения, вызов всех трех идентичен
+addMultiple(3)(4) // 7
+addCurried1(3)(4) // 7
+addCurried2(3)(4) // 7
```
+
+{% endtab %}
+
+{% endtabs %}
diff --git a/_ru/tour/named-arguments.md b/_ru/tour/named-arguments.md
index defb9d4282..da9202a051 100644
--- a/_ru/tour/named-arguments.md
+++ b/_ru/tour/named-arguments.md
@@ -1,34 +1,61 @@
---
layout: tour
title: Именованные Аргументы
-
-discourse: true
-
partof: scala-tour
-
num: 34
language: ru
next-page: packages-and-imports
previous-page: default-parameter-values
prerequisite-knowledge: function-syntax
-
---
При вызове методов можно конкретно указывать название задаваемого аргумента следующим образом:
-```tut
-def printName(first: String, last: String): Unit = {
- println(first + " " + last)
-}
+{% tabs named-arguments-when-good %}
-printName("John", "Smith") // Prints "John Smith"
-printName(first = "John", last = "Smith") // Prints "John Smith"
-printName(last = "Smith", first = "John") // Prints "John Smith"
+{% tab 'Scala 2 и 3' for=named-arguments-when-good %}
+
+```scala mdoc
+def printName(first: String, last: String): Unit =
+ println(s"$first $last")
+
+printName("John", "Public") // выводит "John Public"
+printName(first = "John", last = "Public") // выводит "John Public"
+printName(last = "Public", first = "John") // выводит "John Public"
+printName("Elton", last = "John") // выводит "Elton John"
```
-Обратите внимание, что при указании имени параметра, порядок аргумента может быть изменен. Однако если какие-то аргументы именованного, а другие нет, то аргументы без имени должны стоять на первом месте и располагаться в том порядке, в котором описаны параметры метода.
-```tut:fail
-printName(last = "Smith", "john") // ошибка: позиция после именованного аргумента
+{% endtab %}
+
+{% endtabs %}
+
+Это полезно, когда два параметра имеют один и тот же тип и аргументы могут быть случайно перепутаны.
+
+Обратите внимание, что именованные аргументы могут быть указаны в любом порядке.
+Однако, если аргументы расположены не в порядке параметров метода (читается слева направо),
+остальные аргументы должны быть названы.
+
+В следующем примере именованные аргументы позволяют опустить параметр `middle`.
+В случае ошибки, если первый аргумент не на своем месте, необходимо будет указать второй аргумент.
+
+{% tabs named-arguments-when-error %}
+
+{% tab 'Scala 2 и 3' for=named-arguments-when-error %}
+
+```scala mdoc:fail
+def printFullName(first: String, middle: String = "Q.", last: String): Unit =
+ println(s"$first $middle $last")
+
+printFullName(first = "John", last = "Public") // выводит "John Q. Public"
+printFullName("John", last = "Public") // выводит "John Q. Public"
+printFullName("John", middle = "Quincy", "Public") // выводит "John Quincy Public"
+printFullName(last = "Public", first = "John") // выводит "John Q. Public"
+printFullName(last = "Public", "John") // ошибка: позиция после именованного аргумента
```
-Обратите внимание, что именованные аргументы не работают при вызове Java методов.
+{% endtab %}
+
+{% endtabs %}
+
+Именованные аргументы работают при вызове Java методов, но только в том случае,
+если используемая Java библиотека была скомпилирована с флагом `-parameters`.
diff --git a/_ru/tour/nested-functions.md b/_ru/tour/nested-functions.md
index ef082c36e4..8bc05a9d70 100644
--- a/_ru/tour/nested-functions.md
+++ b/_ru/tour/nested-functions.md
@@ -1,34 +1,55 @@
---
layout: tour
title: Вложенные Методы
-
-discourse: true
-
partof: scala-tour
-
num: 9
language: ru
next-page: multiple-parameter-lists
previous-page: higher-order-functions
-
---
В Scala возможно объявление метода вкладывать в тело другого метода. Это реализовано в следующем примере, в котором метод `factorial` используется для вычисления факториала заданного числа:
-{% scalafiddle %}
-```tut
- def factorial(x: Int): Int = {
- def fact(x: Int, accumulator: Int): Int = {
- if (x <= 1) accumulator
- else fact(x - 1, x * accumulator)
- }
- fact(x, 1)
- }
-
- println("Factorial of 2: " + factorial(2))
- println("Factorial of 3: " + factorial(3))
+{% tabs Nested_functions_definition class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=Nested_functions_definition %}
+
+```scala mdoc
+def factorial(x: Int): Int = {
+ def fact(x: Int, accumulator: Int): Int = {
+ if (x <= 1) accumulator
+ else fact(x - 1, x * accumulator)
+ }
+ fact(x, 1)
+}
+
+println("Factorial of 2: " + factorial(2))
+println("Factorial of 3: " + factorial(3))
```
-{% endscalafiddle %}
+
+{% endtab %}
+
+{% tab 'Scala 3' for=Nested_functions_definition %}
+
+```scala
+def factorial(x: Int): Int =
+ def fact(x: Int, accumulator: Int): Int =
+ if x <= 1 then accumulator
+ else fact(x - 1, x * accumulator)
+ fact(x, 1)
+
+println("Factorial of 2: " + factorial(2))
+println("Factorial of 3: " + factorial(3))
+
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+{% tabs Nested_functions_result %}
+
+{% tab 'Scala 2 и 3' for=Nested_functions_result %}
Результат выполнения программы:
@@ -36,3 +57,7 @@ previous-page: higher-order-functions
Factorial of 2: 2
Factorial of 3: 6
```
+
+{% endtab %}
+
+{% endtabs %}
diff --git a/_ru/tour/operators.md b/_ru/tour/operators.md
index 33b4cbfd20..c8ec47bb3e 100644
--- a/_ru/tour/operators.md
+++ b/_ru/tour/operators.md
@@ -1,31 +1,46 @@
---
layout: tour
title: Операторы
-
-discourse: true
-
partof: scala-tour
-
num: 30
language: ru
next-page: by-name-parameters
previous-page: type-inference
prerequisite-knowledge: case-classes
-
---
+
В Скале операторы - это обычные методы. В качестве _инфиксного оператора_ может быть использован любой метод с одним параметром. Например, `+` может вызываться с использованием точки:
+
+{% tabs operators_1 %}
+{% tab 'Scala 2 и 3' for=operators_1 %}
+
```
10.+(1)
```
+{% endtab %}
+{% endtabs %}
+
Однако легче воспринимать код, когда такие методы записаны как инфиксный оператор:
+
+{% tabs operators_2 %}
+{% tab 'Scala 2 и 3' for=operators_2 %}
+
```
10 + 1
```
+{% endtab %}
+{% endtabs %}
+
## Создание и использование операторов
+
В качестве оператора можно использовать любой допустимый символ. Включая имена на подобии `add` или символ (символы) типа `+`.
-```tut
+
+{% tabs operators_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=operators_3 %}
+
+```scala mdoc
case class Vec(x: Double, y: Double) {
def +(that: Vec) = Vec(this.x + that.x, this.y + that.y)
}
@@ -37,9 +52,31 @@ val vector3 = vector1 + vector2
vector3.x // 3.0
vector3.y // 3.0
```
+
+{% endtab %}
+{% tab 'Scala 3' for=operators_3 %}
+
+```scala
+case class Vec(x: Double, y: Double):
+ def +(that: Vec) = Vec(this.x + that.x, this.y + that.y)
+
+val vector1 = Vec(1.0, 1.0)
+val vector2 = Vec(2.0, 2.0)
+
+val vector3 = vector1 + vector2
+vector3.x // 3.0
+vector3.y // 3.0
+```
+
+{% endtab %}
+{% endtabs %}
+
У класса Vec есть метод `+`, который мы использовали для добавления `vector1` и `vector2`. Используя круглые скобки, можно строить сложные выражения с читаемым синтаксисом. Пример создания класса `MyBool`, которое включает в себя методы `and` и `or`
-```tut
+{% tabs operators_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=operators_4 %}
+
+```scala mdoc
case class MyBool(x: Boolean) {
def and(that: MyBool): MyBool = if (x) that else this
def or(that: MyBool): MyBool = if (x) this else that
@@ -47,17 +84,38 @@ case class MyBool(x: Boolean) {
}
```
+{% endtab %}
+{% tab 'Scala 3' for=operators_4 %}
+
+```scala
+case class MyBool(x: Boolean):
+ def and(that: MyBool): MyBool = if x then that else this
+ def or(that: MyBool): MyBool = if x then this else that
+ def negate: MyBool = MyBool(!x)
+```
+
+{% endtab %}
+{% endtabs %}
+
Теперь можно использовать операторы `and` и `or` в качестве инфиксных операторов:
-```tut
+{% tabs operators_5 %}
+{% tab 'Scala 2 и 3' for=operators_5 %}
+
+```scala mdoc
def not(x: MyBool) = x.negate
def xor(x: MyBool, y: MyBool) = (x or y) and not(x and y)
```
+{% endtab %}
+{% endtabs %}
+
Это помогает сделать объявление `xor` более читабельным.
## Порядок очередности
+
Когда выражение использует несколько операторов, операторы оцениваются на основе приоритета первого символа. Таблица приоритетов символов:
+
```
(символы которых нет снизу)
* / %
@@ -68,14 +126,31 @@ def xor(x: MyBool, y: MyBool) = (x or y) and not(x and y)
&
^
|
-(буквы)
+(буквы, $, _)
```
+
Такой приоритет распространяется на любые функции, которые вы задаете. Например, следующее выражение:
+
+{% tabs operators_7 %}
+{% tab 'Scala 2 и 3' for=operators_7 %}
+
```
a + b ^? c ?^ d less a ==> b | c
```
+
+{% endtab %}
+{% endtabs %}
+
эквивалентно
+
+{% tabs operators_8 %}
+{% tab 'Scala 2 и 3' for=operators_8 %}
+
```
((a + b) ^? (c ?^ d)) less ((a ==> b) | c)
```
+
+{% endtab %}
+{% endtabs %}
+
`?^` имеет высший приоритет, потому что начинается с символа `?`. Второй по старшинству приоритет имеет `+`, за которым следуют `==>`, `^?`, `|`, и `less`.
diff --git a/_ru/tour/package-objects.md b/_ru/tour/package-objects.md
index 1a0ba1b7f2..89c392ea46 100644
--- a/_ru/tour/package-objects.md
+++ b/_ru/tour/package-objects.md
@@ -1,28 +1,53 @@
---
layout: tour
title: Объекты Пакета
-
-discourse: true
-
partof: scala-tour
-
num: 36
language: ru
previous-page: packages-and-imports
---
-# Объекты Пакета
+Часто бывает удобно иметь определения, доступные для всего пакета,
+когда не нужно придумывать имя для оболочки `object`, которая их содержит.
-У каждого пакета может существовать связанный с этим пакетом объект (package object), общий для всех членов пакета. Такой объект может быть только один. Любые выражения, содержащиеся в объекте пакета, считаются членами самого пакета.
+{% tabs pkg-obj-vs-top-lvl_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=pkg-obj-vs-top-lvl_1 %}
-Объекты пакета могут содержать произвольные виды выражений, а не только переменные и методы. Например, они часто используются для хранения псевдонимов типа и наборов неявных преобразований доступных всему пакету. Объекты пакета могут также наследоваться от классов и трейтов Scala.
+Scala 2 предоставляет _объекты пакета_ (_package objects_) в виде удобного контейнера, общего для всего пакета.
+
+Объекты пакета могут содержать произвольные виды выражений, а не только переменные и методы.
+Например, они часто используются для хранения псевдонимов типа и наборов неявных преобразований доступных всему пакету.
+Объекты пакета могут также наследоваться от классов и трейтов Scala.
+
+> В будущей версии Scala 3 объекты пакета будут удалены в пользу определений верхнего уровня.
По соглашению, исходный код объекта пакета обычно помещается в файл под названием `package.scala`.
+Каждому пакету разрешено иметь один объект пакета.
+Любые выражения, содержащиеся в объекте пакета, считаются членами самого пакета.
+
+{% endtab %}
+{% tab 'Scala 3' for=pkg-obj-vs-top-lvl_1 %}
+
+В Scala 3 любое определение может быть объявлено на верхнем уровне пакета.
+Например, классы, перечисления, методы и переменные.
+
+Любые определения, размещенные на верхнем уровне пакета, считаются членами самого пакета.
+
+> В Scala 2 верхнеуровневый метод, определения типов и переменных должны были быть заключены в **объект пакета**.
+> Их все еще можно использовать в Scala 3 для обратной совместимости.
+> Вы можете увидеть, как они работают, переключая вкладки.
+
+{% endtab %}
+{% endtabs %}
+
См. пример ниже. Предположим, есть старший класс `Fruit` и три наследуемых от него объекта `Fruit` в пакете.
`gardening.fruits`:
+{% tabs pkg-obj-vs-top-lvl_2 %}
+{% tab 'Scala 2 и 3' for=pkg-obj-vs-top-lvl_2 %}
+
```
// в файле gardening/fruits/Fruit.scala
package gardening.fruits
@@ -33,9 +58,15 @@ object Plum extends Fruit("Plum", "blue")
object Banana extends Fruit("Banana", "yellow")
```
+{% endtab %}
+{% endtabs %}
+
Теперь предположим, что мы хотим поместить переменную `planted` и метод `showFruit` непосредственно в пакет `gardening`.
Вот как это делается:
+{% tabs pkg-obj-vs-top-lvl_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=pkg-obj-vs-top-lvl_3 %}
+
```
// в файле gardening/fruits/package.scala
package gardening
@@ -47,11 +78,31 @@ package object fruits {
}
```
-Для примера, следующий объект `PrintPlanted` импортирует `planted` и `showFruit` точно так же, как с вариантом импорта класса `Fruit`, используя групповой стиль импорта пакета gardening.fruits:
+{% endtab %}
+{% tab 'Scala 3' for=pkg-obj-vs-top-lvl_3 %}
+
+```
+// в файле gardening/fruits/package.scala
+package gardening.fruits
+
+val planted = List(Apple, Plum, Banana)
+def showFruit(fruit: Fruit): Unit =
+ println(s"${fruit.name}s are ${fruit.color}")
+```
+
+{% endtab %}
+{% endtabs %}
+
+Для примера, следующий объект `PrintPlanted` импортирует `planted` и `showFruit` точно так же, как с вариантом импорта класса `Fruit`,
+используя групповой стиль импорта пакета `gardening.fruits`:
+
+{% tabs pkg-obj-vs-top-lvl_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=pkg-obj-vs-top-lvl_4 %}
```
// в файле PrintPlanted.scala
import gardening.fruits._
+
object PrintPlanted {
def main(args: Array[String]): Unit = {
for (fruit <- planted) {
@@ -61,10 +112,58 @@ object PrintPlanted {
}
```
-Объекты пакета ведут себя также, как и любые другие объекты. Это означает, что вы можете использовать наследование, при этом сразу нескольких трейтов:
+{% endtab %}
+{% tab 'Scala 3' for=pkg-obj-vs-top-lvl_4 %}
```
-package object fruits extends FruitAliases with FruitHelpers {
- // здесь располагаются вспомогательные классы и переменные
-}
+// в файле PrintPlanted.scala
+import gardening.fruits.*
+
+@main def printPlanted(): Unit =
+ for fruit <- planted do
+ showFruit(fruit)
+```
+
+{% endtab %}
+{% endtabs %}
+
+### Объединение нескольких определений на уровне пакета
+
+Часто в вашем проекте может быть несколько повторно используемых определений,
+заданных в различных модулях, которые вы хотите агрегировать на верхнем уровне пакета.
+
+Например, некоторые вспомогательные методы в трейте `FruitHelpers`
+и некоторые псевдонимы терминов/типов в свойстве `FruitAliases`.
+Вот как вы можете разместить все их определения на уровне пакета `fruit`:
+
+{% tabs pkg-obj-vs-top-lvl_5 class=tabs-scala-version %}
+{% tab 'Scala 2' for=pkg-obj-vs-top-lvl_5 %}
+
+Объекты пакета ведут себя также, как и любые другие объекты.
+Это означает, что вы можете использовать наследование, при этом сразу нескольких трейтов:
+
```
+package gardening
+
+// `fruits` наследует свои элементы от родителей.
+package object fruits extends FruitAliases with FruitHelpers
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=pkg-obj-vs-top-lvl_5 %}
+
+В Scala 3 предпочтительно использовать `export` для объединения членов из нескольких объектов в единую область видимости.
+Здесь мы определяем приватные объекты, которые смешиваются с вспомогательными трейтами,
+а затем экспортируют их элементы на верхнем уровне:
+
+```
+package gardening.fruits
+
+private object FruitAliases extends FruitAliases
+private object FruitHelpers extends FruitHelpers
+
+export FruitHelpers.*, FruitAliases.*
+```
+
+{% endtab %}
+{% endtabs %}
diff --git a/_ru/tour/packages-and-imports.md b/_ru/tour/packages-and-imports.md
index ef7865e3e7..4624fa7238 100644
--- a/_ru/tour/packages-and-imports.md
+++ b/_ru/tour/packages-and-imports.md
@@ -1,29 +1,35 @@
---
layout: tour
title: Пакеты и Импорт
-
-discourse: true
-
partof: scala-tour
-
num: 35
language: ru
-previous-page: named-arguments
+previous-page: annotations
next-page: package-objects
---
-# Пакеты и Импорт
+# Пакеты и Импорт
+
Scala использует пакеты для указания пространства имен, они позволяют создавать модульную структуру кода.
## Создание пакета
+
Пакеты создаются путем объявления одного или нескольких имен пакетов в верхней части файла Scala.
+{% tabs packages-and-imports_1 %}
+{% tab 'Scala 2 и 3' for=packages-and-imports_1 %}
+
```
package users
class User
```
+
+{% endtab %}
+{% endtabs %}
+
По соглашению пакеты называют тем же именем, что и каталог, содержащий файл Scala. Однако Scala не обращает внимания на расположение файлов. Структура каталогов sbt-проекта для `package users` может выглядеть следующим образом:
+
```
- ExampleProject
- build.sbt
@@ -37,8 +43,15 @@ class User
UserPreferences.scala
- test
```
-Обратите внимание, что каталог `users` находится внутри каталога `scala` и как в пакете содержатся несколько файлов Scala. Каждый файл Scala в пакете может иметь одно и то же объявление пакета. Другой способ объявления пакетов - с помощью фигурных скобок:
-```
+
+Обратите внимание, что каталог `users` находится внутри каталога `scala` и как в пакете содержатся несколько файлов Scala.
+Каждый файл Scala в пакете может иметь одно и то же объявление пакета.
+Другой способ объявления пакетов - вложить их друг в друга::
+
+{% tabs packages-and-imports_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=packages-and-imports_2 %}
+
+```scala
package users {
package administrators {
class NormalUser
@@ -48,18 +61,47 @@ package users {
}
}
```
+
+{% endtab %}
+{% tab 'Scala 3' for=packages-and-imports_2 %}
+
+```scala
+package users:
+ package administrators:
+ class NormalUser
+
+ package normalusers:
+ class NormalUser
+```
+
+{% endtab %}
+{% endtabs %}
+
Как видите, такой способ позволяет вкладывать пакеты друг в друга, а также обеспечивает отличный контроль за областью видимости и возможностью изоляции.
Имя пакета должно быть все в нижнем регистре, и если код разрабатывается в организации имеющей сайт, то следует использовать имя следующего формата: `<домен-верхнего-уровня>.<доменное-имя>.<название-проекта>`. Например, если бы у Google был проект под названием `SelfDrivingCar`, название пакета выглядело бы следующим образом:
-```
+
+{% tabs packages-and-imports_3 %}
+{% tab 'Scala 2 и 3' for=packages-and-imports_3 %}
+
+```scala
package com.google.selfdrivingcar.camera
class Lens
```
+
+{% endtab %}
+{% endtabs %}
+
Что может соответствовать следующей структуре каталога: `SelfDrivingCar/src/main/scala/com/google/selfdrivingcar/camera/Lens.scala`.
## Импорт
+
Указание `import` открывает доступ к членам (классам, трейтам, функциям и т.д.) в других пакетах. Указание `import` не требуется для доступа к членам одного и того же пакета. Указание `import` избирательны:
+
+{% tabs packages-and-imports_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=packages-and-imports_4 %}
+
```
import users._ // групповой импорт всего пакета users
import users.User // импортировать только User
@@ -67,20 +109,65 @@ import users.{User, UserPreferences} // импортировать только
import users.{UserPreferences => UPrefs} // импортировать и переименовать
```
+{% endtab %}
+{% tab 'Scala 3' for=packages-and-imports_4 %}
+
+```
+import users.* // групповой импорт всего пакета users, кроме given
+import users.given // импорт всех given пакета users
+import users.User // импортировать только User
+import users.{User, UserPreferences} // импортировать только User, UserPreferences
+import users.UserPreferences as UPrefs // импортировать и переименовать
+```
+
+{% endtab %}
+{% endtabs %}
+
Одним из отличий Scala от Java является то, что импорт можно использовать где угодно:
-```tut
+{% tabs packages-and-imports_5 class=tabs-scala-version %}
+{% tab 'Scala 2' for=packages-and-imports_5 %}
+
+```scala mdoc
def sqrtplus1(x: Int) = {
import scala.math.sqrt
sqrt(x) + 1.0
}
```
-В случае возникновения конфликта имен и необходимости импортировать что-либо из корня проекта, имя пакета должно начинаться с префикса `_root_`:
+
+{% endtab %}
+{% tab 'Scala 3' for=packages-and-imports_5 %}
+
+```scala
+def sqrtplus1(x: Int) =
+ import scala.math.sqrt
+ sqrt(x) + 1.0
```
+
+{% endtab %}
+{% endtabs %}
+
+В случае возникновения конфликта имен и необходимости импортировать что-либо из корня проекта, имя пакета должно начинаться с префикса `_root_`:
+
+{% tabs packages-and-imports_6 class=tabs-scala-version %}
+{% tab 'Scala 2' for=packages-and-imports_6 %}
+
+```scala
package accounts
import _root_.users._
```
+{% endtab %}
+{% tab 'Scala 3' for=packages-and-imports_6 %}
+
+```scala
+package accounts
+
+import _root_.users.*
+```
+
+{% endtab %}
+{% endtabs %}
Примечание: Пакеты `scala` и `java.lang`, а также `object Predef` импортируются по умолчанию.
diff --git a/_ru/tour/pattern-matching.md b/_ru/tour/pattern-matching.md
index a3d4dda5a4..b46810564b 100644
--- a/_ru/tour/pattern-matching.md
+++ b/_ru/tour/pattern-matching.md
@@ -1,24 +1,24 @@
---
layout: tour
title: Сопоставление с примером
-
-discourse: true
-
partof: scala-tour
-
num: 12
language: ru
next-page: singleton-objects
previous-page: case-classes
prerequisite-knowledge: case-classes, string-interpolation, subtyping
-
---
Сопоставление с примером (Pattern matching) - это механизм сравнения значений с определенным примером. При успешном совпадении значение может быть разложено на составные части. Мы рассматриваем сопоставление с примером, как более мощную версию `switch` оператора из Java. Eго также можно использовать вместо серии if/else выражений.
## Синтаксис
+
Синтаксис сопоставления с примером состоит из значения, ключевого слова `match` (сопоставить) и по крайней мере, одного пункта с примером `case`, с которым мы хотим сопоставить наше значение.
-```tut
+
+{% tabs pattern-matching-1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=pattern-matching-1 %}
+
+```scala mdoc
import scala.util.Random
val x: Int = Random.nextInt(10)
@@ -27,50 +27,99 @@ x match {
case 0 => "zero"
case 1 => "one"
case 2 => "two"
- case _ => "many"
+ case _ => "other"
}
```
-Значение константы `x` выше представляет собой случайное целое число от 0 до 10. `x` становится левым операндом оператора `match`, а справа - выражением с четырьмя примерами (называемые еще _вариантами_). Последний вариант `_` - позволяет "поймать все оставшиеся варианты" т. е. для любого числа больше 2.
+
+{% endtab %}
+{% tab 'Scala 3' for=pattern-matching-1 %}
+
+```scala
+import scala.util.Random
+
+val x: Int = Random.nextInt(10)
+
+x match
+ case 0 => "zero"
+ case 1 => "one"
+ case 2 => "two"
+ case _ => "other"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Значение константы `x` выше представляет собой случайное целое число от 0 до 9. `x` становится левым операндом оператора `match`, а справа - выражением с четырьмя примерами (называемые еще _вариантами_). Последний вариант `_` - позволяет "поймать все оставшиеся варианты" т. е. для любого числа больше 2.
Сопоставление с примером возвращает значение.
-```tut
+
+{% tabs pattern-matching-2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=pattern-matching-2 %}
+
+```scala mdoc
def matchTest(x: Int): String = x match {
case 1 => "one"
case 2 => "two"
- case _ => "many"
+ case _ => "other"
}
-matchTest(3) // many
-matchTest(1) // one
+matchTest(3) // выводит "other"
+matchTest(1) // выводит "one"
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=pattern-matching-2 %}
+
+```scala
+def matchTest(x: Int): String = x match
+ case 1 => "one"
+ case 2 => "two"
+ case _ => "other"
+
+matchTest(3) // выводит "other"
+matchTest(1) // выводит "one"
```
+
+{% endtab %}
+{% endtabs %}
+
Это сопоставляющее выражение имеет тип String, так как все варианты сопоставления возвращают String. Поэтому функция `matchTest` возвращает String.
## Сопоставление с классами образцами
-Классы образцы особенно полезны для сопоставления.
+Классы образцы особенно полезны для сопоставления.
-```tut
-abstract class Notification
+{% tabs notification %}
+{% tab 'Scala 2 и 3' for=notification %}
+
+```scala mdoc
+sealed trait Notification
case class Email(sender: String, title: String, body: String) extends Notification
case class SMS(caller: String, message: String) extends Notification
case class VoiceRecording(contactName: String, link: String) extends Notification
+```
+{% endtab %}
+{% endtabs %}
-```
-`Notification` - абстрактный суперкласс, от которого наследуются три конкретных типа реализаций классов образцов `Email`, `SMS`, и `VoiceRecording`. Теперь мы можем делать сопоставление с примером используя в качестве примера один из этих классов образцов.
+`Notification` - запечатанный трейт, от которого наследуются три конкретных типа реализаций классов образцов `Email`, `SMS`, и `VoiceRecording`. Теперь мы можем делать сопоставление с примером используя в качестве примера один из этих классов образцов.
При сопоставлении с классом образцом мы можем сразу извлекать параметры из которых состоит класс (благодаря автоматическому использованию [объекта экстрактора](extractor-objects.html)):
-```
+{% tabs pattern-matching-4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=pattern-matching-4 %}
+
+```scala
def showNotification(notification: Notification): String = {
notification match {
- case Email(email, title, _) =>
- s"You got an email from $email with title: $title"
+ case Email(sender, title, _) =>
+ s"You got an email from $sender with title: $title"
case SMS(number, message) =>
s"You got an SMS from $number! Message: $message"
case VoiceRecording(name, link) =>
- s"you received a Voice Recording from $name! Click the link to hear it: $link"
+ s"You received a Voice Recording from $name! Click the link to hear it: $link"
}
}
val someSms = SMS("12345", "Are you there?")
@@ -78,17 +127,46 @@ val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
println(showNotification(someSms)) // выводит "You got an SMS from 12345! Message: Are you there?"
-println(showNotification(someVoiceRecording)) // выводит "you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123"
+println(showNotification(someVoiceRecording)) // выводит "You received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123"
```
+
+{% endtab %}
+{% tab 'Scala 3' for=pattern-matching-4 %}
+
+```scala
+def showNotification(notification: Notification): String =
+ notification match
+ case Email(sender, title, _) =>
+ s"You got an email from $sender with title: $title"
+ case SMS(number, message) =>
+ s"You got an SMS from $number! Message: $message"
+ case VoiceRecording(name, link) =>
+ s"You received a Voice Recording from $name! Click the link to hear it: $link"
+
+val someSms = SMS("12345", "Are you there?")
+val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
+
+println(showNotification(someSms)) // выводит "You got an SMS from 12345! Message: Are you there?"
+
+println(showNotification(someVoiceRecording)) // выводит "You received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123"
+```
+
+{% endtab %}
+{% endtabs %}
+
Функция `showNotification` принимает в качестве параметра абстрактный тип `Notification` который проверяет по образцам (т.е. выясняет, является ли он классом `Email`, `SMS` или `VoiceRecording`). В `case Email(email, title, _)`поля `email` и `title` используются в возвращаемом значении, а вот поле `body` игнорируется благодаря символу `_`.
## Ограждения примеров
+
Ограждения примеров - это просто логические выражения, которые используются для того, чтобы сделать выбор более специфичным (убрать лишние варианты). Просто добавьте `if <логическое выражение>` после примера.
-```
+{% tabs pattern-matching-5 class=tabs-scala-version %}
+{% tab 'Scala 2' for=pattern-matching-5 %}
+
+```scala
def showImportantNotification(notification: Notification, importantPeopleInfo: Seq[String]): String = {
notification match {
- case Email(email, _, _) if importantPeopleInfo.contains(email) =>
+ case Email(sender, _, _) if importantPeopleInfo.contains(sender) =>
"You got an email from special someone!"
case SMS(number, _) if importantPeopleInfo.contains(number) =>
"You got an SMS from special someone!"
@@ -99,23 +177,59 @@ def showImportantNotification(notification: Notification, importantPeopleInfo: S
val importantPeopleInfo = Seq("867-5309", "jenny@gmail.com")
-val someSms = SMS("867-5309", "Are you there?")
+val someSms = SMS("123-4567", "Are you there?")
+val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
+val importantEmail = Email("jenny@gmail.com", "Drinks tonight?", "I'm free after 5!")
+val importantSms = SMS("867-5309", "I'm here! Where are you?")
+
+println(showImportantNotification(someSms, importantPeopleInfo)) // выводит "You got an SMS from 123-4567! Message: Are you there?"
+println(showImportantNotification(someVoiceRecording, importantPeopleInfo)) // выводит "You received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123"
+println(showImportantNotification(importantEmail, importantPeopleInfo)) // выводит "You got an email from special someone!"
+
+println(showImportantNotification(importantSms, importantPeopleInfo)) // выводит "You got an SMS from special someone!"
+```
+
+{% endtab %}
+{% tab 'Scala 3' for=pattern-matching-5 %}
+
+```scala
+def showImportantNotification(notification: Notification, importantPeopleInfo: Seq[String]): String =
+ notification match
+ case Email(sender, _, _) if importantPeopleInfo.contains(sender) =>
+ "You got an email from special someone!"
+ case SMS(number, _) if importantPeopleInfo.contains(number) =>
+ "You got an SMS from special someone!"
+ case other =>
+ showNotification(other) // в этом варианте считается подходящими параметры любого типа. Значит этот вариант выполняется во всех случаях и передает исходный параметр в функцию showNotification
+
+val importantPeopleInfo = Seq("867-5309", "jenny@gmail.com")
+
+val someSms = SMS("123-4567", "Are you there?")
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
val importantEmail = Email("jenny@gmail.com", "Drinks tonight?", "I'm free after 5!")
val importantSms = SMS("867-5309", "I'm here! Where are you?")
-println(showImportantNotification(someSms, importantPeopleInfo))
-println(showImportantNotification(someVoiceRecording, importantPeopleInfo))
-println(showImportantNotification(importantEmail, importantPeopleInfo))
-println(showImportantNotification(importantSms, importantPeopleInfo))
+println(showImportantNotification(someSms, importantPeopleInfo)) // выводит "You got an SMS from 123-4567! Message: Are you there?"
+println(showImportantNotification(someVoiceRecording, importantPeopleInfo)) // выводит "You received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123"
+println(showImportantNotification(importantEmail, importantPeopleInfo)) // выводит "You got an email from special someone!"
+
+println(showImportantNotification(importantSms, importantPeopleInfo)) // выводит "You got an SMS from special someone!"
```
+{% endtab %}
+{% endtabs %}
+
В варианте `case Email(email, _, _) if importantPeopleInfo.contains(email)`, пример сравнивается только если `email` находится в списке `importantPeopleInfo`.
## Сопоставление только с типом
+
Вы можете сопоставлять только по типу как в примере:
-```tut
-abstract class Device
+
+{% tabs pattern-matching-6 class=tabs-scala-version %}
+{% tab 'Scala 2' for=pattern-matching-6 %}
+
+```scala mdoc
+sealed trait Device
case class Phone(model: String) extends Device {
def screenOff = "Turning screen off"
}
@@ -123,29 +237,99 @@ case class Computer(model: String) extends Device {
def screenSaverOn = "Turning screen saver on..."
}
-def goIdle(device: Device) = device match {
+def goIdle(device: Device): String = device match {
case p: Phone => p.screenOff
case c: Computer => c.screenSaverOn
}
```
+
+{% endtab %}
+{% tab 'Scala 3' for=pattern-matching-6 %}
+
+```scala
+sealed trait Device
+case class Phone(model: String) extends Device:
+ def screenOff = "Turning screen off"
+
+case class Computer(model: String) extends Device:
+ def screenSaverOn = "Turning screen saver on..."
+
+
+def goIdle(device: Device): String = device match
+ case p: Phone => p.screenOff
+ case c: Computer => c.screenSaverOn
+```
+
+{% endtab %}
+{% endtabs %}
+
метод `goIdle` реализует изменение поведения в зависимости от типа `Device`. По соглашению в качестве названия варианта используется первая буква типа (в данном случае `p` и `c`).
-## Запечатанные классы
-Трейты и классы могут быть помечены как `sealed` это означает, что подтипы должны быть объявлены в одном файле, гарантируя тем самым, что все подтипы будут известны.
+## Запечатанные типы
+
+Вы могли заметить, что в приведенных выше примерах базовые типы уточняются с помощью ключевого слова `sealed`.
+Это обеспечивает дополнительную безопасность, поскольку компилятор проверяет,
+указаны ли все случаи в выражении `match`, если базовым типом является `sealed`.
+
+Например, в методе `showNotification`, определенном выше,
+если мы "забудем" один пример, скажем, `VoiceRecording`,
+компилятор выдаст предупреждение:
-```tut
-sealed abstract class Furniture
-case class Couch() extends Furniture
-case class Chair() extends Furniture
+{% tabs pattern-matching-7 class=tabs-scala-version %}
+{% tab 'Scala 2' for=pattern-matching-7 %}
-def findPlaceToSit(piece: Furniture): String = piece match {
- case a: Couch => "Lie on the couch"
- case b: Chair => "Sit on the chair"
+```scala
+def showNotification(notification: Notification): String = {
+ notification match {
+ case Email(sender, title, _) =>
+ s"You got an email from $sender with title: $title"
+ case SMS(number, message) =>
+ s"You got an SMS from $number! Message: $message"
+ }
}
```
-Это полезно для сопоставления с примером, ведь мы будем заранее знать все доступные варианты и нам не нужен вариант "все остальные".
+
+{% endtab %}
+{% tab 'Scala 3' for=pattern-matching-7 %}
+
+```scala
+def showNotification(notification: Notification): String =
+ notification match
+ case Email(sender, title, _) =>
+ s"You got an email from $sender with title: $title"
+ case SMS(number, message) =>
+ s"You got an SMS from $number! Message: $message"
+```
+
+{% endtab %}
+{% endtabs %}
+
+Это определение выдает следующее предупреждение:
+
+```
+match may not be exhaustive.
+
+It would fail on pattern case: VoiceRecording(_, _)
+```
+
+Компилятор даже предоставляет примеры входных данных, которые потерпят неудачу при сопоставлении!
+
+С другой стороны, проверка полноты требует, чтобы вы определили все подтипы базового типа в том же файле,
+что и базовый тип (иначе бы компилятор не знал все возможные варианты).
+Например, если вы попытаетесь определить новый тип `Notification` вне файла,
+который определяет `sealed trait Notification`, это приведет к ошибке компиляции:
+
+```
+case class Telepathy(message: String) extends Notification
+ ^
+ Cannot extend sealed trait Notification in a different source file
+```
## Замечания
Сопоставление с примером наиболее полезно для сопоставления алгебраических типов, выраженных через [классы образцы](case-classes.html).
Scala также позволяет создавать образцы независимо от классов образцов, через использование метода `unapply` в [объектах экстракторах](extractor-objects.html).
+
+## Дополнительные ресурсы
+
+- Дополнительная информация о сопоставлении с примером доступна [в книге Scala](/ru/scala3/book/control-structures.html#match-выражения).
diff --git a/_ru/tour/polymorphic-methods.md b/_ru/tour/polymorphic-methods.md
index a430aaf654..115cec0d94 100644
--- a/_ru/tour/polymorphic-methods.md
+++ b/_ru/tour/polymorphic-methods.md
@@ -1,24 +1,22 @@
---
layout: tour
title: Полиморфные методы
-
-discourse: true
-
partof: scala-tour
-
num: 28
language: ru
next-page: type-inference
previous-page: implicit-conversions
prerequisite-knowledge: unified-types
-
---
-Также как и у обобщенных классов, у методов есть полиморфизм по типу, с таким же синтаксисом (параметр типа указывается в квадратных скобках сразу после названия метода).
+Также как и у обобщенных классов, у методов есть полиморфизм по типу, с таким же синтаксисом (параметр типа указывается в квадратных скобках сразу после названия метода).
Вот пример:
-```tut
+{% tabs polymorphic-methods_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=polymorphic-methods_1 %}
+
+```scala mdoc
def listOfDuplicates[A](x: A, length: Int): List[A] = {
if (length < 1)
Nil
@@ -29,8 +27,25 @@ println(listOfDuplicates[Int](3, 4)) // List(3, 3, 3, 3)
println(listOfDuplicates("La", 8)) // List(La, La, La, La, La, La, La, La)
```
+{% endtab %}
+{% tab 'Scala 3' for=polymorphic-methods_1 %}
+
+```scala
+def listOfDuplicates[A](x: A, length: Int): List[A] =
+ if length < 1 then
+ Nil
+ else
+ x :: listOfDuplicates(x, length - 1)
+
+println(listOfDuplicates[Int](3, 4)) // List(3, 3, 3, 3)
+println(listOfDuplicates("La", 8)) // List(La, La, La, La, La, La, La, La)
+```
+
+{% endtab %}
+{% endtabs %}
+
Метод `listOfDuplicates` принимает параметр типа `A` и параметры значений `x` и `length`. Значение `x` имеет тип `A`. Если `length < 1` мы возвращаем пустой список. В противном случае мы добавляем `x`к списку, которые возвращаем через рекурсивный вызовов. (Обратите внимание, что `::` означает добавление элемента слева к списку справа).
В первом вызове метода мы явно указываем параметр типа, записывая `[Int]`. Поэтому первым аргументом должен быть `Int` и тип возвращаемого значения будет `List[Int]`.
-Во втором вызове показано, что вам не всегда нужно явно указывать параметр типа. Часто компилятор сам может вывести тип исходя из контекста или типа передаваемых аргументов. В этом варианте `"La"` - это `String`, поэтому компилятор знает, что `A` должен быть `String`.
+Во втором вызове показано, что вам не всегда нужно явно указывать параметр типа. Часто компилятор сам может вывести тип исходя из контекста или типа передаваемых аргументов. В этом варианте `"La"` - это `String`, поэтому компилятор знает, что `A` должен быть `String`.
diff --git a/_ru/tour/regular-expression-patterns.md b/_ru/tour/regular-expression-patterns.md
index 32877a0106..2058d76ee7 100644
--- a/_ru/tour/regular-expression-patterns.md
+++ b/_ru/tour/regular-expression-patterns.md
@@ -1,21 +1,20 @@
---
layout: tour
title: Регулярные Выражения
-
-discourse: true
-
partof: scala-tour
-
num: 15
language: ru
next-page: extractor-objects
previous-page: singleton-objects
-
---
-Регулярные выражения (Regular expression) - это специальный шаблон для поиска данных задаваемый в виде текстовой строки. Любая строка может быть преобразована в регулярное выражение методом `.r`.
+Регулярные выражения (Regular expression) - это специальный шаблон для поиска данных, задаваемый в виде текстовой строки. Любая строка может быть преобразована в регулярное выражение методом `.r`.
-```tut
+{% tabs regex-patterns_numberPattern class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=regex-patterns_numberPattern %}
+
+```scala mdoc
import scala.util.matching.Regex
val numberPattern: Regex = "[0-9]".r
@@ -26,14 +25,36 @@ numberPattern.findFirstMatchIn("awesomepassword") match {
}
```
+{% endtab %}
+
+{% tab 'Scala 3' for=regex-patterns_numberPattern %}
+
+```scala
+import scala.util.matching.Regex
+
+val numberPattern: Regex = "[0-9]".r
+
+numberPattern.findFirstMatchIn("awesomepassword") match
+ case Some(_) => println("Password OK")
+ case None => println("Password must contain a number")
+```
+
+{% endtab %}
+
+{% endtabs %}
+
В приведенном выше примере `numberPattern` - это `Regex` (регулярное выражение), которое мы используем, чтобы убедиться, что пароль содержит число.
Используя круглые скобки можно объединять сразу несколько групп регулярных выражений.
-```tut
+{% tabs regex-patterns_keyValPattern class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=regex-patterns_keyValPattern %}
+
+```scala mdoc
import scala.util.matching.Regex
-val keyValPattern: Regex = "([0-9a-zA-Z-#() ]+): ([0-9a-zA-Z-#() ]+)".r
+val keyValPattern: Regex = "([0-9a-zA-Z- ]+): ([0-9a-zA-Z-#()/. ]+)".r
val input: String =
"""background-color: #A03300;
@@ -48,7 +69,36 @@ val input: String =
for (patternMatch <- keyValPattern.findAllMatchIn(input))
println(s"key: ${patternMatch.group(1)} value: ${patternMatch.group(2)}")
```
-Здесь мы обработали сразу и ключи и значения строки. В каждой совпадении есть подгруппа совпадений. Вот как выглядит результат:
+
+{% endtab %}
+
+{% tab 'Scala 3' for=regex-patterns_keyValPattern %}
+
+```scala
+import scala.util.matching.Regex
+
+val keyValPattern: Regex = "([0-9a-zA-Z- ]+): ([0-9a-zA-Z-#()/. ]+)".r
+
+val input: String =
+ """background-color: #A03300;
+ |background-image: url(img/header100.png);
+ |background-position: top center;
+ |background-repeat: repeat-x;
+ |background-size: 2160px 108px;
+ |margin: 0;
+ |height: 108px;
+ |width: 100%;""".stripMargin
+
+for patternMatch <- keyValPattern.findAllMatchIn(input) do
+ println(s"key: ${patternMatch.group(1)} value: ${patternMatch.group(2)}")
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+Здесь мы обработали сразу и ключи и значения строки. В каждом совпадении есть подгруппа совпадений. Вот как выглядит результат:
+
```
key: background-color value: #A03300
key: background-image value: url(img
@@ -59,3 +109,68 @@ key: margin value: 0
key: height value: 108px
key: width value: 100
```
+
+Кроме того, регулярные выражения можно использовать в качестве шаблонов (в выражениях `match`)
+для удобного извлечения совпавших групп:
+
+{% tabs regex-patterns_saveContactInformation class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=regex-patterns_saveContactInformation %}
+
+```scala mdoc
+def saveContactInformation(contact: String): Unit = {
+ import scala.util.matching.Regex
+
+ val emailPattern: Regex = """^(\w+)@(\w+(.\w+)+)$""".r
+ val phonePattern: Regex = """^(\d{3}-\d{3}-\d{4})$""".r
+
+ contact match {
+ case emailPattern(localPart, domainName, _) =>
+ println(s"Hi $localPart, we have saved your email address.")
+ case phonePattern(phoneNumber) =>
+ println(s"Hi, we have saved your phone number $phoneNumber.")
+ case _ =>
+ println("Invalid contact information, neither an email address nor phone number.")
+ }
+}
+
+saveContactInformation("123-456-7890")
+saveContactInformation("JohnSmith@sample.domain.com")
+saveContactInformation("2 Franklin St, Mars, Milky Way")
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=regex-patterns_saveContactInformation %}
+
+```scala
+def saveContactInformation(contact: String): Unit =
+ import scala.util.matching.Regex
+
+ val emailPattern: Regex = """^(\w+)@(\w+(.\w+)+)$""".r
+ val phonePattern: Regex = """^(\d{3}-\d{3}-\d{4})$""".r
+
+ contact match
+ case emailPattern(localPart, domainName, _) =>
+ println(s"Hi $localPart, we have saved your email address.")
+ case phonePattern(phoneNumber) =>
+ println(s"Hi, we have saved your phone number $phoneNumber.")
+ case _ =>
+ println("Invalid contact information, neither an email address nor phone number.")
+
+saveContactInformation("123-456-7890")
+saveContactInformation("JohnSmith@sample.domain.com")
+saveContactInformation("2 Franklin St, Mars, Milky Way")
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+Вот как выглядит результат:
+
+```
+Hi, we have saved your phone number 123-456-7890.
+Hi JohnSmith, we have saved your email address.
+Invalid contact information, neither an email address nor phone number.
+```
diff --git a/_ru/tour/self-types.md b/_ru/tour/self-types.md
index ccc896b0ec..06597bfe70 100644
--- a/_ru/tour/self-types.md
+++ b/_ru/tour/self-types.md
@@ -1,25 +1,25 @@
---
layout: tour
title: Самоописываемые типы
-
-discourse: true
-
partof: scala-tour
-
num: 25
language: ru
next-page: implicit-parameters
previous-page: compound-types
topics: self-types
prerequisite-knowledge: nested-classes, mixin-class-composition
-
---
-Самоописываемый тип(Self type) - это способ объявить, что трейт должен быть смешан с другим трейтом, даже если он не расширяет его напрямую. Что открывает доступ к членам зависимости без импортирования.
+
+Самоописываемый тип (Self type) - это способ объявить, что трейт должен быть смешан с другим трейтом, даже если он не расширяет его напрямую. Что открывает доступ к членам зависимости без импортирования.
Самоописываемый тип - это способ сузить тип `this` или другого идентификатора, который ссылается на `this`. Синтаксис похож на синтаксис обычной функции, но означает кое-что иное.
Чтобы использовать самоописываемый тип в трейте напишите: идентификатор, тип другого трейта, который хотите добавить и `=>` (например, `someIdentifier: SomeOtherTrait =>`).
-```tut
+
+{% tabs self-types_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=self-types_1 %}
+
+```scala mdoc
trait User {
def username: String
}
@@ -30,7 +30,7 @@ trait Tweeter {
}
class VerifiedTweeter(val username_ : String) extends Tweeter with User { // Мы добавили User потому этого требует Tweeter
- def username = s"real $username_"
+ def username = s"real $username_"
}
val realBeyoncé = new VerifiedTweeter("Beyoncé")
@@ -38,3 +38,26 @@ realBeyoncé.tweet("Just spilled my glass of lemonade") // выведет "real
```
Поскольку мы указали `this: User =>` в трейте `Tweeter`, теперь переменная `username` находится в пределах видимости для метода `tweet`. Это также означает что `VerifiedTweeter` при наследовании от `Tweeter` должен быть смешан с `User` (используя `with User`).
+
+{% endtab %}
+{% tab 'Scala 3' for=self-types_1 %}
+
+```scala
+trait User:
+ def username: String
+
+trait Tweeter:
+ this: User => // переназначил this
+ def tweet(tweetText: String) = println(s"$username: $tweetText")
+
+class VerifiedTweeter(val username_ : String) extends Tweeter, User: // Мы добавили User потому этого требует Tweeter
+ def username = s"real $username_"
+
+val realBeyoncé = VerifiedTweeter("Beyoncé")
+realBeyoncé.tweet("Just spilled my glass of lemonade") // выведет "real Beyoncé: Just spilled my glass of lemonade"
+```
+
+Поскольку мы указали `this: User =>` в трейте `Tweeter`, теперь переменная `username` находится в пределах видимости для метода `tweet`. Это также означает что `VerifiedTweeter` при наследовании от `Tweeter` должен быть смешан с `User` (используя `, User`).
+
+{% endtab %}
+{% endtabs %}
diff --git a/_ru/tour/singleton-objects.md b/_ru/tour/singleton-objects.md
index 2867dda492..5a0da42d5c 100644
--- a/_ru/tour/singleton-objects.md
+++ b/_ru/tour/singleton-objects.md
@@ -1,41 +1,74 @@
---
layout: tour
title: Объекты Одиночки
-
-discourse: true
-
partof: scala-tour
-
num: 13
language: ru
next-page: regular-expression-patterns
previous-page: pattern-matching
prerequisite-knowledge: classes, methods, private-methods, packages, option
---
+
Все объекты являются одиночками (Singleton Object) - то есть существуют в единственном экземпляре. Он создается лениво, когда на него ссылаются, также как ленивые значения (lazy val).
На самом верхнем уровне объект является одиночкой.
Как член класса или как локальная переменная, он ведет себя точно так же как ленивое значение (lazy val).
+
# Объявление одиночного объекта
+
Объект - является значением. Объявление объекта происходит схожим с классом образом, но используется ключевое слово `object`:
-```tut
+
+{% tabs object-definition-box %}
+
+{% tab 'Scala 2 и 3' for=object-definition-box %}
+
+```scala mdoc
object Box
```
+{% endtab %}
+
+{% endtabs %}
+
Вот пример объекта с методом:
-```
+
+{% tabs singleton-logger-example class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=singleton-logger-example %}
+
+```scala
package logging
object Logger {
def info(message: String): Unit = println(s"INFO: $message")
}
```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=singleton-logger-example %}
+
+```scala
+package logging
+
+object Logger:
+ def info(message: String): Unit = println(s"INFO: $message")
+```
+
+{% endtab %}
+
+{% endtabs %}
+
Метод `info` может быть импортирован в любом месте программы. Создание подобных методов является распространенным вариантом использования одиночных объектов.
Давайте посмотрим, как использовать `info` в другом пакете:
-```
+{% tabs singleton-usage-example class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=singleton-usage-example %}
+
+```scala
import logging.Logger.info
class Project(name: String, daysToComplete: Int)
@@ -47,15 +80,44 @@ class Test {
}
```
+{% endtab %}
+
+{% tab 'Scala 3' for=singleton-usage-example %}
+
+```scala
+import logging.Logger.info
+
+class Project(name: String, daysToComplete: Int)
+
+class Test:
+ val project1 = Project("TPS Reports", 1)
+ val project2 = Project("Website redesign", 5)
+ info("Created projects") // Prints "INFO: Created projects"
+```
+
+{% endtab %}
+
+{% endtabs %}
+
Метод `info` виден благодаря указанию импорта `import logging.Logger.info`.
+Для импорта требуется "постоянный путь" к импортируемому символу, а путь к объекту неизменен.
-Замечание: Если `object` не является объектом верхнего уровня, но вложен в другой класс или объект, то объект, как и любой другой член, "зависим от пути".
+Замечание: Если `object` не является объектом верхнего уровня, но вложен в другой класс или объект,
+то объект, как и любой другой член, "зависим от пути".
+Это означает, что для двух видов напитков, `class Milk` и `class OrangeJuice`,
+элемент класса `object NutritionInfo` "зависит" от включающего его экземпляра, будь то `Milk` или `OrangeJuice`.
+`milk.NutritionInfo` полностью отличается от `oj.NutritionInfo`.
## Объекты компаньоны
Объект с тем же именем, что и класс называется _объект компаньон_ (companion object). И наоборот, класс является классом-компаньоном объекта. Класс или объект компаньон может получить доступ к приватным членам своего спутника. Используйте объект компаньон для методов и значений, которые не специфичны для экземпляров класса компаньона.
-```
-import scala.math._
+
+{% tabs companion-object-circle class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=companion-object-circle %}
+
+```scala
+import scala.math.pow
case class Circle(radius: Double) {
import Circle._
@@ -71,10 +133,38 @@ val circle1 = Circle(5.0)
circle1.area
```
+{% endtab %}
+
+{% tab 'Scala 3' for=companion-object-circle %}
+
+```scala
+import scala.math.pow
+
+case class Circle(radius: Double):
+ import Circle.*
+ def area: Double = calculateArea(radius)
+
+object Circle:
+ private def calculateArea(radius: Double): Double = Pi * pow(radius, 2.0)
+
+
+val circle1 = Circle(5.0)
+
+circle1.area
+```
+
+{% endtab %}
+
+{% endtabs %}
+
Класс `Circle` имеет член `area`, который специфичен для каждого конкретного экземпляра, а метод `calculateArea` одиночного объекта `Circle`, доступен для каждого экземпляра класса `Circle`.
Объект компаньон может также содержать методы создающие конкретные экземпляры класса спутника:
-```tut
+{% tabs companion-object-email class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=companion-object-email %}
+
+```scala mdoc
class Email(val username: String, val domainName: String)
object Email {
@@ -92,16 +182,48 @@ scalaCenterEmail match {
s"""Registered an email
|Username: ${email.username}
|Domain name: ${email.domainName}
- """)
+ """.stripMargin)
case None => println("Error: could not parse email")
}
```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=companion-object-email %}
+
+```scala
+class Email(val username: String, val domainName: String)
+
+object Email:
+ def fromString(emailString: String): Option[Email] =
+ emailString.split('@') match
+ case Array(a, b) => Some(Email(a, b))
+ case _ => None
+
+val scalaCenterEmail = Email.fromString("scala.center@epfl.ch")
+scalaCenterEmail match
+ case Some(email) => println(
+ s"""Registered an email
+ |Username: ${email.username}
+ |Domain name: ${email.domainName}
+ """.stripMargin)
+ case None => println("Error: could not parse email")
+```
+
+{% endtab %}
+
+{% endtabs %}
+
`object Email` содержит производящий метод `fromString`, который создает экземпляр `Email` из строки. Мы возвращаем результат как `Option[Email]` на случай возникновения ошибок парсинга.
Примечание: Если у класса или объекта есть компаньон, они должны быть размещены в одном и том же файле. Чтобы задать компаньонов в REPL, либо определите их на той же строке, либо перейдите в режим `:paste`.
-## Примечания для Java-программистов ##
+## Примечания для Java-программистов
`static` члены в Java смоделированы как обычные члены объекта компаньона в Scala.
При использовании объекта компаньона из Java-кода, члены будут определены в сопутствующем классе компаньоне с `static` модификатором. Это называется _пробрасывание статики_. Такое происходит, даже если вы сами не определили класс компаньон.
+
+## Дополнительные ресурсы
+
+- Узнайте больше об объектах компаньонах в [Scala Book](/ru/scala3/book/domain-modeling-tools.html#сопутствующие-объекты)
diff --git a/_ru/tour/tour-of-scala.md b/_ru/tour/tour-of-scala.md
index 637a12d8cc..62f9fbe592 100644
--- a/_ru/tour/tour-of-scala.md
+++ b/_ru/tour/tour-of-scala.md
@@ -1,59 +1,60 @@
---
layout: tour
title: Введение
-
-discourse: true
-
partof: scala-tour
-
num: 1
language: ru
next-page: basics
---
## Добро пожаловать к обзору
+
Здесь вы увидите вводное описание наиболее часто используемых возможностей Scala.
Этот обзор предназначен для новичков в изучении языка.
-Это лишь небольшая экскурсия, а не полный курс освоения языка. Для глубокого погружения рекомендуем почитать [книги](/books.html) или воспользоваться курсами
-[на других ресурсах](/learn.html).
+Это лишь небольшая экскурсия, а не полный курс освоения языка. Для глубокого погружения рекомендуем почитать [книги](/books.html) или воспользоваться курсами
+[на других ресурсах](/online-courses.html).
## Что такое Scala?
+
Scala - это современный мультипарадигмальный язык программирования, разработанный для выражения общих концепций программирования в простой, удобной и типобезопасной манере. Элегантно объединяя особенности объектно-ориентированных и функциональных языков.
-## Scala объектно ориентированный ##
+## Scala объектно ориентированный
+
Scala - это чистый объектно-ориентированный язык в том смысле, что [каждое значение - это объект](unified-types.html). Типы и поведение объектов описаны в [классах](classes.html) и [трейтах](traits.html)(характеристиках объектов). Классы расширяются за счет механизма наследования и гибкого [смешивания классов](mixin-class-composition.html), который используется для замены множественного наследования.
-## Scala функциональный ##
+## Scala функциональный
+
Scala также является функциональным языком в том смысле, что [каждая функция - это значение](unified-types.html). Scala предоставляет [легкий синтаксис](basics.html) для определения анонимных функций, поддерживает [функции высшего порядка](higher-order-functions.html), поддерживает [вложенные функции](nested-functions.html), а также [каррирование](multiple-parameter-lists.html). Scala имеют встроенную поддержку алгебраических типов данных, которые используются в большинстве функциональных языках программирования (эта поддержка базируется на механизме [сопоставления с примером](pattern-matching.html), где в качестве примера выступают [классы образцы](case-classes.html) ). [Объекты](singleton-objects.html) предоставляют удобный способ группировки функций, не входящих в класс.
Вдобавок к этому, концепция сопоставления с примером логично переносится на [обработку XML-данных](https://github.com/scala/scala-xml/wiki/XML-Processing) используя в качестве примера [регулярные выражения](regular-expression-patterns.html), при поддержке функционала [объектов экстракторов](extractor-objects.html). Для еще большего удобства обработки данных представлена схема формирования запросов с использованием [for-выражения](for-comprehensions.html). Такие возможности делают Scala идеальным решением для разработки приложений по типу веб-сервисов.
-## Scala статически типизированный ##
+## Scala статически типизированный
+
Scala оснащен выразительной системой типов, которая обеспечивает безопасное и гармоничное использование абстракций. В частности, система типов поддерживает:
-* [обобщенные классы](generic-classes.html)
-* [вариантность типов](variances.html)
-* [верхние](upper-type-bounds.html) и [нижние](lower-type-bounds.html) границы типов
-* [внутренние классы](inner-classes.html) и [члены абстрактного типа](abstract-type-members.html), как часть объектов
-* [составные типы](compound-types.html)
-* [самоописываемые типы](self-types.html)
-* [неявные параметры](implicit-parameters.html) и [неявные преобразования](implicit-conversions.html)
-* [полиморфные методы](polymorphic-methods.html)
+- [обобщенные классы](generic-classes.html)
+- [вариантность типов](variances.html)
+- [верхние](upper-type-bounds.html) и [нижние](lower-type-bounds.html) границы типов
+- [внутренние классы](inner-classes.html) и [члены абстрактного типа](abstract-type-members.html), как часть объектов
+- [составные типы](compound-types.html)
+- [самоописываемые типы](self-types.html)
+- [неявные параметры](implicit-parameters.html) и [неявные преобразования](implicit-conversions.html)
+- [полиморфные методы](polymorphic-methods.html)
-[Выведение типов](type-inference.html) означает, что разработчику не обязательно добавлять в код избыточную информацию о типах.
+[Выведение типов](type-inference.html) означает, что разработчику не обязательно добавлять в код избыточную информацию о типах.
Такой функционал обеспечивает основу для безопасного переиспользования абстракций и типобезопасного развития программного обеспечения.
-## Scala расширяемый ##
+## Scala расширяемый
Зачастую разработка приложений для очень специфичных областей требует специфичных для этих областей языковых возможностей, либо отдельных специализированных языков программирования. Вместо этого Scala предлагает уникальные механизмы, для легкой модификации и расширения самого языка.
Во многих случаях такое можно сделать без использования средств мета-программирования, таких как макросы. Например:
-* [Неявные классы](https://docs.scala-lang.org/overviews/core/implicit-classes.html) позволяют добавлять новые методы к уже существующим.
-* [Интерполяция строк](/overviews/core/string-interpolation.html) позволяет добавлять обработку строк (расширяется разработчиком с помощью интерполяторов).
+- [Неявные классы](https://docs.scala-lang.org/overviews/core/implicit-classes.html) позволяют добавлять новые методы к уже существующим.
+- [Интерполяция строк](/ru/scala3/book/string-interpolation.html) позволяет добавлять обработку строк (расширяется разработчиком с помощью интерполяторов).
-## Scala совместимый
+## Scala совместимый
Scala полностью совместим с популярной средой Java Runtime Environment (JRE). Взаимодействие с основным объектно-ориентированным языком программирования Java происходит максимально гладко. Новые функции Java, такие как SAM, [лямбды](higher-order-functions.html), [аннотации](annotations.html) и [дженерики](generic-classes.html), имеют прямые аналоги в Scala.
@@ -61,4 +62,4 @@ Scala полностью совместим с популярной средой
## Наслаждайтесь туром!
-Для продолжения знакомства предлагаю перейти на [следующую страницу](basics.html) нашего тура.
\ No newline at end of file
+Для продолжения знакомства предлагаю перейти на [следующую страницу](basics.html) нашего тура.
diff --git a/_ru/tour/traits.md b/_ru/tour/traits.md
index 4fea28e80f..ef958c94cf 100644
--- a/_ru/tour/traits.md
+++ b/_ru/tour/traits.md
@@ -1,42 +1,69 @@
---
layout: tour
title: Трейты
-
-discourse: true
-
partof: scala-tour
-
num: 5
language: ru
next-page: tuples
-previous-page: classes
+previous-page: named-arguments
topics: traits
prerequisite-knowledge: expressions, classes, generics, objects, companion-objects
-
---
-Трейты (Traits) используются чтоб обмениваться между классами информацией о структуре и полях. Они похожи на интерфейсы из Java 8. Классы и объекты могут расширять трейты, но трейты не могут быть созданы и поэтому не имеют параметров.
+Трейты (Traits) используются, чтобы обмениваться между классами информацией о структуре и полях. Они похожи на интерфейсы из Java 8. Классы и объекты могут расширять трейты, но трейты не могут быть созданы и поэтому не имеют параметров.
## Объявление трейта
+
Минимальное объявление трейта - это просто ключевое слово `trait` и его имя:
-```tut
+{% tabs trait-hair-color %}
+{% tab 'Scala 2 и 3' for=trait-hair-color %}
+
+```scala mdoc
trait HairColor
```
+{% endtab %}
+{% endtabs %}
+
Трейты наиболее полезны в качестве обобщенного типа с абстрактными методами.
-```tut
+
+{% tabs trait-iterator-definition class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=trait-iterator-definition %}
+
+```scala mdoc
trait Iterator[A] {
def hasNext: Boolean
def next(): A
}
```
+{% endtab %}
+
+{% tab 'Scala 3' for=trait-iterator-definition %}
+
+```scala
+trait Iterator[A]:
+ def hasNext: Boolean
+ def next(): A
+```
+
+{% endtab %}
+
+{% endtabs %}
+
При наследовании от трейта `Iterator[A]` требует указание типа `A` а также реализация методов `hasNext` и `next`.
## Использование трейтов
-Чтоб использовать трейты, необходимо наследовать класс от него используя ключевое слово `extends`. Затем необходимо реализовать все абстрактные члены трейта, используя ключевое слово `override`:
-```tut
+
+Чтобы использовать трейты, необходимо наследовать класс от него, используя ключевое слово `extends`. Затем необходимо реализовать все абстрактные члены трейта, используя ключевое слово `override`:
+
+{% tabs trait-intiterator-definition class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=trait-intiterator-definition %}
+
+```scala mdoc:nest
trait Iterator[A] {
def hasNext: Boolean
def next(): A
@@ -45,7 +72,7 @@ trait Iterator[A] {
class IntIterator(to: Int) extends Iterator[Int] {
private var current = 0
override def hasNext: Boolean = current < to
- override def next(): Int = {
+ override def next(): Int = {
if (hasNext) {
val t = current
current += 1
@@ -54,16 +81,52 @@ class IntIterator(to: Int) extends Iterator[Int] {
}
}
+val iterator = new IntIterator(10)
+iterator.next() // вернет 0
+iterator.next() // вернет 1
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=trait-intiterator-definition %}
+
+```scala
+trait Iterator[A]:
+ def hasNext: Boolean
+ def next(): A
+
+class IntIterator(to: Int) extends Iterator[Int]:
+ private var current = 0
+ override def hasNext: Boolean = current < to
+ override def next(): Int =
+ if hasNext then
+ val t = current
+ current += 1
+ t
+ else
+ 0
+end IntIterator
val iterator = new IntIterator(10)
iterator.next() // вернет 0
iterator.next() // вернет 1
```
+
+{% endtab %}
+
+{% endtabs %}
+
Этот класс `IntIterator` использует параметр `to` в качестве верхней границы. Он наследуется от `Iterator[Int]`, что означает, что метод `next` должен возвращать Int.
## Подтипы
-Туда где требуется определенный тип трейта, мы можем передавать любой наследованный от требуемого трейта класс
-```tut
+
+Туда, где требуется определенный тип трейта, мы можем передавать любой наследованный от требуемого трейта класс
+
+{% tabs trait-pet-example class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=trait-pet-example %}
+
+```scala mdoc
import scala.collection.mutable.ArrayBuffer
trait Pet {
@@ -81,4 +144,36 @@ animals.append(dog)
animals.append(cat)
animals.foreach(pet => println(pet.name)) // выведет "Harry" и "Sally"
```
-У трейта `Pet` есть абстрактное поле `name`, которое реализовано в классах `Cat` and `Dog`. В последней строке мы вызываем `pet.name`, который должен быть реализован в любом подтипе унаследованным от трейта `Pet`.
+
+{% endtab %}
+
+{% tab 'Scala 3' for=trait-pet-example %}
+
+```scala
+import scala.collection.mutable.ArrayBuffer
+
+trait Pet:
+ val name: String
+
+class Cat(val name: String) extends Pet
+class Dog(val name: String) extends Pet
+
+val dog = Dog("Harry")
+val cat = Cat("Sally")
+
+val animals = ArrayBuffer.empty[Pet]
+animals.append(dog)
+animals.append(cat)
+animals.foreach(pet => println(pet.name)) // выведет "Harry" и "Sally"
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+У трейта `Pet` есть абстрактное поле `name`, которое реализовано в классах `Cat` and `Dog`. В последней строке мы вызываем `pet.name`, который должен быть реализован в любом подтипе, унаследованном от трейта `Pet`.
+
+## Дополнительные ресурсы
+
+- Узнайте больше о трейтах в [Scala Book](/ru/scala3/book/domain-modeling-tools.html#трейты)
+- Использование трейтов для определения [Enum](/ru/scala3/book/domain-modeling-fp.html#моделирование-данных)
diff --git a/_ru/tour/tuples.md b/_ru/tour/tuples.md
index 094a76fbdf..8f1550c473 100644
--- a/_ru/tour/tuples.md
+++ b/_ru/tour/tuples.md
@@ -1,95 +1,142 @@
---
layout: tour
title: Кортежи
-
-discourse: true
-
partof: scala-tour
-
num: 6
language: ru
next-page: mixin-class-composition
previous-page: traits
topics: tuples
-
---
-В Scala, кортеж (Тuple) это класс контейнер содержащий упорядоченный набор элементов различного типа.
-Кортежи неизменяемы.
+В Scala, кортеж (Тuple) - это контейнер содержащий упорядоченный набор элементов различного типа.
+Кортежи неизменяемы.
Кортежи могут пригодиться, когда нам нужно вернуть сразу несколько значений из функции.
Кортеж может быть создан как:
-```tut
-val ingredient = ("Sugar" , 25):Tuple2[String, Int]
+{% tabs tuple-construction %}
+
+{% tab 'Scala 2 и 3' for=tuple-construction %}
+
+```scala mdoc
+val ingredient = ("Sugar", 25)
```
-Такая запись создает кортеж размерности 2, содержащий пару элементов String и Int.
-Кортежи в Скале - представлены серией классов: Tuple2, Tuple3 и т.д., до Tuple22.
-Таким образом, создавая кортеж с n элементами (n лежащими между 2 и 22), Скала просто создает один из соответствующих классов, который параметризован типом входящих в состав элементов.
+{% endtab %}
-В нашем примере, составляющие тип Tuple2[String, Int].
+{% endtabs %}
+
+Такая запись создает кортеж, содержащий пару элементов `String` и `Int`.
+
+Выводимый тип `ingredient` - это `(String, Int)`.
## Доступ к элементам
-Доступ к элементам кортежа осуществляется при помощи синтаксиса подчеркивания.
-'tuple._n' дает n-ый элемент (столько, сколько существует элементов).
+{% tabs tuple-indexed-access class=tabs-scala-version %}
-```tut
-println(ingredient._1) // Sugar
+{% tab 'Scala 2' for=tuple-indexed-access %}
+Один из способов доступа к элементам кортежа — по их позиции.
+`tuple._n` дает n-ый элемент (столько, сколько существует элементов).
+
+```scala mdoc
+println(ingredient._1) // Sugar
println(ingredient._2) // 25
```
-## Распаковка данных кортежа
+{% endtab %}
-Scala кортежи также поддерживают [распаковку](extractor-objects.html).
+{% tab 'Scala 3' for=tuple-indexed-access %}
-```tut
-val (name, quantity) = ingredient
+Один из способов доступа к элементам кортежа — по их позиции.
+Доступ к отдельным элементам осуществляется с помощью `tuple(0)`, `tuple(1)` и так далее.
+
+```scala
+println(ingredient(0)) // Sugar
+println(ingredient(1)) // 25
+```
+
+{% endtab %}
+
+{% endtabs %}
-println(name) // Sugar
+## Сопоставление с образцом для кортежей
+Кортеж также можно распаковать с помощью сопоставления с образцом:
+
+{% tabs tuple-extraction %}
+
+{% tab 'Scala 2 и 3' for=tuple-extraction %}
+
+```scala mdoc
+val (name, quantity) = ingredient
+println(name) // Sugar
println(quantity) // 25
```
-Распаковка данных кортежа может быть использована в [сопоставлении с примером](pattern-matching.html)
-
-```tut
-val planetDistanceFromSun = List(("Mercury", 57.9), ("Venus", 108.2), ("Earth", 149.6 ), ("Mars", 227.9), ("Jupiter", 778.3))
-
-planetDistanceFromSun.foreach{ tuple => {
-
- tuple match {
-
- case ("Mercury", distance) => println(s"Mercury is $distance millions km far from Sun")
-
- case p if(p._1 == "Venus") => println(s"Venus is ${p._2} millions km far from Sun")
-
- case p if(p._1 == "Earth") => println(s"Blue planet is ${p._2} millions km far from Sun")
-
- case _ => println("Too far....")
-
- }
-
- }
-
+{% endtab %}
+
+{% endtabs %}
+
+Здесь выводимый тип `name` - `String` и выводимый тип `quantity` - `Int`.
+
+Вот еще один пример сопоставления с образцом кортежа:
+
+{% tabs tuple-foreach-patmat %}
+
+{% tab 'Scala 2 и 3' for=tuple-foreach-patmat %}
+
+```scala mdoc
+val planets =
+ List(("Mercury", 57.9), ("Venus", 108.2), ("Earth", 149.6),
+ ("Mars", 227.9), ("Jupiter", 778.3))
+planets.foreach {
+ case ("Earth", distance) =>
+ println(s"Our planet is $distance million kilometers from the sun")
+ case _ =>
}
```
-Или в ['for' выражении](for-comprehensions.html).
+{% endtab %}
-```tut
-val numPairs = List((2, 5), (3, -7), (20, 56))
+{% endtabs %}
-for ((a, b) <- numPairs) {
+Или, в _for-comprehension_:
+
+{% tabs tuple-for-extraction class=tabs-scala-version %}
+
+{% tab 'Scala 2' for=tuple-for-extraction %}
+```scala mdoc
+val numPairs = List((2, 5), (3, -7), (20, 56))
+for ((a, b) <- numPairs) {
println(a * b)
-
}
```
-Значение () типа Unit по свой сути совпадает со значением () типа Tuple0. Может быть только одно значение такого типа, так как в нём нет элементов.
+{% endtab %}
+
+{% tab 'Scala 3' for=tuple-for-extraction %}
+
+```scala
+val numPairs = List((2, 5), (3, -7), (20, 56))
+for (a, b) <- numPairs do
+ println(a * b)
+```
+
+{% endtab %}
+
+{% endtabs %}
+
+## Кортежи и кейс-классы
+
+Иногда бывает трудно выбирать между кортежами и кейс-классами.
+Кейс-классы содержат именованные элементы. Имена могут улучшить читаемость некоторых типов кода.
+В приведенном выше примере мы могли бы определить планеты, как `case class Planet(name: String, distance: Double)`,
+а не использовать кортежи.
+
+## Дополнительные ресурсы
-Иногда бывает трудно выбирать между кортежами и классами образцами. Как правило, классы образцы являются предпочтительным выбором, если класс-контейнер содержащий элементы сам по себе имеет значимый смысл.
+- Дополнительная информация о кортежах - в книге [Scala Book](/ru/scala3/book/taste-collections.html#кортежи)
diff --git a/_ru/tour/type-inference.md b/_ru/tour/type-inference.md
index 45aa9c1754..52f0836467 100644
--- a/_ru/tour/type-inference.md
+++ b/_ru/tour/type-inference.md
@@ -1,11 +1,7 @@
---
layout: tour
title: Выведение Типа
-
-discourse: true
-
partof: scala-tour
-
num: 29
language: ru
next-page: operators
@@ -16,27 +12,57 @@ previous-page: polymorphic-methods
## Не указывая тип
-```tut
+{% tabs type-inference_1 %}
+{% tab 'Scala 2 и 3' for=type-inference_1 %}
+
+```scala mdoc
val businessName = "Montreux Jazz Café"
```
+
+{% endtab %}
+{% endtabs %}
+
Компилятор может определить, что тип константы `businessName` является `String`. Аналогичным образом это работает и для методов:
-```tut
+{% tabs type-inference_2 %}
+{% tab 'Scala 2 и 3' for=type-inference_2 %}
+
+```scala mdoc
def squareOf(x: Int) = x * x
```
+
+{% endtab %}
+{% endtabs %}
+
Компилятор может определить, что возвращаемый тип является `Int`, поэтому явного указания типа не требуется.
Для рекурсивных методов компилятор не в состоянии вывести тип. Вот программа, которая не скомпилируется по этой причине:
-```tut:fail
+{% tabs type-inference_3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=type-inference_3 %}
+
+```scala mdoc:fail
def fac(n: Int) = if (n == 0) 1 else n * fac(n - 1)
```
+{% endtab %}
+{% tab 'Scala 3' for=type-inference_3 %}
+
+```scala
+def fac(n: Int) = if n == 0 then 1 else n * fac(n - 1)
+```
+
+{% endtab %}
+{% endtabs %}
+
Также необязательно указывать параметры типа при вызове [полиморфных методов](polymorphic-methods.html) или [обобщенных классов](generic-classes.html). Компилятор Scala определит тип параметра из контекста и из типов фактически передаваемых параметров метода/конструктора.
Вот два примера:
-```tut
+{% tabs type-inference_4 %}
+{% tab 'Scala 2 и 3' for=type-inference_4 %}
+
+```scala mdoc
case class MyPair[A, B](x: A, y: B)
val p = MyPair(1, "scala") // тип: MyPair[Int, String]
@@ -44,32 +70,53 @@ def id[T](x: T) = x
val q = id(1) // тип: Int
```
+{% endtab %}
+{% endtabs %}
+
Компилятор использует типы аргументов `MyPair` для определения типа `A` и `B`. Тоже самое для типа `x`.
## Параметры
Для параметров компилятор никогда не выводит тип. Однако, в некоторых случаях, он может вывести типы для параметров анонимной функции при передаче ее в качестве аргумента.
-```tut
+{% tabs type-inference_5 %}
+{% tab 'Scala 2 и 3' for=type-inference_5 %}
+
+```scala mdoc
Seq(1, 3, 4).map(x => x * 2) // List(2, 6, 8)
```
+{% endtab %}
+{% endtabs %}
+
Параметр у map - `f: A => B` (функциональный параметр переводящий тип из A в B). Поскольку мы разместили целые числа в нашей последовательности `Seq`, компилятор знает, что элемент `A` является `Int` (т.е. `x` является целым числом). Поэтому компилятор может определить из выражения `x * 2`, что результат (`B`) является типом `Int`.
## Когда _не следует_ полагаться на выведение типа
Обычно считается, наиболее удобочитаемым объявить тип членов, которые открыты для публичного использования через API. Поэтому мы рекомендуем вам явно указывать тип для любых API, которые будут доступны пользователям вашего кода.
-Кроме того, выведение может иногда приводить к слишком специфичному типу. Предположим, мы напишем:
+Кроме того, выведение может иногда приводить к слишком специфичному типу. Предположим, мы напишем:
+
+{% tabs type-inference_6 %}
+{% tab 'Scala 2 и 3' for=type-inference_6 %}
-```tut
+```scala
var obj = null
```
+{% endtab %}
+{% endtabs %}
+
Тогда мы не сможем далее сделать это переназначение:
-```tut:fail
+{% tabs type-inference_7 %}
+{% tab 'Scala 2 и 3' for=type-inference_7 %}
+
+```scala mdoc:fail
obj = new AnyRef
```
-Такое не будет компилироваться, потому что для `obj` предполагался тип `Null`. Поскольку единственным значением этого типа является `null`, то невозможно присвоить другое значение.
\ No newline at end of file
+{% endtab %}
+{% endtabs %}
+
+Такое не будет компилироваться, потому что для `obj` предполагался тип `Null`. Поскольку единственным значением этого типа является `null`, то невозможно присвоить другое значение.
diff --git a/_ru/tour/unified-types.md b/_ru/tour/unified-types.md
index 2f9c9f08f4..e5f947ed89 100644
--- a/_ru/tour/unified-types.md
+++ b/_ru/tour/unified-types.md
@@ -1,24 +1,19 @@
---
layout: tour
title: Единобразие типов
-
-discourse: true
-
partof: scala-tour
-
num: 3
language: ru
next-page: classes
previous-page: basics
prerequisite-knowledge: classes, basics
-
---
В Scala все значения имеют тип, включая числовые значения и функции. Диаграмма ниже иллюстрирует подмножество иерархии типов.
-## Иерархия типов Scala ##
+## Иерархия типов Scala
[`Any`](https://www.scala-lang.org/api/2.12.1/scala/Any.html) это супертип всех типов, также называемый верхним типом. Он определяет несколько универсальных методов, таких как `equals`, `hashCode` и `toString`. У `Any` есть два прямых подкласса: `AnyVal` и `AnyRef`.
@@ -28,7 +23,10 @@ prerequisite-knowledge: classes, basics
Вот пример, демонстрирующий, что строки, целые числа, символы, логические значения и функции являются объектами, как и любой другой объект:
-```tut
+{% tabs unified-types-1 %}
+{% tab 'Scala 2 и 3' for=unified-types-1 %}
+
+```scala mdoc
val list: List[Any] = List(
"a string",
732, // целое число
@@ -40,6 +38,9 @@ val list: List[Any] = List(
list.foreach(element => println(element))
```
+{% endtab %}
+{% endtabs %}
+
Объявляем переменную `list` типа `List[Any]`. Список инициализируется элементами различных типов, но все они являются экземпляром `scala.Any`, так что вы можете добавить их в список.
Ниже приведен вывод программы:
@@ -53,30 +54,44 @@ true
```
## Приведение типа
+
Числовые типы могут быть приведены следующим образом:
Например:
-```tut
+{% tabs unified-types-2 %}
+{% tab 'Scala 2 и 3' for=unified-types-2 %}
+
+```scala mdoc
val x: Long = 987654321
-val y: Float = x // 9.8765434E8 (заметьте, что некоторая точность теряется в этом случае.)
+val y: Float = x.toFloat // 9.8765434E8 (заметьте, что некоторая точность теряется в этом случае.)
val face: Char = '☺'
val number: Int = face // 9786
```
+{% endtab %}
+{% endtabs %}
+
Приведение типа - однонаправленно. Следующий пример не скомпилируется:
+{% tabs unified-types-3 %}
+{% tab 'Scala 2 и 3' for=unified-types-3 %}
+
```
val x: Long = 987654321
-val y: Float = x // 9.8765434E8
+val y: Float = x.toFloat // 9.8765434E8
val z: Long = y // обратно не подходит
```
+{% endtab %}
+{% endtabs %}
+
Вы также можете приводить к своему подтипу. Об этом мы поговорим позже в ходе нашего обзора.
## Nothing и Null
-`Nothing` является подтипом всех типов, также называемым нижним типом. Нет значения, которое имеет тип `Nothing`. Обычно он используется чтоб дать сигнал о не вычислимости, например брошено исключение, выход из программы, бесконечное зацикливание (т.е. это тип выражения, которое не вычисляется).
+
+`Nothing` является подтипом всех типов, также называемым нижним типом. Нет значения, которое имеет тип `Nothing`. Обычно он используется чтоб дать сигнал о не вычислимости, например брошено исключение, выход из программы, бесконечное зацикливание (т.е. это тип выражения, которое не вычисляется).
`Null` подтип всех ссылочных типов (т.е. любой подтип AnyRef). Он имеет одно значение, определяемое ключевым словом литерала `null`. `Null` предоставляется в основном для функциональной совместимости с другими языками JVM и почти никогда не должен использоваться в коде Scala. Об альтернативах `null` мы поговорим позднее.
diff --git a/_ru/tour/upper-type-bounds.md b/_ru/tour/upper-type-bounds.md
index 7446261c1a..7a9238016e 100644
--- a/_ru/tour/upper-type-bounds.md
+++ b/_ru/tour/upper-type-bounds.md
@@ -1,22 +1,21 @@
---
layout: tour
title: Верхнее Ограничение Типа
-
-discourse: true
-
partof: scala-tour
categories: tour
num: 20
language: ru
next-page: lower-type-bounds
previous-page: variances
-
---
В Scala [параметры типа](generic-classes.html) и [члены абстрактного типа](abstract-type-members.html) могут быть ограничены определенными диапазонами. Такие диапазоны ограничивают конкретные значение типа и, возможно, предоставляют больше информации о членах таких типов. _Верхнее ограничение типа_ `T <: A` указывает на то что тип `T` относится к подтипу типа `A`.
Приведем пример, демонстрирующий верхнее ограничение для типа класса `PetContainer`:
-```tut
+{% tabs upper-type-bounds class=tabs-scala-version %}
+{% tab 'Scala 2' for=upper-type-bounds %}
+
+```scala mdoc
abstract class Animal {
def name: String
}
@@ -43,10 +42,53 @@ val dogContainer = new PetContainer[Dog](new Dog)
val catContainer = new PetContainer[Cat](new Cat)
```
-```tut:fail
+{% endtab %}
+{% tab 'Scala 3' for=upper-type-bounds %}
+
+```scala
+abstract class Animal:
+ def name: String
+
+abstract class Pet extends Animal
+
+class Cat extends Pet:
+ override def name: String = "Cat"
+
+class Dog extends Pet:
+ override def name: String = "Dog"
+
+class Lion extends Animal:
+ override def name: String = "Lion"
+
+class PetContainer[P <: Pet](p: P):
+ def pet: P = p
+
+val dogContainer = PetContainer[Dog](Dog())
+val catContainer = PetContainer[Cat](Cat())
+```
+
+{% endtab %}
+{% endtabs %}
+
+{% tabs upper-type-bounds_error class=tabs-scala-version %}
+{% tab 'Scala 2' for=upper-type-bounds_error %}
+
+```scala mdoc:fail
// это не скомпилируется
val lionContainer = new PetContainer[Lion](new Lion)
```
+
+{% endtab %}
+{% tab 'Scala 3' for=upper-type-bounds_error %}
+
+```scala
+// это не скомпилируется
+val lionContainer = PetContainer[Lion](Lion())
+```
+
+{% endtab %}
+{% endtabs %}
+
Класс `PetContainer` принимает тип `P`, который должен быть подтипом `Pet`. `Dog` и `Cat` - это подтипы `Pet`, поэтому мы можем создать новые `PetContainer[Dog]` и `PetContainer[Cat]`. Однако, если мы попытаемся создать `PetContainer[Lion]`, то получим следующую ошибку:
`type arguments [Lion] do not conform to class PetContainer's type parameter bounds [P <: Pet]`
diff --git a/_ru/tour/variances.md b/_ru/tour/variances.md
index 96e597c635..c122728f51 100644
--- a/_ru/tour/variances.md
+++ b/_ru/tour/variances.md
@@ -1,33 +1,52 @@
---
layout: tour
title: Вариантность
-
-discourse: true
-
partof: scala-tour
-
num: 19
language: ru
next-page: upper-type-bounds
previous-page: generic-classes
-
---
-Вариантность (Variances) - это указание определенной специфики взаимосвязи между связанными типам. Scala поддерживает вариантную аннотацию типов у [обобщенных классов](generic-classes.html), что позволяет им быть ковариантными, контрвариантными или инвариантными (если нет никакого указание на вариантность). Использование вариантности в системе типов позволяет устанавливать понятные взаимосвязи между сложными типами, в то время как отсутствие вариантности может ограничить повторное использование абстракции класса.
+Вариантность (Variances) - это указание определенной специфики взаимосвязи между связанными типами.
+Scala поддерживает вариантную аннотацию типов у [обобщенных классов](generic-classes.html),
+что позволяет им быть ковариантными, контрвариантными или инвариантными (если нет никакого указания на вариантность).
+Использование вариантности в системе типов позволяет устанавливать понятные взаимосвязи между сложными типами,
+в то время как отсутствие вариантности может ограничить повторное использование абстракции класса.
+
+{% tabs variances_1 %}
+{% tab 'Scala 2 и 3' for=variances_1 %}
-```tut
+```scala mdoc
class Foo[+A] // ковариантный класс
-class Bar[-A] // контрвариантный класс
-class Baz[A] // инвариантными класс
+class Bar[-A] // контравариантный класс
+class Baz[A] // инвариантный класс
```
-### Ковариантность
+{% endtab %}
+{% endtabs %}
+
+### Инвариантность
-Параметр типа `A` обобщенного класса можно сделать ковариантным с помощью аннотации `+A`. Для некоторого класса `List[+A]`, указание `A` в виде коварианта подразумевает, что для двух типов `A` и `B`, где `A` является подтипом `B`, `List[A]` представляет собой подтип `List[B]`. Что позволяет нам создавать очень полезные и интуитивно понятные взаимоотношения между типами с использованием обобщений (generics).
+По умолчанию параметры типа в Scala инвариантны: отношения подтипа между параметрами типа не отражаются в параметризованном типе.
+Чтобы понять, почему это работает именно так, рассмотрим простой параметризованный тип, изменяемый контейнер.
-Рассмотрим простую структуру классов:
+{% tabs invariance_1 %}
+{% tab 'Scala 2 и 3' for=invariance_1 %}
-```tut
+```scala mdoc
+class Box[A](var content: A)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Мы собираемся поместить в него значения типа `Animal` (животное). Этот тип определяется следующим образом:
+
+{% tabs invariance_2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=invariance_2 %}
+
+```scala mdoc
abstract class Animal {
def name: String
}
@@ -35,120 +54,241 @@ case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal
```
-И `Cat` (кошка) и `Dog`(собака) являются подтипами `Animal`(животное). Стандартная библиотека Scala имеет обобщенный неизменяемый тип `List[+A]`, где параметр типа `A` является ковариантным. Это означает, что `List[Cat]` - это `List[Animal]`, а `List[Dog]` - это также `List[Animal]`. Интуитивно понятно, что список кошек и список собак - это список животных и вы должны быть в состоянии заменить любого из них на `List[Animal]`.
+{% endtab %}
+{% tab 'Scala 3' for=invariance_2 %}
-В следующем примере метод `printAnimalNames` принимает в качестве аргумента список животных и выводит их имена в новой строке. Если бы `List[A]` не был ковариантным, последние два вызова метода не компилировались бы, что сильно ограничило бы полезность метода `printAnimalNames`.
+```scala
+abstract class Animal:
+ def name: String
-```tut
-object CovarianceTest extends App {
- def printAnimalNames(animals: List[Animal]): Unit = {
- animals.foreach { animal =>
- println(animal.name)
- }
- }
+case class Cat(name: String) extends Animal
+case class Dog(name: String) extends Animal
+```
- val cats: List[Cat] = List(Cat("Whiskers"), Cat("Tom"))
- val dogs: List[Dog] = List(Dog("Fido"), Dog("Rex"))
+{% endtab %}
+{% endtabs %}
- printAnimalNames(cats)
- // Whiskers
- // Tom
+Можно сказать, что `Cat` (кот) - это подтип `Animal`, `Dog` (собака) - также подтип `Animal`.
+Это означает, что следующее допустимо и пройдет проверку типов:
- printAnimalNames(dogs)
- // Fido
- // Rex
-}
+{% tabs invariance_3 %}
+{% tab 'Scala 2 и 3' for=invariance_3 %}
+
+```scala mdoc
+val myAnimal: Animal = Cat("Felix")
```
-### Контрвариантность
+{% endtab %}
+{% endtabs %}
-Параметр типа `A` обобщенного класса можно сделать контрвариантным с помощью аннотации `-A`. Это создает схожее, но противоположное ковариантным, взаимоотношения между типом параметра и подтипами класса. То есть, для некого класса `Writer[-A]`, указание `A` контрвариантным подразумевает, что для двух типов `A` и `B` где `A` является подтипом `B`, `Writer[B]` является подтипом `Writer[A]`.
+А контейнеры?
+Является ли `Box[Cat]` подтипом `Box[Animal]`, как `Cat` подтип `Animal`?
+На первый взгляд может показаться, что это правдоподобно,
+но если мы попытаемся это сделать, компилятор сообщит об ошибке:
-Рассмотрим классы `Cat`, `Dog`, и `Animal`, описанные выше для следующего примера:
+{% tabs invariance_4 class=tabs-scala-version %}
+{% tab 'Scala 2' for=invariance_4 %}
-```tut
-abstract class Printer[-A] {
- def print(value: A): Unit
-}
+```scala mdoc:fail
+val myCatBox: Box[Cat] = new Box[Cat](Cat("Felix"))
+val myAnimalBox: Box[Animal] = myCatBox // не компилируется
+val myAnimal: Animal = myAnimalBox.content
```
-`Printer[A]` - это простой класс, который знает, как распечатать некоторый тип `A`. Давайте определим подклассы для конкретных типов:
-
-```tut
-class AnimalPrinter extends Printer[Animal] {
- def print(animal: Animal): Unit =
- println("The animal's name is: " + animal.name)
-}
+{% endtab %}
+{% tab 'Scala 3' for=invariance_4 %}
-class CatPrinter extends Printer[Cat] {
- def print(cat: Cat): Unit =
- println("The cat's name is: " + cat.name)
-}
+```scala
+val myCatBox: Box[Cat] = Box[Cat](Cat("Felix"))
+val myAnimalBox: Box[Animal] = myCatBox // не компилируется
+val myAnimal: Animal = myAnimalBox.content
```
-Если `Printer[Cat]` знает, как распечатать любой класс `Cat` в консоли, а `Printer[Animal]` знает, как распечатать любое `Animal` в консоли, то разумно если `Printer[Animal]` также знает, как распечатать любое `Cat`. Обратного отношения нет, потому что `Printer[Cat]` не знает, как распечатать любой `Animal` в консоли. Чтоб иметь возможность заменить `Printer[Cat]` на `Printer[Animal]`, необходимо `Printer[A]` сделать контрвариантным.
+{% endtab %}
+{% endtabs %}
-```tut
-object ContravarianceTest extends App {
- val myCat: Cat = Cat("Boots")
+Почему это может быть проблемой?
+Мы можем достать из контейнера кота, и это все еще животное, не так ли? Ну да.
+Но это не все, что мы можем сделать. Мы также можем заменить в контейнере кота другим животным.
- def printMyCat(printer: Printer[Cat]): Unit = {
- printer.print(myCat)
- }
+{% tabs invariance_5 %}
+{% tab 'Scala 2 и 3' for=invariance_5 %}
+
+```scala
+ myAnimalBox.content = Dog("Fido")
+```
- val catPrinter: Printer[Cat] = new CatPrinter
- val animalPrinter: Printer[Animal] = new AnimalPrinter
+{% endtab %}
+{% endtabs %}
- printMyCat(catPrinter)
- printMyCat(animalPrinter)
-}
+Теперь в контейнере для животных есть собака.
+Все в порядке, вы можете поместить собак в контейнеры для животных, потому что собаки — это животные.
+Но наш контейнер для животных — это контейнер для котов! Нельзя поместить собаку в контейнер с котом.
+Если бы мы могли, а затем попытались достать кота из нашего кошачьего контейнера,
+он оказался бы собакой, нарушающей целостность типа.
+
+{% tabs invariance_6 %}
+{% tab 'Scala 2 и 3' for=invariance_6 %}
+
+```scala
+ val myCat: Cat = myCatBox.content // myCat стал бы собакой Fido!
```
-Результатом работы этой программы будет:
+{% endtab %}
+{% endtabs %}
+Из этого мы должны сделать вывод, что между `Box[Cat]` и `Box[Animal]` не может быть отношения подтипа,
+хотя между `Cat` и `Animal` это отношение есть.
+
+### Ковариантность
+
+Проблема, с которой мы столкнулись выше, заключается в том,
+что, поскольку мы можем поместить собаку в контейнер для животных,
+контейнер для кошек не может быть контейнером для животных.
+
+Но что, если мы не сможем поместить собаку в контейнер?
+Тогда мы бы могли просто вернуть нашего кота, и это не проблема, чтобы можно было следовать отношениям подтипа.
+Оказывается, это действительно то, что мы можем сделать.
+
+{% tabs covariance_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=covariance_1 %}
+
+```scala mdoc
+class ImmutableBox[+A](val content: A)
+val catbox: ImmutableBox[Cat] = new ImmutableBox[Cat](Cat("Felix"))
+val animalBox: ImmutableBox[Animal] = catbox // теперь код компилируется
```
-The cat's name is: Boots
-The animal's name is: Boots
+
+{% endtab %}
+{% tab 'Scala 3' for=covariance_1 %}
+
+```scala
+class ImmutableBox[+A](val content: A)
+val catbox: ImmutableBox[Cat] = ImmutableBox[Cat](Cat("Felix"))
+val animalBox: ImmutableBox[Animal] = catbox // теперь код компилируется
```
-### Инвариантность
+{% endtab %}
+{% endtabs %}
+
+Мы говорим, что `ImmutableBox` _ковариантен_ в `A` - на это указывает `+` перед `A`.
-Обобщенные классы в Scala по умолчанию являются инвариантными. Это означает, что они не являются ни ковариантными, ни контрвариантными друг другу. В контексте следующего примера класс `Container` является инвариантным. Между `Container[Cat]` и `Container[Animal]`, нет ни прямой, ни обратной взаимосвязи.
+Более формально это дает нам следующее отношение:
+если задано некоторое `class Cov[+T]`, то если `A` является подтипом `B`, то `Cov[A]` является подтипом `Cov[B]`.
+Это позволяет создавать очень полезные и интуитивно понятные отношения подтипов с помощью обобщения.
-```tut
-class Container[A](value: A) {
- private var _value: A = value
- def getValue: A = _value
- def setValue(value: A): Unit = {
- _value = value
+В следующем менее надуманном примере метод `printAnimalNames` принимает список животных в качестве аргумента
+и печатает их имена с новой строки.
+Если бы `List[A]` не был бы ковариантным, последние два вызова метода не компилировались бы,
+что сильно ограничивало бы полезность метода `printAnimalNames`.
+
+{% tabs covariance_2 %}
+{% tab 'Scala 2 и 3' for=covariance_2 %}
+
+```scala mdoc
+def printAnimalNames(animals: List[Animal]): Unit =
+ animals.foreach {
+ animal => println(animal.name)
}
-}
+
+val cats: List[Cat] = List(Cat("Whiskers"), Cat("Tom"))
+val dogs: List[Dog] = List(Dog("Fido"), Dog("Rex"))
+
+// печатает: "Whiskers", "Tom"
+printAnimalNames(cats)
+
+// печатает: "Fido", "Rex"
+printAnimalNames(dogs)
```
-Может показаться что `Container[Cat]` должен также являться и `Container[Animal]`, но позволить мутабельному обобщенному классу быть ковариантным было бы небезопасно. В данном примере очень важно, чтобы `Container` был инвариантным. Предположим, что `Container` на самом деле был ковариантным, что-то вроде этого могло случиться:
+{% endtab %}
+{% endtabs %}
+
+### Контрвариантность
+
+Мы видели, что можем достичь ковариантности, убедившись, что не сможем поместить что-то в ковариантный тип, а только что-то получить.
+Что, если бы у нас было наоборот, что-то, что можно положить, но нельзя вынуть?
+Такая ситуация возникает, если у нас есть что-то вроде сериализатора, который принимает значения типа `A`
+и преобразует их в сериализованный формат.
+
+{% tabs contravariance_1 class=tabs-scala-version %}
+{% tab 'Scala 2' for=contravariance_1 %}
+
+```scala mdoc
+abstract class Serializer[-A] {
+ def serialize(a: A): String
+}
+val animalSerializer: Serializer[Animal] = new Serializer[Animal] {
+ def serialize(animal: Animal): String = s"""{ "name": "${animal.name}" }"""
+}
+val catSerializer: Serializer[Cat] = animalSerializer
+catSerializer.serialize(Cat("Felix"))
```
-val catContainer: Container[Cat] = new Container(Cat("Felix"))
-val animalContainer: Container[Animal] = catContainer
-animalContainer.setValue(Dog("Spot"))
-val cat: Cat = catContainer.getValue // Ой, мы бы закончили присвоением собаки к коту.
+
+{% endtab %}
+{% tab 'Scala 3' for=contravariance_1 %}
+
+```scala
+abstract class Serializer[-A]:
+ def serialize(a: A): String
+
+val animalSerializer: Serializer[Animal] = Serializer[Animal]():
+ def serialize(animal: Animal): String = s"""{ "name": "${animal.name}" }"""
+
+val catSerializer: Serializer[Cat] = animalSerializer
+catSerializer.serialize(Cat("Felix"))
```
-К счастью, компилятор остановит нас прежде, чем мы зайдем так далеко.
+{% endtab %}
+{% endtabs %}
+
+Мы говорим, что `Serializer` _контравариантен_ в `A`, и на это указывает `-` перед `A`.
+Более общий сериализатор является подтипом более конкретного сериализатора.
+
+Более формально это дает нам обратное отношение: если задано некоторое `class Contra[-T]`,
+то если `A` является подтипом `B`, `Contra[B]` является подтипом `Contra[A]`.
+
+### Неизменность и вариантность
-### Другие Примеры
+Неизменяемость является важной частью проектного решения, связанного с использованием вариантности.
+Например, коллекции Scala систематически различают [изменяемые и неизменяемые коллекции](https://docs.scala-lang.org/ru/overviews/collections-2.13/overview.html).
+Основная проблема заключается в том, что ковариантная изменяемая коллекция может нарушить безопасность типов.
+Вот почему `List` - ковариантная коллекция, а `scala.collection.mutable.ListBuffer` - инвариантная коллекция.
+`List` - это коллекция в `package scala.collection.immutable`, поэтому она гарантированно будет неизменяемой для всех.
+Принимая во внимание, что `ListBuffer` изменяем, то есть вы можете обновлять, добавлять или удалять элементы `ListBuffer`.
-Другим примером, который может помочь понять вариантность, является трейт `Function1[-T, +R]` из стандартной библиотеки Scala. `Function1` представляет собой функцию с одним параметром, где первый тип `T` представляет собой тип параметра, а второй тип `R` представляет собой тип результата. Функция `Function1` является контрвариантной в рамках типа принимаемого аргумента, а ковариантной - в рамках возвращаемого типа. Для этого примера мы будем использовать явное обозначение типа `A =>B` чтоб продемонстрировать `Function1[A, B]`.
+Чтобы проиллюстрировать проблему ковариантности и изменчивости, предположим,
+что `ListBuffer` ковариантен, тогда следующий проблемный пример скомпилируется (на самом деле он не компилируется):
-Рассмотрим схожий пример `Cat`, `Dog`, `Animal` в той же взаимосвязи что и раньше, плюс следующее:
+{% tabs immutability_and_variance_2 %}
+{% tab 'Scala 2 и 3' %}
-```tut
-abstract class SmallAnimal extends Animal
-case class Mouse(name: String) extends SmallAnimal
+```scala mdoc:fail
+import scala.collection.mutable.ListBuffer
+
+val bufInt: ListBuffer[Int] = ListBuffer[Int](1,2,3)
+val bufAny: ListBuffer[Any] = bufInt
+bufAny(0) = "Hello"
+val firstElem: Int = bufInt(0)
```
-Предположим, мы работаем с функциями, которые принимают типы животных и возвращают типы еды, которую они едят. Если мы хотим `Cat => SmallAnimal` (потому что кошки едят маленьких животных), но вместо этого мы получим функцию `Animal => Mouse`, то наша программа все равно будет работать. Интуитивно функция `Animal => Mouse` все равно будет принимать `Cat` в качестве аргумента, тк `Cat` является `Animal`, и возвращать `Mouse` - который также является и `SmallAnimal`. Поскольку мы можем безопасно заменить первое вторым, можно сказать, что `Animal => Mouse` аналогично `Cat => SmallAnimal`.
+{% endtab %}
+{% endtabs %}
+
+Если бы приведенный выше код был бы возможен, то вычисление `firstElem` завершилась бы ошибкой с `ClassCastException`,
+потому что `bufInt(0)` теперь содержит `String`, а не `Int`.
+
+Инвариантность `ListBuffer` означает, что `ListBuffer[Int]` не является подтипом `ListBuffer[Any]`,
+несмотря на то, что `Int` является подтипом `Any`,
+и поэтому `bufInt` не может быть присвоен в качестве значения `bufAny`.
### Сравнение с другими языками
-В языках, похожих на Scala, разные способы поддержи вариантности. Например, указания вариантности в Scala очень похожи на то, как это делается в C#, где такие указания добавляются при объявлении абстракции класса (вариантность при объявлении). Однако в Java, указание вариантности задается непосредственно при использовании абстракции класса (вариантность при использовании).
+В языках, похожих на Scala, разные способы поддержки вариантности.
+Например, указания вариантности в Scala очень похожи на то, как это делается в C#,
+где такие указания добавляются при объявлении абстракции класса (вариантность при объявлении).
+Однако в Java, указание вариантности задается непосредственно при использовании абстракции класса (вариантность при использовании).
+
+Тенденция Scala к неизменяемым типам делает ковариантные и контравариантные типы более распространенными,
+чем в других языках, поскольку изменяемый универсальный тип должен быть инвариантным.
diff --git a/_sass/base/helper.scss b/_sass/base/helper.scss
index 1b32d31165..8b6f9c46d2 100755
--- a/_sass/base/helper.scss
+++ b/_sass/base/helper.scss
@@ -3,12 +3,50 @@
//------------------------------------------------
.wrap {
- @include outer-container;
- @include padding(0 20px);
+ @include outer-container;
+ @include padding(0 20px);
+}
+
+.place-inline {
+ // add vertical margin
+ @include outer-container;
+ @include margin(20px 0);
+}
+
+.inline-sticky-top {
+ position: sticky;
+ top: 15px;
+ margin-bottom: 25px;
+ background: #fff;
+ -webkit-box-shadow: 0 0 18px 20px #fff;
+ -moz-box-shadow: 0 0 18px 20px #fff;
+ box-shadow: 0 0 18px 20px #fff;
+ z-index: 5;
+}
+
+.inline-sticky-top.inline-sticky-top-higher {
+ z-index: 7;
+}
+
+.wrap-inline {
+ // add vertical padding
+ @include outer-container;
+ @include padding(20px 0);
+}
+
+.wrap-tab {
+ @extend .wrap-narrow;
+ margin-top: 20px;
+ margin-bottom: 20px;
+}
+
+.wrap-narrow {
+ @include outer-container;
+ @include padding(0 10px);
}
.dot {
- font-size: 10px;
- color: rgba($base-font-color-light, 0.6);
- margin: 0 3px;
+ font-size: 10px;
+ color: rgba($base-font-color-light, 0.6);
+ margin: 0 3px;
}
diff --git a/_sass/components/alt-details.scss b/_sass/components/alt-details.scss
new file mode 100644
index 0000000000..c86febae5d
--- /dev/null
+++ b/_sass/components/alt-details.scss
@@ -0,0 +1,83 @@
+// ALT-DETAILS
+//------------------------------------------------
+//------------------------------------------------
+
+.alt-details.help-info {
+ .alt-details-toggle {
+ background-color: $brand-primary;
+ color: white;
+
+ &:hover {
+ background-color: darken($brand-primary, 15%);
+ }
+ }
+
+ .alt-details-detail {
+ background: #fae6e6
+ }
+}
+
+.alt-details {
+ @include span-columns(12);
+
+ .alt-details-toggle {
+ @include span-columns(12);
+ font-family: $base-font-family;
+ line-height: normal;
+ text-align: center;
+ border: none;
+ background-color: $brand-tertiary;
+ padding: 5px 10px;
+ border-radius: $border-radius-large;
+ font-size: $font-size-medium;
+ cursor: pointer;
+ font-weight: 500;
+ color: $gray-dark;
+
+ &:hover {
+ background-color: darken($brand-tertiary, 15%);
+ }
+
+ &:after {
+ // show a right arrow at the end of the toggle element
+ content: "\f138"; //
+ font-family: "Font Awesome 5 Free";
+ font-weight: 900;
+ font-size: 15px;
+ float: right;
+ margin-top: 2px;
+ }
+
+ }
+
+ .alt-details-control {
+ margin: 0;
+ }
+
+ .alt-details-control+.alt-details-toggle+.alt-details-detail {
+ // by default, hide the details
+ position: absolute;
+ top: -999em;
+ left: -999em;
+ }
+
+ .alt-details-control:checked+.alt-details-toggle+.alt-details-detail {
+ // show the details when the control is checked
+ position: static;
+ }
+
+ .alt-details-control:checked+.alt-details-toggle:after {
+ // change the marker on the toggle label to a down arrow
+ content: "\f13a"; //
+ }
+
+ .alt-details-detail {
+ // The detail box appears to be underneath the toggle button
+ // so we add a padding to the top and push it up.
+ border-bottom: $base-border-gray;
+ border-left: $base-border-gray;
+ border-right: $base-border-gray;
+ padding-top: 15px;
+ margin-top: 15px;
+ }
+}
diff --git a/_sass/components/code.scss b/_sass/components/code.scss
index e771eb6ad1..15e8c641e3 100755
--- a/_sass/components/code.scss
+++ b/_sass/components/code.scss
@@ -23,3 +23,45 @@
}
}
+
+.code-snippet-area {
+ width: 100%;
+ margin-top: 1em;
+ margin-bottom: 1em;
+ position: relative; // so we can position the buttons
+
+ &:hover {
+
+ // display the copy buttons on hover of the whole area
+ .code-snippet-buttons {
+ opacity: 0.95;
+
+ &:active {
+ transition: none;
+ opacity: 0.7;
+ }
+ }
+ }
+
+ .code-snippet-buttons {
+ opacity: 0; // default invisible until hover
+ transition: $base-transition;
+ position: absolute; // so we can position the buttons
+ right: 3px;
+ top: 5px;
+
+ button {
+ border: none;
+ background: #fff;
+ font-size: $font-size-medium;
+ color: $gray-darker;
+ cursor: pointer;
+ }
+ }
+
+ .code-snippet-display {
+ margin-top: 0px;
+ margin-bottom: 0px;
+ width: 100%;
+ }
+}
diff --git a/_sass/components/dropdown.scss b/_sass/components/dropdown.scss
index 6cf33e73ca..b656233a34 100644
--- a/_sass/components/dropdown.scss
+++ b/_sass/components/dropdown.scss
@@ -2,6 +2,8 @@
//------------------------------------------------
//------------------------------------------------
+$border-1-grey: 1px solid rgba(128, 128, 128, 0.5);
+
.language-dropdown {
position: relative;
margin-top: 50px;
@@ -17,6 +19,7 @@
// width: 100%;
// }
float: right;
+ padding-right: 6px; // leave space for the search bar
.table-of-content & {
margin-top: 0;
@@ -31,8 +34,13 @@
box-sizing: border-box;
.table-of-content & {
- border: 1px solid rgba(128, 128, 128, 0.5);
+ border: $border-1-grey;
+ }
+
+ .full-width & {
+ border: $border-1-grey;
}
+
.table-of-content &:focus {
}
diff --git a/_sass/components/heading-anchor.scss b/_sass/components/heading-anchor.scss
new file mode 100644
index 0000000000..a38b6d96bf
--- /dev/null
+++ b/_sass/components/heading-anchor.scss
@@ -0,0 +1,12 @@
+// HEADING ANCHOR
+//------------------------------------------------
+//------------------------------------------------
+
+.heading-anchor {
+ visibility: hidden;
+ padding-left: 0.5em;
+
+ &:hover {
+ text-decoration: none;
+ }
+}
diff --git a/_sass/components/search.scss b/_sass/components/search.scss
index de18915531..5a25704964 100755
--- a/_sass/components/search.scss
+++ b/_sass/components/search.scss
@@ -2,6 +2,19 @@
//------------------------------------------------
//------------------------------------------------
+// Override the styles below to style the search container
+// when it is shown on a specific page (as opposed to the
+// landing page)
+.titles + .search-container {
+ @include span-columns(3);
+ @include bp(medium) {
+ display: none;
+ }
+ float: right;
+ margin-top: 50px;
+ margin-right: 0;
+}
+
.search-container {
position: relative;
margin-top: 20px;
diff --git a/_sass/components/tab.scss b/_sass/components/tab.scss
index b5a9bb89c3..8207f3eb52 100755
--- a/_sass/components/tab.scss
+++ b/_sass/components/tab.scss
@@ -2,15 +2,21 @@
//------------------------------------------------
//------------------------------------------------
+// dynamic tab switching based on https: //levelup.gitconnected.com/tabbed-interfaces-without-javascript-661bab1eaec8
+
.nav-tab {
border-bottom: $base-border-gray;
@include display(flex);
@include align-items(center);
@include justify-content(flex-start);
- margin-bottom: 10px;
+ overflow-x: auto; // scrollbar when width is too small.
+ overflow-y: hidden;
.item-tab {
+
+ label,
a {
+ transition: none; // do not animate the transition to active
color: $base-font-color-light;
display: block;
padding: 0 20px 10px;
@@ -23,21 +29,107 @@
color: $base-font-color;
}
- &.active {
- border-bottom: 2px solid $brand-primary;
- color: $brand-primary;
- pointer-events: none;
+ &:hover {
+ cursor: pointer;
}
}
+ label {
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ }
+
}
+
@include bp(small) {
@include justify-content(space-between);
+
.item-tab {
- a {
- padding: 0 10px 10px;
- font-size: $font-size-medium;
+ label,
+ a {
+ transition: none; // do not animate the transition to active
+ padding: 0 10px 10px;
+ font-size: $font-size-medium;
+ }
}
+ }
+}
+
+/* Active Tabs for standard screen size */
+.nav-tab>.item-tab>a.active, // used in the blog
+.tabsection>input:nth-child(1):checked~.nav-tab .item-tab:nth-child(1) label,
+.tabsection>input:nth-child(2):checked~.nav-tab .item-tab:nth-child(2) label,
+.tabsection>input:nth-child(3):checked~.nav-tab .item-tab:nth-child(3) label,
+.tabsection>input:nth-child(4):checked~.nav-tab .item-tab:nth-child(4) label,
+.tabsection>input:nth-child(5):checked~.nav-tab .item-tab:nth-child(5) label,
+.tabsection>input:nth-child(6):checked~.nav-tab .item-tab:nth-child(6) label,
+.tabsection>input:nth-child(7):checked~.nav-tab .item-tab:nth-child(7) label,
+.tabsection>input:nth-child(8):checked~.nav-tab .item-tab:nth-child(8) label,
+.tabsection>input:nth-child(9):checked~.nav-tab .item-tab:nth-child(9) label {
+ border-bottom: 2px solid $brand-primary;
+ padding: 0 20px 8px; // so text does not jump up when active
+ color: $brand-primary;
+ pointer-events: none;
+}
+
+/* Active Tabs for small screen size */
+@include bp(small) {
+ .nav-tab>.item-tab>a.active,
+ .tabsection>input:nth-child(1):checked~.nav-tab .item-tab:nth-child(1) label,
+ .tabsection>input:nth-child(2):checked~.nav-tab .item-tab:nth-child(2) label,
+ .tabsection>input:nth-child(3):checked~.nav-tab .item-tab:nth-child(3) label,
+ .tabsection>input:nth-child(4):checked~.nav-tab .item-tab:nth-child(4) label,
+ .tabsection>input:nth-child(5):checked~.nav-tab .item-tab:nth-child(5) label,
+ .tabsection>input:nth-child(6):checked~.nav-tab .item-tab:nth-child(6) label,
+ .tabsection>input:nth-child(7):checked~.nav-tab .item-tab:nth-child(7) label,
+ .tabsection>input:nth-child(8):checked~.nav-tab .item-tab:nth-child(8) label,
+ .tabsection>input:nth-child(9):checked~.nav-tab .item-tab:nth-child(9) label {
+ padding: 0 10px 8px; // match narrower padding for inactive tabs
+ }
+}
+
+.tabsection {
+ padding: 0.1px 0; // ensure inner content is correctly padded
+ border-left: 2px solid $base-border-color-gray;
+
+ .nav-tab {
+ padding-left: 0;
+ margin-bottom: 0;
+
+ .item-tab {
+ padding: 0;
+ margin-bottom: 0;
+ list-style: none;
}
}
+
+ input { // hide the input because they are not interactive
+ display: block; /* "enable" hidden elements in IE/edge */
+ position: absolute; /* then hide them off-screen */
+ left: -100%;
+ }
+
+ .tabcontent {
+ section { // by default, hide all sections until the user clicks on the associated label
+ position: absolute;
+ top: -999em;
+ left: -999em;
+ }
+ }
+}
+
+.tabsection>input:nth-child(1):checked~.tabcontent section:nth-child(1),
+.tabsection>input:nth-child(2):checked~.tabcontent section:nth-child(2),
+.tabsection>input:nth-child(3):checked~.tabcontent section:nth-child(3),
+.tabsection>input:nth-child(4):checked~.tabcontent section:nth-child(4),
+.tabsection>input:nth-child(5):checked~.tabcontent section:nth-child(5),
+.tabsection>input:nth-child(6):checked~.tabcontent section:nth-child(6),
+.tabsection>input:nth-child(7):checked~.tabcontent section:nth-child(7),
+.tabsection>input:nth-child(8):checked~.tabcontent section:nth-child(8),
+.tabsection>input:nth-child(9):checked~.tabcontent section:nth-child(9) {
+ position: static;
}
diff --git a/_sass/components/wip-notice.scss b/_sass/components/wip-notice.scss
new file mode 100644
index 0000000000..3c84c75ac0
--- /dev/null
+++ b/_sass/components/wip-notice.scss
@@ -0,0 +1,12 @@
+.wip-notice {
+ position: relative;
+ top: 1em;
+ padding: 1em;
+ border-radius: 5px;
+ background: $gray-light;
+
+ a {
+ color: $brand-primary;
+ font-weight: 700;
+ }
+}
diff --git a/_sass/layout/details-summary.scss b/_sass/layout/details-summary.scss
new file mode 100644
index 0000000000..1f18d4cd64
--- /dev/null
+++ b/_sass/layout/details-summary.scss
@@ -0,0 +1,3 @@
+details > summary > p {
+ display: inline;
+}
diff --git a/_sass/layout/doc-navigation.scss b/_sass/layout/doc-navigation.scss
index 1d11f17010..7539881c3f 100644
--- a/_sass/layout/doc-navigation.scss
+++ b/_sass/layout/doc-navigation.scss
@@ -4,6 +4,7 @@
$nav-height: 46px;
+
.doc-navigation {
padding: 10px 20px;
@include display(flex);
@@ -18,6 +19,23 @@ $nav-height: 46px;
display: none;
}
}
+ .doc-language-version {
+ font-size: 1.6em;
+ font-family: $heading-font-family;
+ font-weight: bold;
+ color: rgb(134,161,166);
+ @include bp(large) {
+ display: none;
+ }
+ }
+ a,
+ a:hover,
+ a:active,
+ a:focus,
+ a:hover,
+ a.active {
+ text-decoration: none;
+ }
}
.navigation-ellipsis {
display: none;
@@ -47,7 +65,7 @@ $nav-height: 46px;
position: absolute;
margin-top: 10px;
display: none;
- z-index: 1;
+ z-index: 40;
box-shadow: 0 3px 12px rgba(0, 0, 0, 0.15);
@include bp(medium) {
diff --git a/_sass/layout/documentation.scss b/_sass/layout/documentation.scss
index f1a16f69d5..c4e56bd3d4 100644
--- a/_sass/layout/documentation.scss
+++ b/_sass/layout/documentation.scss
@@ -9,7 +9,7 @@
.content-title-documentation {
.titles {
- @include span-columns(9);
+ @include span-columns(6);
@include bp(medium) {
@include span-columns(12);
}
@@ -17,15 +17,17 @@
max-height: 160px;
margin-top: 30px;
margin-bottom: 100px;
- @include bp(medium) {
- margin-bottom: 0;
- }
+ // this causes issues on mobile with the header being hidden behind
+ // the contents:
+ // @include bp(medium) {
+ // margin-bottom: 0;
+ //}
.supertitle {
text-transform: uppercase;
font-weight: $font-black;
font-size: 20px;
- color: darken(#53b6d3, 15%);
+ color: rgba(0, 0, 0, 0.2);
}
h1 {
@@ -42,6 +44,10 @@
.content-primary.documentation {
line-height: 1.3;
+ p {
+ line-height: 1.5;
+ }
+
ol {
margin-bottom: 18px;
}
@@ -56,6 +62,38 @@
font-weight: $font-bold;
padding: 1px 5px;
}
+
+ .tag-inline {
+ float: none;
+ }
+
+ h1,
+ h3,
+ h4,
+ h5,
+ h6 {
+ .heading-anchor {
+ color: $base-font-color;
+ }
+
+ &:hover {
+ .heading-anchor {
+ visibility: visible;
+ }
+ }
+ }
+
+ h2 {
+ .heading-anchor {
+ color: $brand-tertiary;
+ }
+
+ &:hover {
+ .heading-anchor {
+ visibility: visible;
+ }
+ }
+ }
}
a.new-version-notice {
diff --git a/_sass/layout/footer.scss b/_sass/layout/footer.scss
index d21eb9e50e..e6f690fd4e 100755
--- a/_sass/layout/footer.scss
+++ b/_sass/layout/footer.scss
@@ -84,7 +84,7 @@
text-align: center;
z-index: 2;
color: #f0f3f3;
- background-color: #dc322f;
+ background-color: $brand-primary;
border-radius: 50%;
display: none;
diff --git a/_sass/layout/glossary.scss b/_sass/layout/glossary.scss
index e55ef1c9aa..8346ea1b40 100644
--- a/_sass/layout/glossary.scss
+++ b/_sass/layout/glossary.scss
@@ -55,7 +55,7 @@
}
li {
- h4 {
+ h3 {
text-transform: none;
margin-bottom: 2px;
font-weight: $font-black;
diff --git a/_sass/layout/header.scss b/_sass/layout/header.scss
index ab392dfd77..ff1b4fdb70 100755
--- a/_sass/layout/header.scss
+++ b/_sass/layout/header.scss
@@ -18,6 +18,23 @@
padding: 10px 40px;
}
+ &.alert-warning {
+ background: $warning-bg;
+ color: $warning-text;
+
+ a {
+ color: $warning-link;
+ font-weight: bold;
+ text-decoration: underline;
+
+ &:active,
+ &:focus,
+ &:hover {
+ text-decoration: none;
+ }
+ }
+ }
+
span {
position: absolute;
right: 20px;
diff --git a/_sass/layout/inner-main.scss b/_sass/layout/inner-main.scss
index 6233be6fdb..64074851c8 100755
--- a/_sass/layout/inner-main.scss
+++ b/_sass/layout/inner-main.scss
@@ -2,17 +2,21 @@
//------------------------------------------------
//------------------------------------------------
+#inner-main>section:nth-child(2) {
+ // corresponds to area with the content below the title
+ position: relative;
+ top: -80px; // have it overlap with the title area
+}
+
#inner-main {
background: $gray-lighter;
padding-bottom: $padding-xlarge;
-
- section:nth-child(2) {
- position: relative;
- top: -80px;
- }
-
.inner-box {
+ margin-bottom: 30px;
+ &:last-child {
+ margin-bottom: 0;
+ }
padding: $padding-medium;
background: #fff;
@include border-radius($border-radius-base);
@@ -43,6 +47,10 @@
order: 1;
margin-bottom: 30px;
}
+
+ @include bp(medium) {
+ order: 3; // move TOC to the bottom on mobile
+ }
}
.content-nav-blog {
@@ -77,13 +85,6 @@
&:nth-child(2n) {
clear: none;
}
-
- &:active,
- &:focus,
- &:hover {
- text-decoration: none;
- background: none;
- }
}
}
}
diff --git a/_sass/layout/online-courses.scss b/_sass/layout/online-courses.scss
new file mode 100644
index 0000000000..e9410fcf02
--- /dev/null
+++ b/_sass/layout/online-courses.scss
@@ -0,0 +1,45 @@
+.online-courses {
+ margin-bottom: 30px;
+}
+
+.online-courses-wrapper {
+ @include clearfix;
+}
+
+.online-courses-image {
+ @include span-columns(5);
+ @include bp(medium) {
+ @include span-columns(12);
+ }
+
+ img {
+ margin-bottom: 0;
+ }
+}
+
+.online-courses-content {
+ @include span-columns(7);
+ @include bp(medium) {
+ @include span-columns(12);
+ }
+
+ h2 {
+ margin-top: 16px;
+ margin-bottom: 16px;
+ }
+
+ blockquote,
+ p,
+ pre,
+ table,
+ ul {
+ margin-bottom: 8px;
+ }
+
+ ol,
+ ul {
+ li {
+ margin-bottom: 4px;
+ }
+ }
+}
diff --git a/_sass/layout/sips.scss b/_sass/layout/sips.scss
index 631c07762c..7fa2d5114e 100644
--- a/_sass/layout/sips.scss
+++ b/_sass/layout/sips.scss
@@ -103,41 +103,29 @@
.sips {
- .pending,
- .completed,
- .dormant,
- .rejected {
- .date {
- display: block;
- font-size: $font-size-small;
- text-transform: uppercase;
- font-weight: $font-bold;
- color: $base-font-color-light;
- margin-top: 4px;
- }
+ .sip-list {
strong {
font-weight: $font-black;
+ display: block;
+ }
+
+ .no-fragmentation {
+ break-inside: avoid;
}
.tag {
float: left;
- position: relative;
display: block;
- top: 3px;
color: #fff;
text-transform: uppercase;
font-size: 11px;
font-weight: 700;
padding: 1px 5px;
+ margin-left: 1px;
+ margin-top: 1px;
}
- }
- .pending {
- display: flex;
- // flex-direction: column;
- // flex-wrap: wrap;
- // max-height: 400px;
ul {
list-style: inside disc;
-webkit-column-count: 2; /* Chrome, Safari, Opera */
@@ -163,41 +151,4 @@
}
}
- .other-sips {
- @include display(flex);
- @include flex-direction(row);
- @include flex-wrap(wrap);
- @include justify-content(space-between);
-
- .completed,
- .dormant,
- .rejected {
- display: flex;
- flex-direction: column;
- // justify-content: flex-end;
- position: relative;
- flex: 0 1 calc(50% - 1em);
-
- @include bp(medium) {
- flex: 0 1 calc(100% - 0.5em);
- }
-
- ul {
- // padding-left: 0px;
-
- li {
- // margin-left: 1em;
- padding-bottom: 24px;
- line-height: 1;
- }
-
- a {
- color: $gray-darker;
- &:hover {
- color: $brand-primary;
- }
- }
- }
- }
- }
}
diff --git a/_sass/layout/table-of-content.scss b/_sass/layout/table-of-content.scss
index 5dca9f7945..e846256f73 100755
--- a/_sass/layout/table-of-content.scss
+++ b/_sass/layout/table-of-content.scss
@@ -65,7 +65,9 @@
@include justify-content(flex-start);
margin-bottom: 10px;
- .fa {
+ .fa,
+ .fa-regular,
+ .fa-brands {
font-size: 1.563rem;
margin-right: 14px;
color: $brand-primary;
@@ -92,9 +94,9 @@
}
}
- &:active,
- &:focus,
- &:hover {
+ &.doc-item-link:active,
+ &.doc-item-link:focus,
+ &.doc-item-link:hover {
text-decoration: none;
background: $gray-lighter;
}
@@ -109,7 +111,7 @@
@include clearfix;
padding-bottom: $padding-small;
.discourse,
- .gitter {
+ .discord {
h3 {
margin-top: 0;
}
@@ -168,7 +170,7 @@
}
}
- .gitter {
+ .discord {
ul {
li {
@include span-columns(3 of 6);
diff --git a/_sass/layout/talk-to-us.scss b/_sass/layout/talk-to-us.scss
index ca83f9676e..94c6a147e3 100755
--- a/_sass/layout/talk-to-us.scss
+++ b/_sass/layout/talk-to-us.scss
@@ -25,7 +25,7 @@
}
.discourse,
- .gitter {
+ .discord {
margin-bottom: 50px;
@include clearfix;
}
@@ -76,7 +76,7 @@
}
}
- .gitter {
+ .discord {
ul.first {
@include shift(2);
diff --git a/_sass/layout/title-page.scss b/_sass/layout/title-page.scss
index 44a33f8621..208f0b9565 100755
--- a/_sass/layout/title-page.scss
+++ b/_sass/layout/title-page.scss
@@ -2,6 +2,10 @@
//------------------------------------------------
//------------------------------------------------
+.outdated-page .title-page {
+ background: $brand-tertiary-outdated;
+}
+
.title-page {
background: $brand-tertiary;
// height: 200px;
diff --git a/_sass/layout/toc.scss b/_sass/layout/toc.scss
index a5ab5c19b3..dfacedd379 100644
--- a/_sass/layout/toc.scss
+++ b/_sass/layout/toc.scss
@@ -11,10 +11,6 @@
position: relative;
}
- @include bp(medium) {
- display: none;
- }
-
.contents {
font-weight: 700;
}
@@ -23,14 +19,11 @@
.inner-toc {
max-height: 60vh;
overflow-y: auto;
+ position: relative;
@include bp(large) {
max-height: none;
}
-
- &.book {
- max-height: none;
- }
}
#toc {
@@ -87,7 +80,7 @@
ul {
margin-top: 5px;
margin-bottom: 10px;
- margin-left: 20px;
+ margin-left: 0px;
a {
color: $base-link-color;
@@ -104,7 +97,7 @@
margin-bottom: 0px;
a {
- line-height: 1;
+ line-height: 1.3;
font-weight: normal;
}
diff --git a/_sass/layout/type-md.scss b/_sass/layout/type-md.scss
index 38b09dbbd4..6548b1ff60 100755
--- a/_sass/layout/type-md.scss
+++ b/_sass/layout/type-md.scss
@@ -43,9 +43,8 @@
h4,
h5 {
- font-size: 1.063rem;
+ font-size: 1.0rem;
font-family: $base-font-family;
- text-transform: uppercase;
font-weight: $font-bold;
}
}
@@ -74,13 +73,12 @@
.text-step {
h2 {
margin-bottom: 24px;
-
+ }
+ h3 {
+ margin-bottom: 0.5rem;
}
blockquote,
- h3,
- h4,
- h5,
img,
p,
pre,
@@ -89,6 +87,15 @@
margin-bottom: 18px;
}
+ p + .code-snippet-area {
+ // remove the margin-top for code snippet following a paragraph
+ margin-top: 0px;
+ }
+
+ h4, h5 {
+ margin-bottom: 0.5rem;
+ }
+
ol,
ul {
padding-left: 18px;
@@ -142,35 +149,52 @@
li,
p,
- tr,
- td,
+ dt,
+ dd,
+ pre {
+ // common code for all code (inline and blocks)
+ code {
+ border: $base-border-gray;
+ }
+ }
+
+ li,
+ p,
dt,
dd {
code {
font-family: 'Consolas';
- @include border-radius($border-radius-small);
- font-size: $font-size-medium;
- background: $gray-lighter;
- color: #667b83;
- // border: 1px solid #ced7d7;
- padding: 0 6px;
- margin: 0 4px;
+ background-color: #fff;
+ color: #859900;
+ @include border-radius($border-radius-medium);
+ padding: 2px 6px;
}
}
- pre {
- margin-bottom: 36px;
+ tr,
+ td{
+ code {
+ font-family: 'Consolas';
+ font-size: 0.9375rem;
+ }
+ }
+
+
+ pre {
code {
- padding: 20px;
+ overflow-x: auto;
+ display: block;
font-size: $font-size-medium;
@include border-radius($border-radius-base);
+ padding: 10px 7px;
}
}
table {
width: 100%;
text-align: left;
+ border-collapse: collapse;
thead {
font-weight: $font-bold;
@@ -178,8 +202,8 @@
td,
th {
- border-bottom: $base-border-gray;
- padding: 6px 0;
+ border: $base-border-gray;
+ padding: 6px;
}
}
@@ -195,6 +219,11 @@
font-style: italic;
@include border-radius($border-radius-base);
+ &.help-info {
+ border: 2px dashed $brand-tertiary-dotty;
+ color: $brand-tertiary-dotty;
+ }
+
p {
margin: 0;
}
diff --git a/_sass/utils/_variables.scss b/_sass/utils/_variables.scss
index b40b379981..d018dbae37 100755
--- a/_sass/utils/_variables.scss
+++ b/_sass/utils/_variables.scss
@@ -7,6 +7,8 @@
$brand-primary: #DC322F;
$brand-secondary: #859900;
$brand-tertiary: #5CC6E4;
+$brand-tertiary-outdated: #a9c0c6;
+$brand-tertiary-dotty: #E45C77;
//-------------------------------------------------
$gray-darker: #002B36;
$gray-dark: #073642;
@@ -15,6 +17,11 @@ $gray-li: #244E58;
$gray-light: #E5EAEA;
$gray-lighter: #F0F3F3;
$apple-blue: #6dccf5;
+
+$warning-bg: #FFA500;
+$warning-link: #185eb3;
+$warning-text: #000;
+
//-------------------------------------------------
$headings-font-color: $gray-dark;
$base-font-color: #4A5659;
@@ -72,6 +79,8 @@ $padding-small: 20px;
//------------------------------------------------
$border-radius-base: 3px;
$border-radius-small: 2px;
+$border-radius-medium: 10px;
+$border-radius-large: 15px;
// Breakpoints
//------------------------------------------------
diff --git a/_sass/vendors/neat/settings/_grid.scss b/_sass/vendors/neat/settings/_grid.scss
index fad1e9a445..d2c3639ff8 100755
--- a/_sass/vendors/neat/settings/_grid.scss
+++ b/_sass/vendors/neat/settings/_grid.scss
@@ -22,7 +22,7 @@ $grid-columns: 12 !default;
///
/// @type Number (Unit)
///
-$max-width: 1000px !default;
+$max-width: 1280px!default;
/// When set to true, it sets the box-sizing property of all elements to `border-box`. Set with a `!global` flag.
///
diff --git a/_sips/all.md b/_sips/all.md
index ed26042765..befff8ec61 100644
--- a/_sips/all.md
+++ b/_sips/all.md
@@ -2,69 +2,97 @@
layout: sips
title: List of All SIPs
-redirect_from: "/sips/sip-list.html"
-redirect_from: "/sips/pending/index.html"
+redirect_from:
+ - "/sips/sip-list.html"
+ - "/sips/pending/index.html"
---
+{% assign sips = site.sips | sort: title %}
+{% assign sipData = site.data.sip-data %}
+
+## Pre-SIP Discussions
+
+You can find so-called “pre-SIP discussions” in the Scala Contributors forum, under
+the category [Scala Improvement Process](https://contributors.scala-lang.org/c/sip/13).
+The goal of pre-SIP discussions is to gather initial community feedback and support.
## Pending SIPs
-
+Proposals that are at the design or implementation stage, and that are actively
+discussed by the committee and the proposals’ authors. Click on a proposal to
+read its content, or the corresponding discussions on GitHub if its design has
+not been accepted yet.
+
+
- {% assign sips = site.sips | sort: date | reverse %}
{% for sip in sips %}
- {% if sip.vote-status == "under-review" or sip.vote-status == "pending" or sip.vote-status == "under-revision" %}
-
+## Completed SIPs
+
+Proposals that have been implemented in the compiler and that are available as a stable
+feature of the compiler (shipped), or that will be available in the next minor release
+of the compiler (accepted). Click on a proposal to read its content.
+
+
+
+ {% for sip in sips %}
+ {% if sip.stage == "completed" %}
+
diff --git a/_sips/index.md b/_sips/index.md
index 99c3a5264a..87dc975d0c 100644
--- a/_sips/index.md
+++ b/_sips/index.md
@@ -3,24 +3,17 @@ layout: sips
title: Scala Improvement Process
---
-
-Two separate processes govern changes to Scala:
-
-1. The **Scala Improvement Process** (SIP) covers changes to the Scala
+The **Scala Improvement Process** covers changes to the Scala
language, the Scala compiler, and the core of the Scala standard
library.
-2. The **Scala Platform Process** (SPP) aims to establish a stable
-collection of libraries suitable for widespread use, with a low barrier
-to entry for newcomers.
-
-## Scala Improvement Process (SIP)
+## Scala Improvement Process
-The **SIP** (_Scala Improvement Process_) is a process for submitting
+The _Scala Improvement Process_ is a process for submitting
changes to the Scala language. This process aims to evolve Scala
openly and collaboratively.
-The SIP process covers the Scala language and compiler and the core of
+The process covers the Scala language and compiler and the core of
the Scala standard library. (The core is anything that is unlikely to
be spun off into a separate module.)
@@ -28,14 +21,20 @@ A proposed change requires a design document, called a Scala
Improvement Proposal (SIP). The SIP committee meets monthly to
discuss, and eventually vote upon, proposals.
-A SIP is subject to a [review process](./sip-submission.html).
+A SIP is subject to a [review process]({% link _sips/process-specification.md %}).
Proposals normally include proposed changes to the
-[Scala language specification](https://www.scala-lang.org/files/archive/spec/2.12/).
+[Scala language specification](https://www.scala-lang.org/files/archive/spec/2.13/).
Before reaching the committee, a proposal normally receives community
discussion and review on the
[Scala Contributors](https://contributors.scala-lang.org/) forum.
-Please read [Submitting a SIP](./sip-submission.html) and our
-[SIP tutorial](./sip-tutorial.html) for more information.
+Please read the [SIP tutorial]({% link _sips/sip-tutorial.md %}) or
+[the process specification]({% link _sips/process-specification.md %}) for more
+information.
+
+The aim of the Scala Improvement Process is to apply the openness and
+collaboration that have shaped Scala's documentation and implementation to the
+process of evolving the language. The linked documents capture our guidelines,
+commitments and expectations regarding this process.
> Historical note: The SIP replaces the older SID (Scala Improvement Document) process.
> Completed SID documents remain available in the
diff --git a/_sips/meeting-results.md b/_sips/meeting-results.md
new file mode 100644
index 0000000000..4a44ee7c1b
--- /dev/null
+++ b/_sips/meeting-results.md
@@ -0,0 +1,32 @@
+---
+layout: sips
+title: SIP Meeting Results
+redirect_from: /sips/minutes-list.html
+---
+
+This page lists the results of every SIP meeting, starting from July 2016.
+
+### Meetings ###
+
+
+ {% assign sips = site.sips | sort: 'date' | reverse %}
+ {% for page in sips %}
+ {% if page.partof == 'results' %}
+
+
+### Meeting Minutes ###
+
+Before 2022, we hosted the complete meeting notes (minutes). Some
+meetings were also [recorded on YouTube](https://www.youtube.com/channel/UCn_8OeZlf5S6sqCqntAvaIw/videos?view=2&sort=dd&shelf_id=1&live_view=502).
+
+
+ {% assign sips = site.sips | sort: 'date' | reverse %}
+ {% for pg in sips %}
+ {% if pg.partof == 'minutes' %}
+
diff --git a/_sips/minutes/2016-07-15-sip-minutes.md b/_sips/minutes/2016-07-15-sip-minutes.md
index e329e46aa6..1f29d94957 100644
--- a/_sips/minutes/2016-07-15-sip-minutes.md
+++ b/_sips/minutes/2016-07-15-sip-minutes.md
@@ -14,8 +14,8 @@ The following agenda was distributed to attendees:
| [Discussion of the new SIP process](https://docs.scala-lang.org/sips/sip-submission.html) | Jorge Vicente Cantero |
| [SIP 25 - Trait parameters](https://docs.scala-lang.org/sips/trait-parameters.html) | Adriaan Moors |
| [SIP 26 - Unsigned Integer Data Types](https://github.com/scala/slip/pull/30) | Martin Odersky |
-| [SIP 22 - Async](https://docs.scala-lang.org/sips/async.html) | Eugene Burmako |
-| [SIP 20 - Improved lazy val initialization](https://docs.scala-lang.org/sips/improved-lazy-val-initialization.html) | Sébastien Doeraene |
+| [SIP 22 - Async](https://github.com/scala/improvement-proposals/pull/21) | Eugene Burmako |
+| [SIP 20 - Improved lazy val initialization](https://github.com/scala/improvement-proposals/pull/19) | Sébastien Doeraene |
| [Trailing commas SIP](https://github.com/scala/docs.scala-lang/pull/533) | Eugene Burmako |
Quick iteration through all the SLIPs:
diff --git a/_sips/minutes/2016-08-16-sip-10th-august-minutes.md b/_sips/minutes/2016-08-16-sip-10th-august-minutes.md
index 74a790f9f2..b0009109a0 100644
--- a/_sips/minutes/2016-08-16-sip-10th-august-minutes.md
+++ b/_sips/minutes/2016-08-16-sip-10th-august-minutes.md
@@ -11,11 +11,11 @@ The following agenda was distributed to attendees:
| Topic | Reviewer |
| --- | --- |
-| [SIP-12: Uncluttering Scala's syntax for control structures](https://docs.scala-lang.org/sips/uncluttering-control.html) | Seth Tisue |
-| [SIP-16: Self-cleaning macros](https://docs.scala-lang.org/sips/self-cleaning-macros.html) | Eugene Burmako |
-| [SIP-21: Spores](https://docs.scala-lang.org/sips/spores.html) | Martin Odersky |
+| [SIP-12: Uncluttering Scala's syntax for control structures](https://github.com/scala/improvement-proposals/pull/12) | Seth Tisue |
+| [SIP-16: Self-cleaning macros](https://github.com/scala/improvement-proposals/pull/15) | Eugene Burmako |
+| [SIP-21: Spores](https://github.com/scala/improvement-proposals/pull/20) | Martin Odersky |
| [SIP-23: Literal-based singleton types](https://docs.scala-lang.org/sips/42.type.html) | Adriaan Moors |
-| [SIP-24: Repeated by-name parameters](https://docs.scala-lang.org/sips/repeated-byname.html) | Andrew Marki |
+| [SIP-24: Repeated by-name parameters](https://github.com/scala/improvement-proposals/pull/23) | Andrew Marki |
| [SIP-27: Trailing commas](https://github.com/scala/docs.scala-lang/pull/533#issuecomment-232959066) | Eugene Burmako |
Jorge Vicente Cantero was the Process Lead and acting secretary of the meeting.
@@ -164,7 +164,7 @@ proposal or study it further.
**Conclusion**: The Committee asks Dale to explicitly summarize the potential
conflicts with tuple syntax, review the initial [HList proposal in
-Dotty](https://github.com/lampepfl/dotty/issues/964) to figure out potential
+Dotty](https://github.com/scala/scala3/issues/964) to figure out potential
conflicts with his proposal. Eugene also proposes Dale to consider whether the
Committee can salvage non-controversial parts of this proposal and reduce this
SIP just to them, as well as discussing the utility of having two ways of doing
diff --git a/_sips/minutes/2016-09-20-sip-20th-september-minutes.md b/_sips/minutes/2016-09-20-sip-20th-september-minutes.md
index ca1d7a43ed..2d65bd1856 100644
--- a/_sips/minutes/2016-09-20-sip-20th-september-minutes.md
+++ b/_sips/minutes/2016-09-20-sip-20th-september-minutes.md
@@ -12,7 +12,7 @@ The following agenda was distributed to attendees:
| Topic | Reviewer |
| --- | --- |
| [SIP-NN: Scala Meta SIP](https://github.com/scala/docs.scala-lang/pull/567) | Iulian Dragos and Josh Suereth |
-| [SIP-21: Spores](https://docs.scala-lang.org/sips/spores.html) | Martin Odersky |
+| [SIP-21: Spores](https://github.com/scala/improvement-proposals/pull/20) | Martin Odersky |
| [SIP-26: Unsigned Integer Data Types](https://github.com/scala/slip/pull/30) | Martin Odersky |
| [SIP-27: Trailing commas](https://github.com/scala/docs.scala-lang/pull/533#issuecomment-232959066) | Eugene Burmako |
diff --git a/_sips/minutes/2016-10-25-sip-minutes.md b/_sips/minutes/2016-10-25-sip-minutes.md
index 8acd0d22c6..7c2d98abe2 100644
--- a/_sips/minutes/2016-10-25-sip-minutes.md
+++ b/_sips/minutes/2016-10-25-sip-minutes.md
@@ -12,7 +12,7 @@ The following agenda was distributed to attendees:
| Topic | Reviewer |
| --- | --- |
| Discussion of the voting system | N/A |
-| [SIP-20: Improved Lazy Val Initialization](https://docs.scala-lang.org/sips/improved-lazy-val-initialization.html) | Sébastien Doeraene |
+| [SIP-20: Improved Lazy Val Initialization](https://github.com/scala/improvement-proposals/pull/19) | Sébastien Doeraene |
| [SIP-27: Trailing commas](https://github.com/scala/docs.scala-lang/pull/533#issuecomment-232959066) | Eugene Burmako |
Jorge Vicente Cantero was the Process Lead and acting secretary of the meeting.
@@ -145,9 +145,9 @@ Dotty, in which the championed scheme is already implemented.
There are no clear winner in the case of local lazy vals, but there seems to be
two clear candidates for the non-local lazy vals
-([V4](https://docs.scala-lang.org/sips/pending/improved-lazy-val-initialization.html)
+([V4](https://github.com/scala/improvement-proposals/pull/19)
and
-[V6](https://docs.scala-lang.org/sips/pending/improved-lazy-val-initialization.html)).
+[V6](https://github.com/scala/improvement-proposals/pull/19)).
Both are faster than the existing implementation in the contended case but V4
general is 4x and V6 is only 2x. However, for the uncontended case V4 general is
30% slower than the existing implementation, while V6 is on par, up to +-5%.
diff --git a/_sips/minutes/2016-11-29-sip-minutes.md b/_sips/minutes/2016-11-29-sip-minutes.md
index 26bd0c9987..bc1d3c3452 100644
--- a/_sips/minutes/2016-11-29-sip-minutes.md
+++ b/_sips/minutes/2016-11-29-sip-minutes.md
@@ -11,8 +11,8 @@ The following agenda was distributed to attendees:
|Topic|Reviewers| Accepted/Rejected |
| --- | --- | --- |
-| [SIP-28 and SIP-29 - Inline and meta](https://docs.scala-lang.org/sips/inline-meta.html) | Josh Suereth and Iulian Dragos | Pending |
-| [SIP-24 - Repeated By Name Parameters](https://docs.scala-lang.org/sips/repeated-byname.html) | Heather Miller | Pending |
+| [SIP-28 and SIP-29 - Inline and meta](https://github.com/scala/improvement-proposals/pull/28) | Josh Suereth and Iulian Dragos | Pending |
+| [SIP-24 - Repeated By Name Parameters](https://github.com/scala/improvement-proposals/pull/23) | Heather Miller | Pending |
| [SIP-30 - Static members](https://github.com/scala/docs.scala-lang/pull/491/files) | Adriaan Moors | Pending |
| [SIP-27 - Trailing commas](https://docs.scala-lang.org/sips/trailing-commas.html) |Eugene Burkamo | Accepted |
@@ -42,7 +42,7 @@ Minutes were taken by Travis Lee.
**Jorge** We'll talk about the SIPS for Scala Meta. Eugene will start.
-### [SIP-28 and SIP-29 - Inline and meta](https://docs.scala-lang.org/sips/inline-meta.html)
+### [SIP-28 and SIP-29 - Inline and meta](https://github.com/scala/improvement-proposals/pull/28)
Eugene and co have been working hard for two months on inline and Scala Meta. Previously discussed new macro system with new inline and meta features. Inline provides a facility to declare methods with inline right hand side into call side (0:01:24) and meta implements compile-time function execution to do meta-programming. Martin implemented inline mechanism in Dotty. Eugene worked on macro notations. New style macros will integrate with tools. Eugene shows how it works in IntelliJ. For example, you can print the value of the parameters. Meta blocks supported by IntelliJ. So are quasi-quotes. You can also expand macros. Will greatly help debugability.
@@ -52,7 +52,7 @@ The spec needs to be updated based on Martin's Dotty implementation. We need to
**Conclusion** This proposal needs at least another iteration to shape up and provide concrete implementation and specification details. This proposal is therefore under revision -- Eugene, the author, will gather and address more feedback and will resubmit the proposal to analysis when it's ready.
-### [SIP-24 - Repeated By Name Parameters](https://docs.scala-lang.org/sips/repeated-byname.html)
+### [SIP-24 - Repeated By Name Parameters](https://github.com/scala/improvement-proposals/pull/23)
Heather says the debate is about the semantics or translation rules. All arguments are evaluated each time the parameter is referenced in the method. This is implemented in Dotty. Should this be implemented in Scalac?
diff --git a/_sips/minutes/2017-02-14-sip-minutes.md b/_sips/minutes/2017-02-14-sip-minutes.md
index a71b61f022..1738cdc5ca 100644
--- a/_sips/minutes/2017-02-14-sip-minutes.md
+++ b/_sips/minutes/2017-02-14-sip-minutes.md
@@ -11,9 +11,9 @@ The following agenda was distributed to attendees:
| Topic | Reviewer |
| --- | --- |
-| [SIP-XX - Improving binary compatibility with @stableABI](https://docs.scala-lang.org/sips/binary-compatibility.html) | Dmitry Petrashko |
-| [SIP-NN - Allow referring to other arguments in default parameters](https://docs.scala-lang.org/sips/refer-other-arguments-in-args.html) | Pathikrit Bhowmick |
-| [SIP-30 - @static fields and methods in Scala objects(SI-4581)](https://docs.scala-lang.org/sips/static-members.html) | Dmitry Petrashko, Sébastien Doeraene and Martin Odersky |
+| [SIP-XX - Improving binary compatibility with @stableABI](https://github.com/scala/improvement-proposals/pull/30) | Dmitry Petrashko |
+| [SIP-NN - Allow referring to other arguments in default parameters](https://github.com/scala/improvement-proposals/pull/29) | Pathikrit Bhowmick |
+| [SIP-30 - @static fields and methods in Scala objects(SI-4581)](https://github.com/scala/improvement-proposals/pull/25) | Dmitry Petrashko, Sébastien Doeraene and Martin Odersky |
| [SIP-33 - Match infix & prefix types to meet expression rules](https://docs.scala-lang.org/sips/priority-based-infix-type-precedence.html) | Oron Port |
Jorge Vicente Cantero was the Process Lead. Travis (@travissarles) was acting secretary of the meeting.
diff --git a/_sips/minutes/2017-05-08-sip-minutes.md b/_sips/minutes/2017-05-08-sip-minutes.md
index 5648993695..f2da50701b 100644
--- a/_sips/minutes/2017-05-08-sip-minutes.md
+++ b/_sips/minutes/2017-05-08-sip-minutes.md
@@ -11,7 +11,7 @@ The following agenda was distributed to attendees:
|Topic|Reviewers| Accepted/Rejected |
| --- | --- | --- |
-| [SIP-NN - comonadic-comprehensions](https://docs.scala-lang.org/sips/comonadic-comprehensions.html) | Shimi Bandiel | Rejected |
+| [SIP-NN - comonadic-comprehensions](https://github.com/scala/improvement-proposals/pull/32) | Shimi Bandiel | Rejected |
| [SIP-33 - Match infix & prefix types to meet expression rules](https://docs.scala-lang.org/sips/priority-based-infix-type-precedence.html)| Oron Port | Pending |
|[Scala Library Changes](https://github.com/scala/scala-dev/issues/323)|Adriaan Moors| Scala-dev proposal |
@@ -41,7 +41,7 @@ Minutes were taken by Darja Jovanovic.
**Jorge** going over the agenda, points out that the second item will be skipped because they are waiting for the prototype from the author of the proposal.
-### [SIP-NN - comonadic-comprehensions](https://docs.scala-lang.org/sips/comonadic-comprehensions.html)
+### [SIP-NN - comonadic-comprehensions](https://github.com/scala/improvement-proposals/pull/32)
[YouTube time: 1:39](https://youtu.be/6rKa4OV7GfM?t=99)
Proposal aims to introduce new syntax from comprehension for monads to comonads.
diff --git a/_sips/minutes/2017-09-21-sip-minutes.md b/_sips/minutes/2017-09-21-sip-minutes.md
index 69cd7e28fb..8d32e2421f 100644
--- a/_sips/minutes/2017-09-21-sip-minutes.md
+++ b/_sips/minutes/2017-09-21-sip-minutes.md
@@ -14,7 +14,7 @@ The following agenda was distributed to attendees:
| [SIP-NN: Right-Associative By-Name Operators](https://docs.scala-lang.org/sips/right-associative-by-name-operators.html) | Adriaan Moors | Pending |
| [SIP-ZZ: Opaque types](https://docs.scala-lang.org/sips/opaque-types.html) | Sébastien Doeraene | Pending |
| [SIP-33: Match infix and prefix types to meet expression rules](https://docs.scala-lang.org/sips/priority-based-infix-type-precedence.html)| Josh Suereth | Pending |
-|[SIP-28 and SIP-29: Inline meta](https://docs.scala-lang.org/sips/inline-meta.html)|Josh Suereth and Iulian Dragos| Pending |
+|[SIP-28 and SIP-29: Inline meta](https://github.com/scala/improvement-proposals/pull/28)|Josh Suereth and Iulian Dragos| Pending |
Jorge Vicente Cantero was the Process Lead and Darja Jovanovic as secretary.
@@ -87,7 +87,7 @@ Syntax "new" "type"
Still waiting on the implementation updates, therefore this item will be discussed in the next SIP Meeting.
-### [SIP-28 and SIP-29: Inline and meta](https://docs.scala-lang.org/sips/inline-meta.html)
+### [SIP-28 and SIP-29: Inline and meta](https://github.com/scala/improvement-proposals/pull/28)
[YouTube time: 51'40'' until the end](https://youtu.be/yzTpVbTUj18?t=3100)
**Eugene** gives a brief history of this SIP development, shares the good news and suggests how to proceed.
diff --git a/_sips/minutes/2017-10-24-sip-minutes.md b/_sips/minutes/2017-10-24-sip-minutes.md
index 7cbe327e61..4d65067a48 100644
--- a/_sips/minutes/2017-10-24-sip-minutes.md
+++ b/_sips/minutes/2017-10-24-sip-minutes.md
@@ -14,7 +14,7 @@ The following agenda was distributed to attendees:
| [SIP-34: Right-Associative By-Name Operators](https://docs.scala-lang.org/sips/right-associative-by-name-operators.html) | Adriaan Moors | Accepted |
| [SIP-35: Opaque types](https://docs.scala-lang.org/sips/opaque-types.html) | Sébastien Doeraene | Pending |
| [SIP-33: Match infix and prefix types to meet expression rules](https://docs.scala-lang.org/sips/priority-based-infix-type-precedence.html)| Josh Suereth | Pending |
-|[SIP-28 and SIP-29: Inline meta](https://docs.scala-lang.org/sips/inline-meta.html)|Josh Suereth and Iulian Dragos| Pending |
+|[SIP-28 and SIP-29: Inline meta](https://github.com/scala/improvement-proposals/pull/28)|Josh Suereth and Iulian Dragos| Pending |
Jorge Vicente Cantero was the Process Lead and Darja Jovanovic as secretary.
@@ -75,7 +75,7 @@ The feedback will be given to the author.
-### [SIP-28 and SIP-29: Inline and meta](https://docs.scala-lang.org/sips/inline-meta.html)
+### [SIP-28 and SIP-29: Inline and meta](https://github.com/scala/improvement-proposals/pull/28)
[YouTube time: 10'05'' until the end](https://youtu.be/aIc-o1pcRhw?t=605)
**Jorge** introduces **Olaf** as a new Team Lead of SIP-28 and SIP-29.
diff --git a/_sips/minutes/2017-12-06-sip-minutes.md b/_sips/minutes/2017-12-06-sip-minutes.md
index f639631b4a..29f2aaafbd 100644
--- a/_sips/minutes/2017-12-06-sip-minutes.md
+++ b/_sips/minutes/2017-12-06-sip-minutes.md
@@ -14,7 +14,7 @@ The following agenda was distributed to attendees:
|Discussion and voting on Miles Sabin (Typelevel representative) joining the Committee | | Accepted
|[SIP 23: Literal-based singleton types](https://docs.scala-lang.org/sips/42.type.html) | Adriaan Moors | Accepted
|[SIP-33: Priority-based infix type precedence rules](https://docs.scala-lang.org/sips/priority-based-infix-type-precedence.html) | Josh Suereth | Accepted |
-|[SIP-NN: Adding prefix types](https://docs.scala-lang.org/sips/adding-prefix-types.html) | Josh Suereth | Pending |
+|[SIP-NN: Adding prefix types](https://github.com/scala/improvement-proposals/pull/35) | Josh Suereth | Pending |
|[SIP-35: Opaque types](https://docs.scala-lang.org/sips/opaque-types.html) | Sébastien Doeraene | Not discussed |
|Discussion about the future of Scala 2.13 and 2.14 | | Not discussed |
@@ -73,7 +73,7 @@ Brief explanation about the "The presence of an upper bound of Singleton on a fo
a) [SIP-33: Priority-based infix type precedence rules](https://docs.scala-lang.org/sips/priority-based-infix-type-precedence.html)
-b) [SIP-NN: Adding prefix types](https://docs.scala-lang.org/sips/adding-prefix-types.html)
+b) [SIP-NN: Adding prefix types](https://github.com/scala/improvement-proposals/pull/35)
**Seth** asks about the implementation status in Dotty and if there are any crucial differences in Scala 2 and Dotty?
**Martin** and **Sebastien** agree there are none in regards to this SIP.
@@ -82,7 +82,7 @@ The members are all in favour for this change and proceed to voting.
**Conclusion** : The SIP-33 is accepted by unanimity.
-### [SIP-NN: Adding prefix types](https://docs.scala-lang.org/sips/adding-prefix-types.html)
+### [SIP-NN: Adding prefix types](https://github.com/scala/improvement-proposals/pull/35)
[YouTube time: 25'00 until the end](https://youtu.be/Mhwf15gjL9s?t=1503)
**Jorge** introduces the SIP's development, based on the idea
diff --git a/_sips/minutes/2018-08-30-sip-minutes.md b/_sips/minutes/2018-08-30-sip-minutes.md
index 48bc21c12f..218877a1db 100644
--- a/_sips/minutes/2018-08-30-sip-minutes.md
+++ b/_sips/minutes/2018-08-30-sip-minutes.md
@@ -68,7 +68,7 @@ Decision / voting / postponing the discussion
**Miles Sabin** summarised discussion on Contributors thread.
- Focuses on the Contributors discussion rather than on the proposal itself
-- Underlines a lack of motivation in the light of a separate issue from [Dotty: Weak eta-expansion](https://github.com/lampepfl/dotty/issues/2570)
+- Underlines a lack of motivation in the light of a separate issue from [Dotty: Weak eta-expansion](https://github.com/scala/scala3/issues/2570)
- Concludes that this proposal should be aligned with eta-extension issue
Summary:
@@ -77,9 +77,9 @@ References
+ [Scala Contributors thread](https://contributors.scala-lang.org/t/proposal-to-remove-auto-application-from-the-language/2145).
-+ [Dotty issue: Weak eta-expansion](https://github.com/lampepfl/dotty/issues/2570).
++ [Dotty issue: Weak eta-expansion](https://github.com/scala/scala3/issues/2570).
-+ [Martin's comment on the issue above](https://github.com/lampepfl/dotty/issues/2570#issuecomment-306202339).
++ [Martin's comment on the issue above](https://github.com/scala/scala3/issues/2570#issuecomment-306202339).
Comments
@@ -200,7 +200,7 @@ Related links
- One in scalaz-deriving: https://gitlab.com/fommil/scalaz-deriving/tree/master/examples/xmlformat/src/main/scala/xmlformat (link behind a login wall, it seems)
- JSX-style libraries for Scala:
- https://github.com/OlivierBlanvillain/monadic-html
- - Binding.scala, TODO app: https://scalafiddle.io/sf/dGkVqlV/9
+ - Binding.scala,
- Ammonite script to convert HTML to the VDOM DSL of scalajs-react (a ScalaTags flavor):
https://gist.github.com/nafg/112bf83e5676ed316f17cea505ea5d93
diff --git a/_sips/minutes/2018-11-26-sip-minutes.md b/_sips/minutes/2018-11-26-sip-minutes.md
index a177b78833..776257508a 100644
--- a/_sips/minutes/2018-11-26-sip-minutes.md
+++ b/_sips/minutes/2018-11-26-sip-minutes.md
@@ -49,7 +49,7 @@ The SIP Committee gathered for the first time face-to-face, for an extensive 3-d
- Outline an action plan within a set time-frame;
- Other: Unanimously voted for Guillaume Martres to join the Committee.
-*Better understanding* was enabled by in depth presentations and Q&As with the EPFL Dotty team; *the Approach* was agreed upon the first day which resulted in creating “FAQs about Scala 3” (see below) and *the Action Plan* was outlined and is still under construction; several issues were opened (please see the list at the end of this document) and a project plan ["Meta-programming in Scala 3"](https://github.com/lampepfl/dotty/issues/5489) has been developed.
+*Better understanding* was enabled by in depth presentations and Q&As with the EPFL Dotty team; *the Approach* was agreed upon the first day which resulted in creating “FAQs about Scala 3” (see below) and *the Action Plan* was outlined and is still under construction; several issues were opened (please see the list at the end of this document) and a project plan ["Meta-programming in Scala 3"](https://github.com/scala/scala3/issues/5489) has been developed.
As the most important points and summary is reflected in “FAQs about Scala 3”, it will stand as an official “minutes” for this unique SIP meeting.
@@ -105,7 +105,7 @@ Implicit Function Types (https://dotty.epfl.ch/docs/reference/instances/implicit
[Type Lambdas](https://dotty.epfl.ch/docs/reference/new-types/type-lambdas.html)
-[Type Checking](https://dotty.epfl.ch/docs/reference/changed-features/type-checking.html)
+Type Checking
[Type Inference](https://dotty.epfl.ch/docs/reference/changed-features/type-inference.html)
@@ -144,20 +144,20 @@ The dependency of Scala 2 macros and reflection on internal implementation detai
We recognize that important parts of the Scala ecosystem have made essential use of the Scala 2 facilities and that it is vital that as many as possible of these use cases be accommodated in Scala 3 in some form or another. This will be disruptive, but we hope to mitigate the disruption by providing facilities which make the more straightforward and important scenarios simpler while still leaving others possible.
Our direction is still evolving; however we believe that replacing the current excessively general and expressive macro system with a suite of less powerful but complementary tools is the way forward.
Currently we are exploring options which range from improved support for type level programming in the language itself (eg. specialized inline, match types, stable definitions, GADT improvements); intrinsifying certain features currently supported by macros (eg. by-name implicits, generic programming primitives); through to less general forms of metaprogramming (quote/splice and staging) and portable reflection via Tasty (which we [recommend](https://github.com/scalacenter/advisoryboard/pull/40)) to support in both Scala 2/3 and via compiler-independent libraries and tools. We recommend that most current uses of Scala macros and reflection can be accommodated by some combination of these tools.
-For more about the project's progress, please see https://github.com/lampepfl/dotty/issues/5489
+For more about the project's progress, please see https://github.com/scala/scala3/issues/5489
### How do we plan to address language experimentation?
We acknowledge that language experimentation is necessary for improving the language. We also believe it requires a different vehicle than stable Scala releases. We don’t have a concrete solution for now, but we’re working on one.
### Other “documents” created during the meetings:
-[SIP: Structural Types](https://github.com/lampepfl/dotty/issues/5372)
+[SIP: Structural Types](https://github.com/scala/scala3/issues/5372)
-[SIP: TASTY changes](https://github.com/lampepfl/dotty/issues/5378)
+[SIP: TASTY changes](https://github.com/scala/scala3/issues/5378)
-[SIP: Underscore Syntax for Type Lambdas](https://github.com/lampepfl/dotty/issues/5379)
+[SIP: Underscore Syntax for Type Lambdas](https://github.com/scala/scala3/issues/5379)
-[Should we bring back rewrite methods?](https://github.com/lampepfl/dotty/issues/5381)
+[Should we bring back rewrite methods?](https://github.com/scala/scala3/issues/5381)
[Features work progress overview](https://docs.google.com/spreadsheets/d/1GWJUo0U3JbBtrfg5vqgb6H5S6wlU5HnTxebLcHwD1zw/edit?usp=sharing)
diff --git a/_sips/minutes/2019-03-13-sip-minutes.md b/_sips/minutes/2019-03-13-sip-minutes.md
index 91924f4bc5..80854b32e3 100644
--- a/_sips/minutes/2019-03-13-sip-minutes.md
+++ b/_sips/minutes/2019-03-13-sip-minutes.md
@@ -346,7 +346,7 @@ Seb: there are two widely different things in this proposal that are mixed toget
Martin: avoiding the word implicit was something of an exercise, to avoid confusing the old system and new system in the minds of people who know the old system. In the long run, it might be better to just go ahead and talk about "implicits".
-Seth: how will we teach this from scratch? Martin: pages like [https://dotty.epfl.ch/docs/reference/contextual/instance-defs.html](https://dotty.epfl.ch/docs/reference/contextual/instance-defs.html) actually are an attempt at this.
+Seth: how will we teach this from scratch? Martin: pages like [https://dotty.epfl.ch/docs/reference/contextual/givens.html](https://dotty.epfl.ch/docs/reference/contextual/givens.html) actually are an attempt at this.
Miles: in the `ListOrd[T]` example, it's essentially a function definition, a function from `Ord[T]` to `Ord[List[T]]`, why doesn't it look like I'm writing a function?
@@ -404,7 +404,7 @@ import implied
Martin: there's a PR, not yet merged, that refines this rule considerably compared to what's on the Dotty feature page?
-It's [https://github.com/lampepfl/dotty/pull/6041](https://github.com/lampepfl/dotty/pull/6041) -- it has the new impl as well as the changes to the web page.
+It's [https://github.com/scala/scala3/pull/6041](https://github.com/scala/scala3/pull/6041) -- it has the new impl as well as the changes to the web page.
Martin: we now have a custom error message so if something fails but changing import to import implied would fix it, the compiler will tell you.
@@ -508,7 +508,7 @@ What's the metaprogramming status?
Martin: quote and splice are stable, but don't support pattern matching yet. TASTY reflection is not complete yet and is still undergoing revisions based on use cases that are being tried.
-No one has done any meaningful whitebox macros yet in the new system, but the door is now open. (<-- not sure if I should include this in the notes without understanding in what context we want to allow whitebox macros?) This only got merged "last week". The relevant PR is [https://github.com/lampepfl/dotty/pull/5846](https://github.com/lampepfl/dotty/pull/5846) "The main motivation for moving staging to typer is to support whitebox macros" but it's still very early days, no one has tried to actually use this.
+No one has done any meaningful whitebox macros yet in the new system, but the door is now open. (<-- not sure if I should include this in the notes without understanding in what context we want to allow whitebox macros?) This only got merged "last week". The relevant PR is [https://github.com/scala/scala3/pull/5846](https://github.com/scala/scala3/pull/5846) "The main motivation for moving staging to typer is to support whitebox macros" but it's still very early days, no one has tried to actually use this.
# **Kind polymorphism**
@@ -554,7 +554,7 @@ Questions about the magic automatic extends clauses, how does the compiler know,
"Generally, all covariant type parameters of the enum class are minimized in a compiler-generated extends clause whereas all contravariant type parameters are maximized", says the doc
-There was some discussion of the details of the rules for type parameters -- this then erupted into a full-on debate. e.g. isn't it weird that if you add an extends clause, suddenly T isn't in scope any more? see [https://github.com/lampepfl/dotty/pull/6095](https://github.com/lampepfl/dotty/pull/6095)
+There was some discussion of the details of the rules for type parameters -- this then erupted into a full-on debate. e.g. isn't it weird that if you add an extends clause, suddenly T isn't in scope any more? see [https://github.com/scala/scala3/pull/6095](https://github.com/scala/scala3/pull/6095)
conclusion: Martin: I'll try to update the rules to reflect the behavior of the compiler.
diff --git a/_sips/minutes/2019-06-08-sip-minutes.md b/_sips/minutes/2019-06-08-sip-minutes.md
index 1b47ce81e5..247472ece1 100644
--- a/_sips/minutes/2019-06-08-sip-minutes.md
+++ b/_sips/minutes/2019-06-08-sip-minutes.md
@@ -28,7 +28,7 @@ apart from the other implicits changes
### Auto-tupling
-Implemented but not merged: [https://github.com/lampepfl/dotty/pull/4311](https://github.com/lampepfl/dotty/pull/4311)
+Implemented but not merged: [https://github.com/scala/scala3/pull/4311](https://github.com/scala/scala3/pull/4311)
The problem is when using infix (e.g. an operator method) there's confusion between a 1-argument tuple2 method
and a 2-argument method, of which there are a few in the standard library.
@@ -96,7 +96,7 @@ Adriaan: Also let's not forget the big Scaladoc impact, can't copy because of th
### Polymorphic function types
-Merged but not documented: [https://github.com/lampepfl/dotty/pull/4672](https://github.com/lampepfl/dotty/pull/4672)
+Merged but not documented: [https://github.com/scala/scala3/pull/4672](https://github.com/scala/scala3/pull/4672)
Presented by Guillaume.
@@ -255,7 +255,7 @@ Martin: But we said we weren't adding anything to the standard library in 3.0
### Erased Terms
-[https://dotty.epfl.ch/docs/reference/metaprogramming/erased-terms.html](https://dotty.epfl.ch/docs/reference/metaprogramming/erased-terms.html)
+[https://dotty.epfl.ch/docs/reference/experimental/erased-defs.html](https://dotty.epfl.ch/docs/reference/experimental/erased-defs.html)
Olivier: Are they necessary?
* Yes's and No's
diff --git a/_sips/minutes/2019-12-18-sip-minutes.md b/_sips/minutes/2019-12-18-sip-minutes.md
index 3cceb8b6fc..f3ea7d1a23 100644
--- a/_sips/minutes/2019-12-18-sip-minutes.md
+++ b/_sips/minutes/2019-12-18-sip-minutes.md
@@ -161,7 +161,7 @@ New thread: [SIP public review: Open classes](https://contributors.scala-lang.or
### Review the "Explicit nulls" SIP
-Thread:
+Thread: <{{ site.scala3ref }}/experimental/explicit-nulls.html>
Sébastien championing and presenting.
diff --git a/_sips/minutes/2020-03-12-minutes.md b/_sips/minutes/2020-03-12-minutes.md
index 6519770488..4e40af5e32 100644
--- a/_sips/minutes/2020-03-12-minutes.md
+++ b/_sips/minutes/2020-03-12-minutes.md
@@ -128,7 +128,7 @@ Run through https://dotty.epfl.ch/docs/reference/metaprogramming/inline.html
* Gui: inline interacts with overriding
* Nic: if in a subclass (say Range) you override a method (say foreach) with `inline` it only inlines if the type is cast
* Seb: I need both, inline if statically the type is Range, and use the optimised override if it's a Seq that's a Range at runtime
-* (After the meeting, this led to [lampepfl/dotty#8543](https://github.com/lampepfl/dotty/pull/8543) and [lampepfl/dotty#8564](https://github.com/lampepfl/dotty/issues/8564).)
+* (After the meeting, this led to [scala/scala3#8543](https://github.com/scala/scala3/pull/8543) and [scala/scala3#8564](https://github.com/scala/scala3/issues/8564).)
* Lukas: `inline` is perfect for macros, but it shouldn't exist for performance. The runtime is where performance should be fixed (and it's in a better position to do it)
* Lukas: inlining isn't on by default (in Scala 2) because it interacts with binary compatibility in non-obvious ways, and `inline` in Dotty does the same
@@ -136,7 +136,7 @@ Run through https://dotty.epfl.ch/docs/reference/metaprogramming/macros.html
Run through https://dotty.epfl.ch/docs/reference/metaprogramming/staging.html, which adds a bit on top of the macro framework above, but can be compiled (and executed) at runtime
-Run through https://dotty.epfl.ch/docs/reference/metaprogramming/tasty-reflect.html
+Run through https://dotty.epfl.ch/docs/reference/metaprogramming/reflection.html
* Gui: concerned how many compiler implementation details TASTy reflect exposes
* Gui: should try to reduce it to the minimum of what users care about, for example, opaque types, and maintain backwards compatibility
@@ -144,7 +144,7 @@ Run through https://dotty.epfl.ch/docs/reference/metaprogramming/tasty-reflect.h
### Review match types
-Review https://github.com/dotty-staging/dotty/blob/fix-6709/docs/docs/reference/new-types/match-types.md (part of https://github.com/lampepfl/dotty/pull/8024)
+Review https://github.com/dotty-staging/dotty/blob/fix-6709/docs/docs/reference/new-types/match-types.md (part of https://github.com/scala/scala3/pull/8024)
```scala
type LeafElem[X] = X match {
@@ -157,7 +157,7 @@ type LeafElem[X] = X match {
* Olivier: The order of match type definitions is significant
* Olivier: The disjointness is between `X` and `String`, not between `String` and `Array`
-* Olivier: See https://github.com/lampepfl/dotty/issues/8493 as an example of disjointness requirement (can't use traits)
+* Olivier: See https://github.com/scala/scala3/issues/8493 as an example of disjointness requirement (can't use traits)
* Martin: Currently the use-cases can be implemented like Generic
* Olivier: Put at a very high level, the intent is to remove some of the computation that happens in implicits and do it (better) in match types
* Olivier: another problem is that when you type-check a type you can stackoverflow, which has bad UX, particularly given we have recursive types
diff --git a/_sips/minutes/2020-03-13-sip-minutes.md b/_sips/minutes/2020-03-13-sip-minutes.md
index 405755918d..7e394ea557 100644
--- a/_sips/minutes/2020-03-13-sip-minutes.md
+++ b/_sips/minutes/2020-03-13-sip-minutes.md
@@ -285,8 +285,8 @@ Martin:
- Used widely in compiler codebase for 6 months
- Does find is necessary to have vertical bars in editor for indentation
- Examples at:
- - https://github.com/lampepfl/dotty/blob/master/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala
- - https://github.com/lampepfl/dotty/blob/master/compiler/src/dotty/tools/dotc/typer/Nullables.scala
+ - https://github.com/scala/scala3/blob/main/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala
+ - https://github.com/scala/scala3/blob/main/compiler/src/dotty/tools/dotc/typer/Nullables.scala
- `then` in if expression was harder to get used to
Guillaume:
@@ -424,7 +424,7 @@ Sébastien:
- Asks if the new rules allow to add an implicit definition of a priority in-between two other definitions while preserving binary compatability?
Martin, in response:
-- Shows a [demo](https://github.com/lampepfl/dotty/blob/master/tests/run/implied-priority.scala) of how to insert a new implicit in between existing definitions.
+- Shows a [demo](https://github.com/scala/scala3/blob/main/tests/run/implied-priority.scala) of how to insert a new implicit in between existing definitions.
- The new scheme of priorities is more simple to grow than before because inheritance is fragile
Sébastien is satisfied with the demo, is fine either way to add to 3.0 or later. Someone should champion it.
diff --git a/_sips/process-specification.md b/_sips/process-specification.md
new file mode 100644
index 0000000000..93a15ce812
--- /dev/null
+++ b/_sips/process-specification.md
@@ -0,0 +1,342 @@
+---
+layout: sips
+title: Process Specification
+redirect_from: /sips/sip-submission.html
+---
+
+The Scala Improvement Process (sometimes called SIP process) is a process for
+submitting changes to the Scala language. This process aims to evolve Scala
+openly and collaboratively.
+
+The SIP process covers the Scala language (syntax, type system and semantics)
+and the core of the Scala standard library. The core is anything that is
+referenced from the language spec (such as primitive types or the definition
+of `Seq`). The SIP process is not concerned with compiler changes that do not
+affect the language (including but not limited to linting warnings,
+optimizations, quality of error messages).
+
+A proposed change requires a design document, called a Scala Improvement
+Proposal (SIP). The committee meets monthly to discuss, and eventually vote
+upon, proposals.
+
+The committee follows the following process when evaluating SIP documents,
+from an idea to the inclusion in the language.
+
+## Definitions
+
+- SIP (Scala Improvement Proposal): a particular proposal for changing the Scala
+ language (additions, changes, and/or removals).
+- Committee: a group of experienced Scala practitioners and language designers,
+ who evaluate changes to the Scala programming language. It consists of a
+ Secretary, a Chairperson, and Members.
+- Chairperson: person in charge of executing the process. They organize and
+ chair the meetings of the Committee, and generally make sure the process is
+ followed, but do not vote on proposals. The Chairperson is an appointed
+ employee of the Scala Center.
+- Committee Member: member of the Committee with voting rights. The Chairperson
+ cannot be a Member at the same time.
+- Secretary: person attending the regular meetings and responsible for writing
+ notes of the discussions.
+- SIP Author: any individual or group of people who writes a SIP for submission
+ to the Committee. The Chairperson and Committee Members may also be SIP Authors.
+ Authors are responsible for building consensus within the community and
+ documenting dissenting opinions before the SIP is officially discussed by the
+ SIP Committee. Their goal is to convince the committee that their proposal is
+ useful and addresses pertinent problems in the language as well as interactions
+ with already existing features. Authors can change over the life-cycle of the
+ SIP.
+- SIP Reviewers: a subset of Committee Members assigned by the Chairperson to
+ review in detail a particular SIP. The same person cannot be both a SIP Author
+ and a SIP Reviewer for the same SIP.
+- SIP Manager: one of the SIP Reviewers who is responsible for all the
+ communications related to the SIP, throughout its entire life-cycle. This includes requesting a vote on the SIP from the whole Committee, presenting the SIP to the Committee at the plenary meetings, merging or closing the corresponding PR, reporting to the community on the vote outcome, and announcing when it is available for testing.
+
+## Stages
+
+From being an idea to being part of the language, a SIP goes through several
+Stages that indicate the "maturity" level of the SIP. The following table
+summarizes the intent of the various stages.
+
+
+
+
+
Stage
+
Purpose
+
Entry criteria
+
Post-entry changes expected
+
+
+
+
+
Pre-SIP
+
Gather initial community feedback and support.
+
N/A. Opening a "Pre-SIP" post on the Scala Contributors forum can be done by anyone at any time
+
N/A
+
+
+
Design
+
Make the case for the proposal. Make the design of the feature precise. Evaluate the solution among other possible solutions. Identify potential challenges.
+
Community support was demonstrated in the Pre-SIP forum post. This is loosely defined.
+
Major changes expected.
+
+
+
Implementation
+
Provide an Experimental implementation of the changes in the compiler. Evaluate how they hold up in practice. Get feedback from implementers and users.
+
The SIP contains a precise specification for the changes and how they should interact with the rest of the language.
+ The Committee votes in favor of the SIP to be "Accepted for implementation".
+
Minor changes based on feedback from implementers and early users.
+
+
+
Completed
+
Ship the feature. Once accepted, the feature will ship as stable in the next Minor release of the Scala language.
+
A complete implementation, with tests, was merged in the mainline compiler and shipped as Experimental. Implementers do not have any concerns left wrt. the implementation of the feature and its interactions.
+ The Committee votes in favor of the SIP to be "Accepted".
+
No changes allowed.
+
+
+
+
+### The process in one graph
+
+
+
+### Pre-SIP Stage
+
+To initiate a discussion, any individual opens a "Pre-SIP" post in the Scala
+Contributors forum. The post should be in the
+[Scala Improvement Process](https://contributors.scala-lang.org/c/sip/13)
+category, and its title should start with "Pre-SIP:". The purpose of the Pre-SIP
+post is to present an idea to the Scala community: a Pre-SIP should present a
+problem that needs solving (i.e., motivate the changes) and present possible
+solutions with pros and cons. The community is encouraged to engage in the
+discussions by voicing support, comments and concerns.
+
+During the Pre-SIP stage, the Committee is not required to be involved.
+Committee Members and the Chairperson are expected to follow Pre-SIP
+discussions, but not required to engage.
+
+Once at least one month has passed and the author has built some community
+support for their Pre-SIP, they can Submit a SIP for discussion by the
+Committee. "Community support" is loosely defined. It involves a mix of positive
+comments, likes, etc. Generally, the Chairperson or a Committee member will post
+a comment on the thread suggesting to submit a SIP when they see that a Pre-SIP
+is ready to enter the process.
+
+### Entry into the process (SIP Submission)
+
+To submit a SIP, a SIP Author writes a pull request to the
+[scala/improvement-proposals](https://github.com/scala/improvement-proposals)
+repository, following the [tutorial]({% link _sips/sip-tutorial.md %}), and
+pointing to the Pre-SIP discussion. If the proposal correctly follows the
+template, and the Pre-SIP discussion seems to show some community support,
+the Chairperson will accept the SIP for review, assign a SIP number, assign
+3 reviewers to the SIP among the Committee Members, and assign one of the reviewers
+to be the Manager of that SIP. Since "community support" is
+loosely defined, any Committee Member can also comment on the PR to accept the
+SIP for review (this is meant mostly as an escape hatch to prevent the
+Chairperson from unilaterally blocking a SIP from entering the process). From
+that point onwards, the SIP has entered the Design Stage.
+
+If the template has not been correctly followed, or if none of the Committee
+Members nor the Chairperson think that the Pre-SIP has gathered enough support,
+the PR may be closed after 2 weeks.
+
+### PR states and GitHub labels
+
+As soon as a SIP PR is opened, the GitHub labels `stage:pre-sip` and
+`status:submitted` are applied to it. At any given moment, a SIP PR will have as
+labels one of the following possibilities:
+
+| | | |
+|------------------------|-------------------------------------|-------------------------|
+| `stage:pre-sip` | `status:submitted` | |
+| `stage:design` | `status:under-review` | |
+| `stage:design` | `status:vote-requested` | `recommendation:accept` |
+| `stage:design` | `status:vote-requested` | `recommendation:reject` |
+| `stage:implementation` | `status:waiting-for-implementation` | |
+| `stage:implementation` | `status:under-review ` | |
+| `stage:implementation` | `status:vote-requested` | `recommendation:accept` |
+| `stage:implementation` | `status:vote-requested` | `recommendation:reject` |
+| `stage:completed` | `status:accepted` | |
+| `stage:completed` | `status:shipped` | |
+| | `status:rejected` | |
+| | `status:withdrawn` | |
+
+### Design Stage -- Review
+
+Once a SIP has entered the Design Stage, the assigned reviewers will review (as
+a GitHub Review on the SIP PR) the proposal within 3 weeks. The authors may then
+address the concerns by pushing additional commits and ask for a new review.
+This phase is iterative, like any pull request to an implementation repository.
+After each request for a new review, the reviewers have 3 weeks to do another
+round.
+
+When the reviewers are confident that the SIP is in good shape to be discussed
+with the full Committee, the Manager sets its status to "Vote Requested" and decide on a
+Vote Recommendation that they will bring to the Committee. A Vote Recommendation
+is either "Recommend Accept" or "Recommend Reject". The proposal is then
+scheduled on the agenda of the next Committee meeting (which happens once a
+month).
+
+At any time, the SIP Author may voluntarily Withdraw their SIP, in which case it
+exits the process. It is possible for someone else (or the same person) to
+become the new SIP Author for that SIP, and therefore bring it back to the
+process. If a SIP Author does not follow up on Reviewers' comments for 2 months,
+the SIP will automatically be considered to be Withdrawn.
+
+### Design Stage -- Vote
+
+During the Committee meeting, the Managers of any scheduled SIP present the SIP
+to the Committee, their recommendation, and explain why they made that
+recommendation. After discussion, the Committee votes for advancing the SIP to
+the Implementation Stage. There are three possible outcomes:
+
+- Accept for implementation: the proposal then advances to the Implementation
+ Stage, and therefore becomes a formal recommendation to be implemented as an
+ Experimental feature into the compiler.
+- Reject: the proposal is rejected and the PR closed. It exits the process at
+ this point. The reviewers will communicate on the PR the reason(s) for the
+ rejection.
+- Keep: the proposal remains in the Design Stage for further iterations. The
+ reviewers will communicate on the PR the current concerns raised by the
+ Committee.
+
+In order to be accepted for implementation and advance to the next stage, a SIP
+must gather strictly more than 50% of "Advance" votes among the whole Committee. This means that an abstention is equivalent to "Do not advance" for this purpose, biasing the process in favor of the status quo. Furthermore, if more than half of the Committee members are absent at the meeting, the vote is cancelled.
+
+For instance, if the Committee is made of 11 members, at least 6 members have to vote "Advance" for the SIP to move to the next stage.
+
+If there was a strict majority in favor of "Advance", the PR for the SIP is Merged at this point by its Manager.
+Otherwise, a second vote between
+Reject and Keep will be used. A proposal needs more than 50% "Reject" votes to
+be rejected in that case. Otherwise, it is kept.
+
+The SIP Manager shares the outcome of the vote with the community by posting a comment to proposal’s Pre-SIP discussion.
+
+### Implementation Stage
+
+Once in the implementation stage, the Committee is not concerned with the SIP
+anymore, until new concerns are discovered or until the implementation is ready.
+The SIP is now a recommendation for the compiler team or any other individual or
+group of people to provide an implementation of the proposal, as a pull request
+to the Scala 3 compiler repository. There is no set timeline for this phase.
+
+Often, proposals not only need to be implemented in the compiler, but also in
+several other tools (IDEs, syntax highlighters, code formatters, etc.). As soon
+as a proposal reaches the implementation stage, the Chairperson notifies the
+impacted tools that they should start implementing support for it. A list of
+tools of the ecosystem is maintained in [this document][tooling ecosystem].
+
+An implementation will be reviewed by the compiler team, and once the
+implementation is deemed good enough, it can ship as an Experimental feature in
+the next release of the compiler where it's practical to do so. At that point, the SIP Manager posts a follow-up comment on the Pre-SIP discussion to invite the community to test the feature and provide feedback.
+
+The implementers may hit challenges that were not foreseen by the Committee.
+Early users may also provide feedback based on practical experience with the
+Experimental feature. This feedback can be sent back to the Committee by
+implementers. This is done with a PR to the SIP repository, amending the
+previously merged SIP document or raising questions for challenges. In that
+case, the SIP Author and Reviewers will work together with the implementers to
+address the feedback. This is again an iterative process. Reviewers may merge
+changes to the proposal at their discretion during this phase.
+
+Once the implementation is deemed stable, including appropriate tests and
+sufficient support by the tooling ecosystem, the implementers and reviewers can
+schedule the SIP to the next Committee meeting for final approval. Once again, a
+SIP needs to gather strictly more than 50% "Accept" votes to be Completed. If
+that is not achieved, it may likewise be sent back for refinements, or be
+rejected, with the same rules as in the "Design Stage -- Vote" section.
+
+### Completed Stage
+
+Once a SIP is accepted for shipping, it will be enabled by default (as
+non-Experimental) in the next practical Minor release of the language.
+
+From this point onwards, the feature is stable and cannot be changed anymore.
+Any further changes would have to come as an entirely new SIP.
+
+## The SIP Committee
+
+The current committee members are:
+
+- Björn Regnell ([@bjornregnell](https://github.com/bjornregnell)), Lund University
+- Chris Andrews ([@chrisandrews-ms](https://github.com/chrisandrews-ms)), Morgan Stanley
+- Guillaume Martres ([@smarter](https://github.com/smarter)), EPFL
+- Haoyi Li ([@lihaoyi](https://github.com/lihaoyi)), Databricks
+- Lukas Rytz ([@lrytz](https://github.com/lrytz)), Lightbend
+- Martin Odersky ([@odersky](https://github.com/odersky)), EPFL
+- Oron Port ([@soronpo](https://github.com/soronpo)), DFiant Inc
+- Sébastien Doeraene ([@sjrd](https://github.com/sjrd)), Scala Center
+
+The current Chairperson is:
+
+- Dimi Racordon ([@kyouko-taiga](https://github.com/kyouko-taiga)), EPFL
+
+The current Secretary is:
+
+- Seth Tisue ([@SethTisue](https://github.com/SethTisue)), Lightbend
+
+### Committee Meetings
+
+The plenary Committee Meetings are scheduled monthly by the Chairperson. They
+have the following purposes:
+
+- Vote to accept, keep or reject SIPs that are in a "Vote Requested" state
+- Be aware of the list of SIPs that are "Under review". If a SIP stays too long
+ under review, Committee Members may request for it to be put to discussion
+ and/or vote in a subsequent plenary meeting, even if the Reviewers do not
+ think it is ready. This is meant primarily as an escape hatch, preventing
+ Reviewers from blocking a SIP by infinitely stalling it.
+- Make any exception to the process that they judge necessary to unblock a
+ situation.
+
+If a Committee Member cannot attend a meeting, they are welcome to share their feedback about the proposals listed in the agenda of the meeting with the Chairperson, who will relate it during the meeting. A Committee Member cannot give their voting power to someone else. If a Committee Member misses more than 2 meetings within a year, they lose their seat.
+
+### Responsibilities of the Committee Members
+
+- Review the proposals they are assigned to:
+ 1. Discuss unclear points with the authors,
+ 2. Help them address their issues and questions,
+ 3. Provide them feedback from the discussions in the meetings, and
+ 4. Explain the latest progress in every meeting.
+- Play a role in the discussions, learn in advance about the topic if needed,
+ and make up their mind in the voting process.
+- Establish communication channels with the community to share updates about the evolution of proposals and collect feedback.
+
+### Guests
+
+Experts in some fields of the compiler may be invited to concrete meetings as
+guests when discussing related SIPs. Their input would be important to discuss
+the current state of the proposal, both its design and implementation.
+
+### On what basis are proposals evaluated?
+
+The Committee ultimately decides how to evaluate proposals, and on what grounds.
+The Committee does not need to justify its decisions, although it is highly
+encouraged to provide reasons.
+
+Nevertheless, here is a non-exhaustive list of things that the Reviewers and
+Committee are encouraged to take into account:
+
+- The proposal follows the "spirit" of Scala
+- The proposal is well motivated; it solves a recurring problem
+- The proposal evaluates the pros and cons of its solution; the solution put
+ forward is believed to be the best one
+- The proposal can be implemented in a way that does not break backward binary
+ nor TASTy compatibility
+- The proposal makes an effort not to break backward source compatibility
+- The proposal does not change the meaning of existing programs
+- The proposal can be implemented on all major platforms (JVM, JS and Native)
+
+## Exceptions and changes
+
+The present document tries to account for most situations that could occur in
+the lifetime of SIPs. However, it does not pretend to be an ultimate solution to
+all cases. At any time, the Committee can decide, by consensus, to make
+exceptions to the process, or to refine the process.
+
+## How do I submit?
+
+Follow the [submission tutorial]({% link _sips/sip-tutorial.md %}).
+
+[tooling ecosystem]: https://github.com/scala/improvement-proposals/blob/main/tooling-ecosystem.md
diff --git a/_sips/results/2022-08-26-meeting.md b/_sips/results/2022-08-26-meeting.md
new file mode 100644
index 0000000000..efec513d6c
--- /dev/null
+++ b/_sips/results/2022-08-26-meeting.md
@@ -0,0 +1,25 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 26th August 2022
+partof: results
+proposals:
+ - url: https://github.com/scala/improvement-proposals/pull/29
+ name: SIP-32 - Allow referring to other arguments in default parameters
+ result: rejected
+ - url: https://github.com/scala/improvement-proposals/pull/37
+ name: SIP-39 - Uncluttering Abuse of Match
+ result: rejected
+ - url: https://docs.scala-lang.org/sips/binary-integer-literals.html
+ name: SIP-42 - Binary Integer Literals
+ result: accepted
+ - url: https://github.com/scala/improvement-proposals/pull/42
+ name: SIP-40 - Name Based XML Literals
+ result: rejected
+ - url: https://github.com/scala/improvement-proposals/pull/41
+ name: SIP-45 - Curried varargs
+ result: rejected
+ - url: https://docs.scala-lang.org/sips/fewer-braces.html
+ name: SIP-44 - Fewer braces
+ result: accepted
+---
+
diff --git a/_sips/results/2022-09-16-meeting.md b/_sips/results/2022-09-16-meeting.md
new file mode 100644
index 0000000000..e18fd2a2da
--- /dev/null
+++ b/_sips/results/2022-09-16-meeting.md
@@ -0,0 +1,13 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 16th September 2022
+partof: results
+proposals:
+ - url: https://github.com/scala/improvement-proposals/pull/47
+ name: SIP-47 - Clause Interleaving
+ result: under-review
+ - url: https://github.com/scala/improvement-proposals/pull/46
+ name: SIP-46 - Use Scala CLI to implement the 'scala' command
+ result: under-review
+---
+
diff --git a/_sips/results/2022-10-21-meeting.md b/_sips/results/2022-10-21-meeting.md
new file mode 100644
index 0000000000..41347c6274
--- /dev/null
+++ b/_sips/results/2022-10-21-meeting.md
@@ -0,0 +1,16 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 21st October 2022
+partof: results
+proposals:
+ - url: https://docs.scala-lang.org/sips/fewer-braces.html
+ name: SIP-44 - Fewer braces
+ result: accepted
+ - url: https://docs.scala-lang.org/sips/scala-cli.html
+ name: SIP-46 - Use Scala CLI to implement the 'scala' command
+ result: accepted
+ - url: https://docs.scala-lang.org/sips/clause-interleaving.html
+ name: SIP-47 - Clause Interleaving
+ result: accepted
+---
+
diff --git a/_sips/results/2022-11-18-meeting.md b/_sips/results/2022-11-18-meeting.md
new file mode 100644
index 0000000000..035164ad8b
--- /dev/null
+++ b/_sips/results/2022-11-18-meeting.md
@@ -0,0 +1,9 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 18th November 2022
+partof: results
+proposals:
+ - url: https://docs.scala-lang.org/sips/polymorphic-eta-expansion.html
+ name: SIP-49 - Polymorphic Eta-Expansion
+ result: accepted
+---
diff --git a/_sips/results/2023-02-17-meeting.md b/_sips/results/2023-02-17-meeting.md
new file mode 100644
index 0000000000..ede0dfc5bf
--- /dev/null
+++ b/_sips/results/2023-02-17-meeting.md
@@ -0,0 +1,9 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 17th February 2023
+partof: results
+proposals:
+ - url: https://github.com/scala/improvement-proposals/pull/54
+ name: SIP-51 - Drop Forwards Binary Compatibility of the Scala 2.13 Standard Library
+ result: accepted
+---
diff --git a/_sips/results/2023-03-17-meeting.md b/_sips/results/2023-03-17-meeting.md
new file mode 100644
index 0000000000..7c1ef1e50f
--- /dev/null
+++ b/_sips/results/2023-03-17-meeting.md
@@ -0,0 +1,9 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 17th March 2023
+partof: results
+proposals:
+ - url: https://docs.scala-lang.org/sips/scala-cli.html
+ name: SIP-46 - Scala CLI as default Scala command
+ result: accepted
+---
diff --git a/_sips/results/2023-04-21-meeting.md b/_sips/results/2023-04-21-meeting.md
new file mode 100644
index 0000000000..b522759d88
--- /dev/null
+++ b/_sips/results/2023-04-21-meeting.md
@@ -0,0 +1,12 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 21st April 2023
+partof: results
+proposals:
+ - url: https://docs.scala-lang.org/sips/quote-pattern-type-variable-syntax.html
+ name: SIP-53 - Quote pattern explicit type variable syntax
+ result: accepted
+ - url: https://docs.scala-lang.org/sips/multi-source-extension-overloads.html
+ name: SIP-54 - Multi-Source Extension Overloads
+ result: accepted
+---
diff --git a/_sips/results/2023-06-16-meeting.md b/_sips/results/2023-06-16-meeting.md
new file mode 100644
index 0000000000..0ad96e5ffb
--- /dev/null
+++ b/_sips/results/2023-06-16-meeting.md
@@ -0,0 +1,9 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 16th June 2023
+partof: results
+proposals:
+ - url: https://docs.scala-lang.org/sips/multi-source-extension-overloads.html
+ name: SIP-54 - Multi-Source Extension Overloads
+ result: accepted
+---
diff --git a/_sips/results/2023-07-21-meeting.md b/_sips/results/2023-07-21-meeting.md
new file mode 100644
index 0000000000..6d873e6717
--- /dev/null
+++ b/_sips/results/2023-07-21-meeting.md
@@ -0,0 +1,7 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 21st July 2023
+partof: results
+proposals: []
+---
+No voting was held on this meeting.
\ No newline at end of file
diff --git a/_sips/results/2023-09-11-meeting.md b/_sips/results/2023-09-11-meeting.md
new file mode 100644
index 0000000000..c7231e6d9b
--- /dev/null
+++ b/_sips/results/2023-09-11-meeting.md
@@ -0,0 +1,7 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 11th September 2023
+partof: results
+proposals: []
+---
+No voting was held on this meeting.
\ No newline at end of file
diff --git a/_sips/results/2023-10-20-meeting.md b/_sips/results/2023-10-20-meeting.md
new file mode 100644
index 0000000000..33abe5c90a
--- /dev/null
+++ b/_sips/results/2023-10-20-meeting.md
@@ -0,0 +1,9 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 20th October 2023
+partof: results
+proposals:
+ - url: https://docs.scala-lang.org/sips/binary-api.html
+ name: SIP-52 - Binary APIs
+ result: accepted
+---
diff --git a/_sips/results/2023-11-17-meeting.md b/_sips/results/2023-11-17-meeting.md
new file mode 100644
index 0000000000..fcb63c9e26
--- /dev/null
+++ b/_sips/results/2023-11-17-meeting.md
@@ -0,0 +1,9 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 17th November 2023
+partof: results
+proposals:
+ - url: https://docs.scala-lang.org/sips/match-types-spec.html
+ name: SIP-56 - Proper Specification for Match Types
+ result: accepted
+---
diff --git a/_sips/results/2023-12-15-meeting.md b/_sips/results/2023-12-15-meeting.md
new file mode 100644
index 0000000000..647b689123
--- /dev/null
+++ b/_sips/results/2023-12-15-meeting.md
@@ -0,0 +1,7 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 12th December 2023
+partof: results
+proposals: []
+---
+No voting was held on this meeting.
\ No newline at end of file
diff --git a/_sips/results/2024-01-19-meeting.md b/_sips/results/2024-01-19-meeting.md
new file mode 100644
index 0000000000..23f2f49c6a
--- /dev/null
+++ b/_sips/results/2024-01-19-meeting.md
@@ -0,0 +1,9 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 19th January 2024
+partof: results
+proposals:
+ - url: https://docs.scala-lang.org/sips/match-types-spec.html
+ name: SIP-56 - Proper Specification for Match Types
+ result: accepted as completed
+---
diff --git a/_sips/results/2024-04-19-meeting.md b/_sips/results/2024-04-19-meeting.md
new file mode 100644
index 0000000000..b5db00bc7a
--- /dev/null
+++ b/_sips/results/2024-04-19-meeting.md
@@ -0,0 +1,16 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 19th April 2024
+partof: results
+proposals:
+ - url: https://github.com/scala/improvement-proposals/pull/72
+ name: SIP-58 - Named Tuples
+ result: accepted
+ - url: https://github.com/scala/improvement-proposals/pull/79
+ name: SIP-62 - For comprehension improvements
+ result: accepted
+ - url: https://github.com/scala/improvement-proposals/pull/81
+ name: SIP-64 - Improve the syntax of context bounds and givens
+ result: accepted
+---
+SIP-61 and SIP-63 were discussed but no vote was held.
diff --git a/_sips/results/2024-05-24-meeting.md b/_sips/results/2024-05-24-meeting.md
new file mode 100644
index 0000000000..51bf1e0a34
--- /dev/null
+++ b/_sips/results/2024-05-24-meeting.md
@@ -0,0 +1,10 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 24th May 2024
+partof: results
+proposals:
+ - url: https://github.com/scala/improvement-proposals/pull/78
+ name: SIP-61 - Unroll default arguments for binary compatibility
+ result: accepted
+---
+SIP-64 was discussed but no vote was held.
diff --git a/_sips/results/2024-06-21-meeting.md b/_sips/results/2024-06-21-meeting.md
new file mode 100644
index 0000000000..9ebb1ca250
--- /dev/null
+++ b/_sips/results/2024-06-21-meeting.md
@@ -0,0 +1,10 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 21st June 2024
+partof: results
+proposals:
+ - url: https://github.com/scala/improvement-proposals/pull/47
+ name: SIP-47 - Clause interleaving
+ result: accepted
+---
+SIP-55, SIP-58, SIP-60, SIP-62, and SIP-64 were discussed but no vote was held.
diff --git a/_sips/results/2024-08-16-meeting.md b/_sips/results/2024-08-16-meeting.md
new file mode 100644
index 0000000000..73361aa923
--- /dev/null
+++ b/_sips/results/2024-08-16-meeting.md
@@ -0,0 +1,7 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 16th August 2024
+partof: results
+proposals: []
+---
+SIP-49, SIP-52, SIP-57, SIP-58, SIP-61, SIP-62, SIP-64, and SIP-66 were discussed but no vote was held.
diff --git a/_sips/results/2024-09-27-meeting.md b/_sips/results/2024-09-27-meeting.md
new file mode 100644
index 0000000000..bbb0bb8b81
--- /dev/null
+++ b/_sips/results/2024-09-27-meeting.md
@@ -0,0 +1,13 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 27th September 2024
+partof: results
+proposals:
+ - url: https://github.com/scala/improvement-proposals/pull/72
+ name: SIP-58 - Named Tuples
+ result: accepted
+ - url: https://github.com/scala/improvement-proposals/pull/81
+ name: SIP-64 - Improve the syntax of context bounds and givens
+ result: accepted
+---
+SIP-62 was discussed but no vote was held.
diff --git a/_sips/results/2024-11-15-meeting.md b/_sips/results/2024-11-15-meeting.md
new file mode 100644
index 0000000000..1a5da82052
--- /dev/null
+++ b/_sips/results/2024-11-15-meeting.md
@@ -0,0 +1,7 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 15th November 2024
+partof: results
+proposals: []
+---
+SIP-66 was discussed but no vote was held.
diff --git a/_sips/results/2024-12-20-meeting.md b/_sips/results/2024-12-20-meeting.md
new file mode 100644
index 0000000000..a9454f3250
--- /dev/null
+++ b/_sips/results/2024-12-20-meeting.md
@@ -0,0 +1,7 @@
+---
+layout: sip-meeting-results
+title: SIP Meeting Results - 20th December 2024
+partof: results
+proposals: []
+---
+SIP-62 and SIP-67 were discussed but no vote was held.
diff --git a/_sips/sip-submission.md b/_sips/sip-submission.md
deleted file mode 100644
index ec871ceadc..0000000000
--- a/_sips/sip-submission.md
+++ /dev/null
@@ -1,331 +0,0 @@
----
-layout: sips
-title: SIP Specification and Submission
----
-
-A **SIP** (_Scala Improvement Process_) is a process for submitting changes to
-the Scala language. Its main motivation is to become the primary mechanism to
-propose, discuss and implement language changes. In this process, all changes to
-the language go through design documents, called Scala Improvement Proposals
-(SIPs), which are openly discussed by a committee and only upon reaching a
-consensus are accepted to be merged into the Scala compiler.
-
-The aim of the Scala Improvement Process is to apply the openness and
-collaboration that have shaped Scala's documentation and implementation to the
-process of evolving the language. This document captures our guidelines,
-commitments and expectations regarding this process.
-
-## Why write a SIP?
-
-SIPs are key to making Scala better for the good of everyone. If you decide to
-invest the time and effort of putting a SIP forward and seeing it through, your
-efforts and time will shape and improve the language, which means that your
-proposal may impact the life of a myriad of developers all over the world,
-including those on your own team. For many, this aspect alone can be quite
-worthwhile.
-
-However, it's important to note that seeing a SIP through to its conclusion is
-an involved task. On the one hand, it takes time to convince people that your
-suggestions are a worthwhile change for hundreds of thousands of developers to
-accept. Particularly given the sheer volume of developers that could be affected
-by your SIP, SIP acceptance is conservative and carefully thought through.
-Typically, this includes many rounds of discussion with core Scala maintainers
-and the overall community, several iterations on the design of the SIP, and some
-effort at prototyping the proposed change. Often, it takes months of discussion,
-re-design, and prototyping for a SIP to be accepted and included in the Scala
-compiler. It is, therefore important to note that seeing a SIP through to its
-conclusion can be time-consuming and not all SIPs may end up in the Scala
-compiler, although they may teach us all something!
-
-If you’re motivated enough to go through this involved but rewarding process, go
-on with writing and keep on reading.
-
-## What's the process for submitting a SIP?
-
-There are four major steps in the SIP process:
-
-1. Initial informal discussion (2 weeks)
-2. Submission
-3. Formal presentation (up to 1 month)
-4. Formal evaluation (up to 6 months)
-
-### Initial informal discussion (2 weeks)
-
-Before submitting a SIP, it is required that you perform necessary preparations:
-
-Discuss your idea on the [Scala Contributors Page](https://contributors.scala-lang.org/) (currently, we suggest
-cross-posting on
-[Scala Improvement Process](https://contributors.scala-lang.org/c/sip) and
-[Language Design](https://contributors.scala-lang.org/c/language-design). This
-may change in the future.) Create a topic that starts with “Pre-SIP” and briefly
-describe what you would like to change and why you think it’s a good idea.
-
-Proposing your ideas on the mailing list is not an optional step. For every
-change to the language, it is important to gauge interest from the compiler
-maintainers and the community. Use this step to promote your idea and gather
-early feedback on your informal proposal. It may happen that experts and
-community members may have tried something similar in the past and may offer
-valuable advice.
-
-Within two weeks after your submission of the pre-SIP to the mailing list, the
-Process Lead will intervene and advise you whether your idea can be submitted as
-a SIP or needs more work.
-
-### Submission
-
-After receiving the green light from the Process Lead, you can write up your
-idea and submit it as a SIP.
-
-A SIP is a Markdown document written in conformance with the [process template](https://github.com/scala/docs.scala-lang/blob/master/_sips/sip-template.md).
-It ought to contain a clear specification of the proposed changes. When such
-changes significantly alter the compiler internals, the author is invited to
-provide a proof of concept. Delivering a basic implementation can speed up the
-process dramatically. Even compiler hackers find very difficult to predict the
-interaction between the design and the implementation, so the sooner we have an
-evidence of a working prototype that interacts with all the features in Scala,
-the better. Otherwise, committee members may feel that the proposed changes are
-impossible and automatically dismiss them. If your changes are big or somewhat
-controversial, don’t let people hypothesize about them and show results upfront.
-
-A SIP is submitted as a pull request against [the official Scala website
-repo](https://github.com/scala/docs.scala-lang). Within a week of receiving the
-pull request, the Process Lead will acknowledge your submission, validate it and
-engage into some discussions with the author to improve the overall quality of
-the document (if necessary).
-
-When you and the Process Lead agree on the final document, it is formally
-accepted for review: assigned a reviewer and scheduled for formal presentation.
-
-### Formal presentation (up to 1 month)
-
-During the next available SIP Committee meeting, the appointed reviewer presents
-the SIP to the committee and kick starts the initial discussion.
-
-If the committee agrees that following through the SIP is a good idea, then the
-following happens:
-
-1. The SIP is assigned a number.
-2. The SIP pull request is merged into the official Scala website repo, and the
-merged document becomes the official webpage of the proposal.
-3. An issue to discuss the SIP is opened at the official Scala website repo. Then,
-the reviewer submits the initial feedback from the committee.
-4. An implementation is requested (if not already present).
-
-Otherwise, the SIP is rejected. The reviewer submits the collected feedback as a
-comment to the pull request, and the pull request is closed.
-
-### Formal evaluation (up to 6 iterations)
-
-Evaluation of a SIP is done in iterations. The maximum number of iterations is
-six. These iterations take place in the SIP meetings and are usually monthly.
-However, they can last longer, in which case the author has more time to
-implement all the required changes.
-
-The committee decides the duration of the next iteration depending upon the
-feedback and complexity of the SIP. Consequently, authors have more time to
-prepare all the changes. If they finish their revision before the scheduled
-iteration, the Process Lead will reschedule it for the next available meeting.
-
-During every iteration, the appointed reviewer presents the changes (updated
-design document, progress with the implementation, etc) to the SIP Committee.
-Based on the feedback, the SIP is either:
-
-1. Accepted, in which case the committee asks the compiler maintainers to
- indicate the earliest version of Scala that can include the language change.
-2. Rejected, in which case the SIP is closed and no longer evaluated in the
- future.
-3. Under revision, in which case the author needs to continue the formal
- evaluation and address all the committee's feedback. Thus, the follow-up
- discussion is scheduled for the next iteration.
-3. Postponed, in which case the committee does not evaluate the proposal anymore
- and sets it aside under some conditions are met. Then, the SIP will be
- resubmitted. This situation happens when proposals entirely depend on another
- pending proposals and need their admission. In such cases, the dependent
- proposal is postponed until the Committee votes on the other one.
-
-If no changes have been made to a SIP in two iterations, it’s marked as dormant
-and both the PR and issue are closed. Dormant SIPs can be reopened by any
-person, be it the same or different authors, at which point it will start from
-the formal evaluation phase.
-
-### Merging the proposal
-
-If the SIP is accepted, the committee will propose a release date to the
-compiler maintainers, where the role of the committee ends. Accepted SIPs will
-then be merged under a flag. When SIPs introduce intricate changes and they
-cannot be merged under a flag, the compiler maintainers will merge it directly.
-
-## Structure of the process
-
-The SIP process involves the following parties:
-
-1. The SIP Author(s)
-2. The Process Lead
-3. The SIP Committee
-
-### The SIP Author(s)
-
-Authors are responsible for building consensus within the community and
-documenting dissenting opinions before the SIP is officially discussed by the
-SIP Committee. Their goal is to convince the committee that their proposal is
-useful and addresses pertinent problems in the language as well as interactions
-with already existing features. Authors can change over the life-cycle of the
-SIP.
-
-### The Process Lead
-
-The Process Lead is the responsible of the smooth running of SIPs and SLIPs. He
-or she appoints the committee members, calls the meetings monthly, assigns new
-proposals to the members, and ensures that all of them are discussed within a
-short period of time.
-
-### The SIP Committee
-
-The SIP Committee is an experienced group of people with knowledge of the
-compiler internals, responsible for the strategic direction of Scala. Members
-are tasked with (a) communicating with the community, (b) weighing in pros and
-cons of every proposal, and (c) accepting, postponing or rejecting the proposal.
-
-Committee members should be either individuals responsible for a specific part
-of the Scala codebase, committers or contributors of the Scala compiler.
-Exceptionally, members may also be important representatives of the community
-with a high technical knowledge to understand the implications of every proposal
-and participate into the discussions. New members are elected by existing
-members of the SIP Committee, based on their expertise and involvement in the
-community.
-
-The current committee members are:
-
-- Martin Odersky ([@odersky](https://github.com/odersky)), EPFL
-- Adriaan Moors ([@adriaanm](https://github.com/adriaanm)), Lightbend
-- Guillaume Martres ([@smarter](https://github.com/smarter)), EPFL
-- Heather Miller ([@heathermiller](https://github.com/heathermiller)), Carnegie Mellon University
-- Iulian Dragos ([@dragos](https://github.com/dragos)), Triplequote
-- Josh Suereth ([@jsuereth](https://github.com/jsuereth)), Google
-- Miles Sabin ([@milessabin](https://github.com/milessabin)), independent
-- Seth Tisue ([@SethTisue](https://github.com/SethTisue)), Lightbend
-- Sébastien Doeraene ([@sjrd](https://github.com/sjrd)), Scala Center
-
-The current Process Lead is:
-
-- Darja Jovanovic ([@darjutak](https://github.com/darjutak)), Scala Center
-
-### Reviewers
-
-The Process Lead assigns every proposal to a member of the committee, who
-becomes the reviewer. The main tasks of the reviewer are the following:
-
-1. Discuss unclear points with the authors,
-2. Help them address their issues and questions,
-3. Provide them feedback from the discussions in the meetings, and
-4. Explain the latest progress in every meeting.
-
-### SIP meetings
-
-SIP meetings are scheduled monthly by the Process Lead, and require a quorum of
-two-thirds (2/3) of the committee members. If the quorum is not reached the
-meeting is rescheduled.
-
-### Voting
-
-All SIP Committee members vote. They can either vote in the meeting or by
-casting their vote via email to the SIP Process Lead before the set deadline.
-
-SIP Committee members can vote "in favor", "against" or "abstain".
-
-For a SIP to be accepted, the following three requirements must be met:
-
-- At least 50% of the committee members vote in favor.
-- There are at least two-thirds "in favor" versus "against" votes.
-- Martin Odersky does not veto it.
-
-An alternative way to think of the two-thirds requirement is that the number of
-votes in favor must be at least twice the number of votes against. Abstentions
-are excluded in calculating a two-thirds vote.
-
-Note that, when calculating the lower bound, numbers round up. Therefore for a
-committee of 9 members, at least 50% means at least 5 members.
-
-The deadline to vote a proposal is decided on a case-by-case basis. The deadline
-will be decided by the committee members present at the last meeting and the SIP
-Process Lead, and will be made public right after the meeting.
-
-#### Examples
-
-Several voting situations are explained next.
-
-All of them assume that there are 9 committee members. The 50% requirement
-requires at least 5 members to vote in favor. We also assume that Martin does
-not veto them.
-
-| In favor | Against | Abstentions | Voting members | Result |
-| -------- | ------- | ----------- | -------------- | ------------ |
-| 6 | 2 | 1 | 8 | Accepted |
-| 5 | 3 | 1 | 8 | Not Accepted |
-| 5 | 2 | 2 | 7 | Accepted |
-
-In the first situation, the proposal is accepted because 6 is both greater than
-the 50% (5) and more than twice the votes against (2). In the second situation,
-the proposal meets the 50% requirement but fails the two-thirds requirement
-since 5 is less than twice the number of votes against, 3, therefore the
-proposal is not accepted. In the third situation, the proposal is accepted
-because 5 is equal to 50% of all the committee members and is greater than twice
-the number of votes against (2).
-
-### Responsibilities of the members
-
-- Review the proposals they are assigned to. The Process Lead will always notify
-them two weeks in advance, at minimum.
-- Play a role in the discussions, learn in advance about the topic if needed, and
-make up their mind in the voting process.
-- Decide which utilities should be inside the core module and are required by the
-compiler. The goal is to shrink it over time, and, where possible, move modules
-to the platform, that will be managed by the SLIP process.
-
-### Guests
-
-Experts in some fields of the compiler may be invited to concrete meetings as
-guests when discussing related SIPs. Their input would be important to discuss
-the current state of the proposal, both its design and implementation.
-
-## Proposal states
-
-The state of a proposal changes over time depending on the phase of the process
-and the decisions taken by the committee. A given proposal can be in one of
-several states:
-
-1. **Validated:** The Process Lead has validated the proposal and checked that
-meets all the formal requirements.
-2. **Numbered:** The committee agrees that the proposal is a valid document and
-it’s worth considering it. Then, the Process Lead gives it a number.
-3. **Awaiting review:** The proposal has been scheduled to be reviewed for a
-concrete date.
-4. **Under review:** Once the author has delivered a new version, the proposal will
-be under review until the next available SIP meeting takes place.
-5. **Under revision:** Authors are addressing the issues pinpointed by the
-committee or working on the implementation.
-6. **Dormant:** When a SIP has been under revision for more than two iterations
- and no progress has been made, the Process Lead will mark it as dormant (note
- that the committee does not have such privilege). This status means that the
- Process Lead will not assign its review in future meetings until authors
- provide the requested feedback or progress. Also, authors can also mark their
- proposals as dormant, and they are encouraged to do so if they think they
- will not have time for their update.
-7. **Postponed:** The SIP has been postponed under some concrete conditions. When these
-are met, the SIP can be resubmitted.
-8. **Rejected:** The SIP has been rejected with a clear and full explanation.
-9. **Accepted:** The SIP has been accepted and it’s waiting for the merge into the
-Scala compiler.
-
-## How do I submit? ##
-
-The process to submit is simple:
-
-* Fork the Scala documentation repository, [https://github.com/scala/docs.scala-lang](https://github.com/scala/docs.scala-lang).
-* Create a new SIP file in the `_sips/sips/`. Use the [S(L)IP template](https://github.com/scala/docs.scala-lang/blob/master/_sips/sip-template.md)
- * Make sure the new file follows the format: `YYYY-MM-dd-{title}.md`. Use the proposal date for `YYYY-MM-dd`.
- * Use the [Markdown Syntax](https://daringfireball.net/projects/markdown/syntax) to write your SIP.
- * Follow the instructions in the [README](https://github.com/scala/docs.scala-lang/) to build your SIP locally so you can ensure that it looks correct on the website.
-* Create a link to your SIP in the "pending sips" section of `index.md`
-* Commit your changes to your forked repository
-* Create a new [pull request](https://github.com/scala/docs.scala-lang/pull/new/gh-pages). This will notify the Scala SIP team.
diff --git a/_sips/sip-template.md b/_sips/sip-template.md
deleted file mode 100644
index b3caf4e276..0000000000
--- a/_sips/sip-template.md
+++ /dev/null
@@ -1,119 +0,0 @@
----
-layout: sip
-title: SIP-NN - SIP Title
-#vote-status: pending <- uncomment this line
-permalink: /sips/:title.html
-redirect_from: /sips/pending/{filename-without-md}.html
----
-
-**By: Author 1 and Author 2 and Author 3**
-
-This document is provided as a template to get you started. Feel free to add, augment,
-remove, restructure and otherwise adapt the structure for what you need after cloning it.
-The cloned document should be placed in sips/pending/_posts according to the naming
-conventions described in the [SIP tutorial](./sip-tutorial.html).
-
-## History
-
-| Date | Version |
-|---------------|---------------|
-| Feb 19th 2015 | Initial Draft |
-| Feb 20th 2015 | Alteration Details |
-
-## Introduction/Motivation/Abstract
-
-(feel free to rename this section to Introduction, Motivation, Abstract, whatever best suits
- your library proposal.)
-
-A high level overview of the library with:
-
-* Description of the scope/features of the library.
-* An explanation of the reason the library is needed, what's missing in the core libs
- that is supplied.
-* Simple code examples if they help clarify, note that there will be ample opportunity
- for more detailed code examples later in the SIP
-
-Think of the introduction as serving to describe the library addition in a way
-that lets a reader decide if this is what they are looking for, whether they think
-this is the right approach to supply the extra functionality, and whether they might
-want to get involved.
-
-## Motivating Examples
-
-### Examples
-
-Code heavy description of how the library functionality can be used.
-
-```scala
-// here is some example scala code, highlighted nicely
-import scala.concurrent._
-
-class Foo extends Bar {
- val x = 10
- def yo(name: String): String = s"hello $name"
-}
-```
-
-### Comparison Examples
-
-Code demonstrating why the library is needed, how equivalent functionality
-might be provided without it.
-
-### Counter-Examples
-
-What the library is not intended to be used for. Examples of what to avoid and
-why.
-
-## Design
-
-Discuss design decisions (including, as examples):
-
-* Reason about correctness of the implementation.
-* "Feel and fit" with existing core libraries.
-* Performance and threading considerations.
-* Naming of classes, traits, methods.
-* Footprint of API.
-* Potential conflicts with existing libraries, e.g. name clashes, IDE auto-import friction, etc.
-
-## Implementation
-
-Include consideration of the following:
-
-* Is this library intended to be bundled with the current core libs, or (recommended) live in
-a separate module distributed with the core distribution of Scala
-(e.g. parser combinators, reflection, etc.)
-* **Existing implementation(s)** (e.g. donor library, github project, etc.). Note that
-having an existing implementation library from which this will be drawn, and that people
-can download and try now, is highly recommended.
-* Time frame, target Scala version for inclusion.
-* Roll-out plan (start with external module, include in std distribution, move to core).
-* Other volunteers/contributors (with areas of expertise, github contact info, etc.)
-
-## Counter-Examples
-
-What the library is not intended to be used for. Examples of what to avoid and
-why.
-
-## Drawbacks
-
-Why should we *not* do this. Be honest, these questions will come out during the
-process anyway so it's better to get them out up front.
-
-## Alternatives
-
-* What other possibilities have been examined?
-* What is the impact of not implementing this proposal?
-
-## References
-
-1. [Existing (Donor) Project][1]
-2. [API Documentation][2]
-3. [Academic/Research papers/supporting material][3]
-4. [Alternative Libraries/Implementations][4]
-5. [Discussion forum/post/gitter/IRC][5]
-
-[1]: https://github.com "GitHub"
-[2]: https://www.scala-lang.org/api/ "Scaladoc"
-[3]: https://en.wikipedia.org/wiki/Academic_publishing "Academic/Research"
-[4]: https://github.com/dogescript/dogescript "Alternatives"
-[5]: https://gitter.im "Gitter"
diff --git a/_sips/sip-tutorial.md b/_sips/sip-tutorial.md
index 2696fd12af..95bb45b053 100644
--- a/_sips/sip-tutorial.md
+++ b/_sips/sip-tutorial.md
@@ -1,51 +1,90 @@
---
layout: sips
title: Writing a new SIP
+redirect_from: /sips/sip-template.html
---
-This tutorial details of how to write a new SIP and adding it to the website.
+This tutorial details of how to write a new Scala Improvement Proposal (SIP) and how to submit it.
+
+## Why write a SIP?
+
+SIPs are key to making Scala better for the good of everyone. If you decide to
+invest the time and effort of putting a SIP forward and seeing it through, your
+efforts and time will shape and improve the language, which means that your
+proposal may impact the life of a myriad of developers all over the world,
+including those on your own team. For many, this aspect alone can be quite
+worthwhile.
+
+However, it's important to note that seeing a SIP through to its conclusion is
+an involved task. On the one hand, it takes time to convince people that your
+suggestions are a worthwhile change for hundreds of thousands of developers to
+accept. Particularly given the sheer volume of developers that could be affected
+by your SIP, SIP acceptance is conservative and carefully thought through.
+
+It is important to note that seeing a SIP through to its
+conclusion can be time-consuming and not all SIPs may end up in the Scala
+compiler, although they may teach us all something!
+
+Last, but not least, delivering a basic implementation can speed up the
+process dramatically. Even compiler hackers find very difficult to predict the
+interaction between the design and the implementation, so the sooner we have an
+evidence of a working prototype that interacts with all the features in Scala,
+the better.
+
+If you’re motivated enough to go through this involved but rewarding process, go
+on with writing and keep on reading.
+
+The following sections provide an overview of the process, and guidelines on
+how to submit a proposal. The detailed process specification is available
+[here]({% link _sips/process-specification.md %}).
+
+## Overview of the process
+
+From being an idea to being part of the language, a SIP goes through several
+*stages* that indicate the “maturity” level of the SIP. The following diagram
+summarizes the purpose of each stage:
+
+
+
+0. **Pre-SIP** You should start by creating a discussion thread in the
+ [Scala Improvement Process](https://contributors.scala-lang.org/c/sip/13)
+ category of the Scala Contributors forum to gather initial community feedback
+ and support. The title of your discussion should start with "Pre-SIP". In
+ this discussion, the community might bring you alternative solutions to
+ the problem you want to solve, or possible bad interactions with other
+ features of the language. Eventually, these discussions may help you polish
+ your proposal.
+1. **Design** The next stage consists of submitting a detailed description of
+ your proposal for approval to the SIP Committee. See the section
+ [How do I submit?](#how-do-i-submit) to know the procedure and expected
+ format. Your proposal will first be reviewed by a small group of reviewers,
+ and eventually the full Committee will either approve it or reject it.
+2. **Implementation** If the Committee approved your proposal, you are
+ welcome to provide an implementation of it in the compiler so that it can
+ be shipped as an experimental feature. You may hit new challenges during the
+ implementation of the feature, or when testing it in practice. In such a
+ case, you should amend the proposal, which will be reviewed again by the
+ reviewers from the SIP Committee. Once the implementation is deemed stable,
+ the full Committee will vote again on the final state of the proposal.
+3. **Completed** If the Committee accepted the proposal, it will be shipped as
+ a stable feature in the next minor release of the compiler. The content of
+ the proposal may not change anymore.
## How do I submit? ##
-The process to submit is simple:
+The process to submit is the following:
-* Fork the [Scala documentation repository](https://github.com/scala/docs.scala-lang) and clone it.
-* Create a new SIP file in the `_sips/sips`. Use the [SIP template](https://github.com/scala/docs.scala-lang/blob/master/_sips/sip-template.md)
- * Make sure the new file follows the format: `YYYY-MM-dd-{title}.md`. Use the proposal date for `YYYY-MM-dd`.
+* Fork the [Scala improvement proposals repository](https://github.com/scala/improvement-proposals) and clone it.
+* Create a new branch off the `main` branch.
+* Copy the [SIP template](https://github.com/scala/improvement-proposals/blob/main/sip-template.md) into the directory `content/`
+ * Give a meaningful name to the file (e.g., `eta-expansion-of-polymorphic-functions.md`).
* Use the [Markdown Syntax](https://daringfireball.net/projects/markdown/syntax) to write your SIP.
- * Follow the instructions in the [README](https://github.com/scala/docs.scala-lang/blob/master/README.md) to build your SIP locally so you can ensure that it looks correct on the website.
-* Create a link to your SIP in the "pending sips" section of `index.md`.
+ * The template is provided to help you get started. Feel free to add, augment, remove, restructure and otherwise adapt the structure for what you need.
* Commit your changes and push them to your forked repository.
-* Create a new pull request. This will notify the Scala SIP team.
-
-
-## SIP Post Format ##
-
-First, create a new SIP file in the `_sips/sips` directory. Make sure the new file follows the format: `YYYY-MM-dd-{title}.md`. Where:
-* `YYYY` is the current year when the proposal originated.
-* `MM` is the current month (`01` = January, `12` = December) when the proposal originated.
-* `dd` is the day of the month when the proposal originated.
-* `{title}` is the title for the SIP.
+* Create a new pull request. This will notify the Scala SIP team, which will get back to you within a couple of weeks.
### Markdown formatting ###
Use the [Markdown Syntax](https://daringfireball.net/projects/markdown/syntax) to write your SIP.
-If you would like a starting point, clone the [SIP Template](./sip-template.html) in
-`_sips/sip-template.md` and use that.
-
-See the [source](https://github.com/scala/docs.scala-lang/blob/master/_sips/sip-template.md) for this document (`sip-tutorial.md`) for how to do syntax highlighting.
-
-```scala
-class Foo
-```
-
-
-## Testing changes ##
-
-Testing changes requires installing [Jekyll](https://jekyllrb.com/docs/installation/). Since this site is hosted on github pages, make sure you have [whatever version of Jekyll that github is running](https://help.github.com/articles/using-jekyll-with-pages#troubleshooting). As of the writing of this README, that is version >= 1.0.x.
-
-After the installation, you need to start up the local server. The
-[README](https://github.com/scala/docs.scala-lang/blob/master/README.md) gives
-a concise explanation on how to do it. When the server is running, view your
-changes at [https://localhost:4000/sips](https://localhost:4000/sips).
+See the content of the [SIP template](https://github.com/scala/improvement-proposals/blob/main/sip-template.md) as a starting point, and for various examples, including syntax highlighting of code snippets.
diff --git a/_sips/sips/2011-10-13-uncluttering-control.md b/_sips/sips/2011-10-13-uncluttering-control.md
deleted file mode 100644
index e1ceb5d790..0000000000
--- a/_sips/sips/2011-10-13-uncluttering-control.md
+++ /dev/null
@@ -1,123 +0,0 @@
----
-layout: sip
-title: SIP-12 - Uncluttering Scala’s syntax for control structures.
-
-vote-status: rejected
-vote-text: The committee votes unanimously to reject the change. The conclusion is that there is not a clear benefit for it and the required invested time and efforts would be too high. For more explanation, read the minutes.
-permalink: /sips/:title.html
-redirect_from: /sips/pending/uncluttering-control.html
----
-
-**By: Martin Odersky**
-
-## Motivation ##
-
-The more Scala code I write the more I get tripped up by the need to write conditions in if-then-else expressions and other control constructs in parentheses. I normally would not advocate syntax changes at this level, except that this has been the single syntax decision that feels worse for me the longer I use it.
-
-## Part 1: if ##
-
-Having to write parentheses is an unfortunate inheritance from C via Java. It makes code more cluttered than it could be. In C/C++/Java this was no big deal, but because Scala is much cleaner syntactically than these languages it starts to stick out like a sore thumb. This in particular because only one form of `if` comes with parentheses; if you use an if as a filter in a for expression or as a guard in a pattern, no parentheses are required.
-
-So, here is the proposal (for Scala 2.10):
-
-1. Introduce a new keyword, `then`.
-
-2. Allow the following alternative syntax form:
-
- if expression then expression [else expression]
-
-3. At some point in the future (there’s no rush) we could deprecate the form
-
- if (expression) expression else expression
-
- and then remove it.
-
-
-Once we have dealt with if, we should do the same thing with while, do-while and for.
-
-## Part 2: do-while ##
-
-do-while is easy. Simply do the following:
-
-1. Allow
-
- do expression while expression
-
- as syntax (i.e. drop the required parentheses around the condition).
-
-While loops and for loops are more tricky.
-
-## Part 3: while ##
-
-For while loops:
-
-1. Allow
-
- while expression do expression
-
- as syntax.We then have to deal with an ambiguity: What should we do with
-
- while (expression1) do expression2 while (expression3)
-
- ? I.e. a `do-while` loop inside an old-style `while` loop? Here’s a possible migration strategy.
-
-2. In Scala 2.10: Introduce
-
- while expression1 do expression2
-
- where `expression1` is not allowed to have parentheses at the outermost level (there’s no need to have them anyway). Also, emit a deprecation warning if the compiler comes across a do-while nested directly in an old-style while:
-
- while (expression1) do expression2 while expression3
-
- To write a `do-while` inside a `while` loop you will need braces, like this:
-
- while (expression1) { do expression2 while expression3 }
-
-3. In Scala 2.11: Disallow
-
- while (expression1) do expression2 while expression3
-
-4. In Scala 2.12: Drop the restriction introduced in 2.10. Conditions in a `while-do` can now be arbitrary expressions including with parentheses at the outside.
-
-## Part 4: for ##
-
-For-loops and for expressions can be handled similarly:
-
-1. Allow
-
- for enumerators yield expression
-
- as syntax. Enumerators are treated as if they were in braces, i.e. newlines can separate generators without the need for additional semicolons.
-
-2. Allow
-
- for enumerators do expression
-
- as syntax. Treat `do-while` ambiguities as in the case for `while`.
-
-3. At some point in the future: deprecate, and then drop the syntax
-
- for (enumerators) expression
- for {enumerators} expression
- for (enumerators) yield expression
- for {enumerators} yield expression
-
-## Examples ##
-
-Here are some examples of expressions enabled by the changes.
-
- if x < y then x else y
-
- while x >= y do x /= 2
-
- for x <- 1 to 10; y <- 1 to 10 do println(x * y)
-
- for
- x <- 0 until N
- y <- 0 until N
- if isPrime(x + y)
- yield (x, y)
-
-## Discussion ##
-
-The new syntax removes more cases than it introduces. It also removes several hard to remember and non-orthogonal rules where you need parentheses, where you can have braces, and what the difference is. It thus makes the language simpler, more regular, and more pleasant to use. Some tricky situations with migration can be dealt with; and should apply anyway only in rare cases.
diff --git a/_sips/sips/2012-03-09-self-cleaning-macros.md b/_sips/sips/2012-03-09-self-cleaning-macros.md
deleted file mode 100644
index 32d50df49f..0000000000
--- a/_sips/sips/2012-03-09-self-cleaning-macros.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-layout: sip
-title: SIP-16 - Self-cleaning Macros
-
-vote-status: rejected
-vote-text: The proposal is rejected unanimously because Scala Meta, the successor metaprogramming tool, is coming soon. For more explanation, read the minutes.
-permalink: /sips/:title.html
-redirect_from: /sips/pending/self-cleaning-macros.html
----
-
-
-This SIP is an embedded google document. If you have trouble with this embedded document, you can visit the [document on Google Docs](https://docs.google.com/document/d/1O879Iz-567FzVb8kw6N5OBpei9dnbW0ZaT7-XNSa6Cs/edit?hl=en_US).
-
-
diff --git a/_sips/sips/2012-03-30-source-locations.md b/_sips/sips/2012-03-30-source-locations.md
deleted file mode 100644
index b80c95b23b..0000000000
--- a/_sips/sips/2012-03-30-source-locations.md
+++ /dev/null
@@ -1,66 +0,0 @@
----
-layout: sip
-title: SIP-19 - Implicit Source Locations
-vote-status: rejected
-vote-text: The proposal is rejected. We expect this to be easily implemented using macros without going through a full SIP. A modern implementation can be found here.
-permalink: /sips/:title.html
-redirect_from: /sips/pending/source-locations.html
----
-
-**Philipp Haller**
-
-**30 March 2012**
-
-## Motivation ##
-
-The Scala compiler's error messages would be nearly useless if they wouldn't provide the corresponding source location, that is, file name, line number, and (some representation of the) character offset, of each error. However, source locations are also very useful outside of the compiler. Libraries and frameworks routinely deal with application- or system-level errors (usually in the form of exceptions), logging, debugging support through tracing, etc. All of these aspects greatly benefit from source location information.
-
-Moreover, embedded domain-specific languages often depend upon source location information for providing useful error messages. Domain-specific languages that employ staging for code generation can use source locations for debug information in the generated code.
-
-This proposal discusses a minimal extension of Scala's implicit parameters to provide access to the source location of method invocations. The design is analogous to the way manifests are generated by the compiler, and should therefore be natural to anyone familiar with manifests in Scala.
-
-## Example ##
-
-To obtain the source location for each invocation of a method `debug`, say, one adds an implicit parameter of type `SourceLocation`:
-
- def debug(message: String)(implicit loc: SourceLocation): Unit = {
- println("@" + loc.fileName + ":" + loc.line + ": " + message)
- }
-
-This means that inside the body of the `debug` method, we can access the source location of its current invocation through the `loc` parameter. For example, suppose
-we are invoking `debug` on line `34` in a file `"MyApp.scala"`:
-
- 34: if (debugEnabled) debug("debug message")
-
-Assuming `debugEnabled` evaluates to `true`, the above expression would lead to the following output:
-
- @MyApp.scala:34: debug message
-
-## The SourceLocation Trait ##
-
-The `SourceLocation` trait is a new type member of the `scala.reflect` package. It has the following members:
-
- trait SourceLocation {
- /** The name of the source file */
- def fileName: String
-
- /** The line number */
- def line: Int
-
- /** The character offset */
- def charOffset: Int
- }
-
-## Specification ##
-
-Implicit source locations are supported through the following small addition to Scala's implicit rules.
-
-If an implicit parameter of a method or constructor is of type `SourceLocation`, a source location object is determined according to the following rules.
-
-First, if there is already an implicit argument of type `SourceLocation`, this argument is selected. Otherwise, an instance of `SourceLocation` is generated by invoking the `apply` method of the object `scala.reflect.SourceLocation`, passing the components of the source location as arguments.
-
-## Implementation ##
-
-An implementation of this proposal can be found at: [https://github.com/phaller/scala/tree/topic/source-location](https://github.com/phaller/scala/tree/topic/source-location)
-
-An extension of this proposal is also part of Scala-Virtualized. The extension adds a subtrait `SourceContext` which in addition provides access to information, such as variable names in the context of a method invocation. More information can be found at: [https://github.com/TiarkRompf/scala-virtualized/wiki/SourceLocation-and-SourceContext](https://github.com/TiarkRompf/scala-virtualized/wiki/SourceLocation-and-SourceContext)
diff --git a/_sips/sips/2013-05-31-improved-lazy-val-initialization.md b/_sips/sips/2013-05-31-improved-lazy-val-initialization.md
deleted file mode 100644
index 1efe9e9eab..0000000000
--- a/_sips/sips/2013-05-31-improved-lazy-val-initialization.md
+++ /dev/null
@@ -1,749 +0,0 @@
----
-layout: sip
-title: SIP-20 - Improved Lazy Vals Initialization
-vote-status: dormant
-vote-text: This proposal lacks an implementation for Scalac and is looking for a new owner.
-permalink: /sips/:title.html
-redirect_from: /sips/pending/improved-lazy-val-initialization.html
----
-
-**By: Aleksandar Prokopec, Dmitry Petrashko, Miguel Garcia, Jason Zaugg, Hubert Plociniczak, Viktor Klang, Martin Odersky**
-
-
-## Abstract ##
-
-This SIP describes the changes in the lazy vals initialization mechanism that address some of the unnecessary deadlock scenarios. The newly proposed lazy val initialization mechanism aims to eliminate the acquisition of resources during the execution of the lazy val initializer block, thus reducing the possibility of a deadlock. The concrete deadlock scenarios that the new lazy val initialization scheme eliminates are summarized below.
-
-The changes in this SIP have previously been discussed in depth on the mailing lists \[[1][1]\] \[[2][2]\] \[[9][9]\] \[[10][10]\].
-
-
-## Description ##
-
-The current lazy val initialization scheme uses double-checked locking to initialize the lazy val only once. A separate volatile bitmap field is used to store the state of the lazy val - a single bit in this bitmap denotes whether the lazy val is initialized or not.
-Assume we have the following declaration.
-
- final class LazyCell {
- lazy val value =
- }
-
-Here is an example of a manually written implementation equivalent to what the compiler currently does:
-
- final class LazyCell {
- @volatile var bitmap_0: Boolean = false
- var value_0: Int = _
- private def value_lzycompute(): Int = {
- this.synchronized {
- if (!bitmap_0) {
- value_0 =
- bitmap_0 = true
- }
- }
- value_0
- }
- def value = if (bitmap_0) value_0 else value_lzycompute()
- }
-
-We now describe several deadlock scenarios in an attempt to classify deadlocks related to the current lazy val initialization implementation.
-
-### No circular dependencies ###
-
-Assume there are two objects A and B with lazy vals `a0` and `a1`, and `b`, respectively:
-
- object A {
- lazy val a0 = B.b
- lazy val a1 = 17
- }
-
- object B {
- lazy val b = A.a1
- }
-
-The initialization block of `a0` above refers to `b` in B, and the initialization of `B.b` refers to `A.a1`. While a circular dependency exists between these two objects, there is no circular dependency **between specific lazy vals** `a0`, `a1` and `b`.
-
-In the scheme, there exists a possibility of a deadlock if thread Ta attempts to initialize `A.a0` and thread Tb attempts to initialize `B.b`. Assume that both Ta and Tb start their synchronized blocks simultaneously. A deadlock can occur due to each thread trying to grab the lock of the other object, while holding their own lock until the initialization completes.
-
-This SIP attempts to address this issue.
-
-### Circular dependencies ###
-
-Assume there are two objects A and B with lazy vals `a` and `b` respectively, where `a` needs `b` for initialization and vice versa. The current implementation scheme can cause a deadlock in this situation. Furthermore: in a single threaded scenario, circular dependencies between lazy vals lead to stack overflows with the current implementation:
-
- scala> object Test {
- | object A { lazy val a: Int = B.b }
- | object B { lazy val b: Int = A.a }
- | }
- defined object Test
-
- scala> Test
- res0: Test.type = Test$@6fd1046d
-
- scala> Test.A.a
- java.lang.StackOverflowError
-
-This is considered erroneous code, and this SIP does not attempt to address this.
-
-### No circular dependencies with other synchronization constructs ###
-
-Consider the declaration of the following lazy val:
-
- class A { self =>
- lazy val x: Int = {
- val t = new Thread() {
- override def run() { self.synchronized {} }
- }
- t.start()
- t.join()
- 1
- }
- }
-
-In the source there appears to be no circular dependency between the lazy val initialization block and the other synchronization construct, so there should be no reason for deadlock. As long as thread `t` completes a condition that the caller depends on and eventually lets go of the current object `self`, the lazy val should be able to initialize itself.
-
-With the current initialization scheme, however, initializing `x` causes a deadlock. The calling thread initializing `x`, holds the monitor of the current object `self`. The same monitor is needed by thread `t`, since it also synchronizes on `self`, thus causing a deadlock.
-
-This SIP attempts to address this issue.
-
-The thread that fulfills the condition that the lazy val initializer block suspends on could on the other hand permanently grab a hold of the monitor of the `self` object. Although this is not strictly speaking a deadlock, it is worth mentioning that the current lazy val initialization implementation might not complete in the following scenario case.
-
- class A { self =>
- val latch = new java.util.concurrent.CountDownLatch(1)
- val t = new Thread() {
- override def run() {
- latch.countDown()
- self.synchronized { while (true) {} }
- }
- }
- t.start()
- lazy val x: Int = {
- latch.await()
- 1
- }
- x
- }
-
-This SIP does not attempt to solve this issue - lazy val initialization semantics assume that the `self` object monitor is available or can be made available throughout the lazy val initialization.
-
-### Circular dependencies with other synchronization constructs ###
-
-Consider the declaration of the following lazy val:
-
- lazy val x: Int = {
- val t = new Thread() {
- override def run() { println(x) }
- }
- t.start()
- t.join()
- 1
- }
-
-In this code, the lazy val initialization block suspends until a condition is fulfilled. This condition can only be fulfilled by reading the value of lazy val `x` - another thread that is supposed to complete this condition cannot do so. Thus, a circular dependency is formed, and the lazy val cannot be initialized. Similar problems can arise with Scala singleton object initialization \[[3][3]\] when creating threads from the singleton object constructor and waiting for their completion, and with static initializer blocks in Java \[[4][4]\] \[[5][5]\].
-
-Note that this problem can also happen if two separate threads try to initialize two singleton objects that refer to each other, which is somewhat more severe. The rule of the thumb for programmers should be - singleton objects should not refer to each other during initialization.
-
-This is considered an anti-pattern, and this SIP does not attempt to address these issues.
-
-## Implementation ##
-
-The solution to the problems that this SIP attempts to address is based on avoiding the acquisition of the current object monitor during the time that the lazy val initializer block executes. Instead of executing the initializer block from within a synchronized block, the synchronized block is run twice, once at the beginning to publicize the information that the initializer block is being run and once after the initializer block to publicize the information that the lazy val field has been computed and assigned. The new scheme will require maintaining 2 bits per lazy field instead of 1, as in the current implementation.
-We will refer to the existing, current lazy val initialization implementation as V1.
-
-### Version V2 ###
-
-Here is an example of manually written implementation for the `LazyCell` class from the previous section:
-
- class LazyCell {
- @volatile var bitmap_0: Int = 0
- var value_0: Int = _
- private def value_lzycompute(): Int = {
- this.synchronized {
- if (bitmap_0 == 0) {
- bitmap_0 = 1
- } else {
- while (bitmap_0 == 1) {
- this.wait()
- }
- return value_0
- }
- }
- val result =
- this.synchronized {
- value_0 = result
- bitmap_0 = 3
- this.notifyAll()
- }
- value_0
- }
- def value = if (bitmap_0 == 3) value_0 else value_lzycompute()
- }
-
-The state of the lazy val is represented with 3 values: 0, 1 and 3. Note that only 2 bits are sufficient to represent them but we use an entire integer here for purposes of clarity. The state 0 represents a non-initialized lazy val. The state 1 represents the lazy val that is currently being initialized by some thread. The state 3 represents the lazy val that has been initialized.
-
-The first-arriving thread sets the state 1 from the synchronized block, leaves the synchronized block and proceeds by executing the initializer block. Subsequently arriving threads enter the synchronized block, see state 1 and `wait` until they are notified that the lazy val has been assigned. The first-arriving thread sets the state to 3 and notifies them after it computes the result and enters the second synchronized block.
-
-### Version V3 - the `notifyAll` improvement ###
-
-As noted in the previous discussions \[[1][1]\] \[[2][2]\] \[[6][6]\] \[[7][7]\], the `notifyAll` call in the proposed implementation bears a significant cost - in the uncontended case it slows down the initialization by a factor of at least 4x measured on a 3.4 GHz i7-2600 and JDK 7 update 4.
-
-Therefore, we propose the following implementation that avoids calling `notifyAll` unless the first-arriving thread knows that there are concurrent readers of the lazy val. We introduce the fourth state corresponding to the bitmap value 2, that denotes that there are concurrent readers of the lazy val. The first-arriving thread only calls the `notifyAll` if it finds state 2 in the second synchronized block.
-
- class LazyCell {
- @volatile var bitmap_0 = 0
- var value_0: Int = _
- private def value_lzycompute(): Int = {
- this.synchronized {
- (bitmap_0: @annotation.switch) match {
- case 0 =>
- bitmap_0 = 1
- case 1 =>
- bitmap_0 = 2
- do this.wait() while (bitmap_0 == 2.toByte)
- return value_0
- case 2 =>
- do this.wait() while (bitmap_0 == 2.toByte)
- return value_0
- case 3 =>
- return value_0
- }
- }
- val result =
- this.synchronized {
- val oldstate = bitmap_0
- value_0 = result
- bitmap_0 = 3
- if (oldstate == 2) this.notifyAll()
- }
- value_0
- }
- def value = if (bitmap_0 == 3) value_0 else value_lzycompute()
- }
-
-Measured on the same machine, this change seems to be 50% slower than the current lazy val implementation for the uncontended case.
-
-### Version V4 - the CAS improvement ###
-
-Each exit or entrance to a synchronized block in principle requires one atomic instruction, amounting to roughly 4 atomic instructions per lazy val initialization. This can be reduced by using the CAS instruction to switch between lazy val states.
-Here is an example of a simple implementation obtained by extending the `AtomicInteger` class:
-
- class LazyCell
- extends java.util.concurrent.atomic.AtomicInteger {
- var value_0: Int = _
- @tailrec final def value(): Int = (get: @switch) match {
- case 0 =>
- if (compareAndSet(0, 1)) {
- val result =
- value_0 = result
- if (getAndSet(3) != 1) synchronized { notify() }
- result
- } else value()
- case 1 =>
- compareAndSet(1, 2)
- synchronized {
- while (get != 3) wait()
- notify()
- }
- value_0
- case 2 =>
- synchronized {
- while (get != 3) wait()
- notify()
- }
- value_0
- case 3 => value_0
- }
- }
-
-This implementation has the following advantages:
-- it seems to have the same initialization performance as the current implementation, in the uncontended case
-- it relies less on synchronized blocks, needing them only in case of contention, thus being less prone to deadlocks
-
-Some disadvantages:
-- we cannot always extend `AtomicInteger`, some classes already inherit something else
-- in the contended worst-case, this scheme is equally prone to deadlocks, because it needs to acquire the synchronized block
-
-However, in the more general setting where there are two or more lazy val fields in an object:
-- the overall memory footprint could possibly increase - we would spend a minimum of 4 bytes per bitmap on first lazy val, where this was previously 1 byte
-- in a setting with multiple bitmaps or an existing base class, we cannot extend `AtomicInteger` (which internally uses `Unsafe` directly), and instead need to use `AtomicIntegerFieldUpdater`s that are slower due to extra checks
-- in a setting with multiple lazy val fields, we can no longer use `getAndSet` in the initialization (concurrent accesses to other lazy fields may modify the bitmap - we have to read and recompute the expected bitmap state) - we need a `compareAndSet` and have some retry-logic (see the `complete` method below), which is slower
-- due to the restrictions on the `AtomicIntegerFieldUpdater`s, we would need to make the `bitmap_0` field publicly visible on the byte-code level, which might be an issue for Java code interfacing with Scala code
-- it is much more complicated than the 2 synchronized blocks implementation
-
-Here is a more general implementation(V4-general), that is slower in the uncontended case than both the current implementation (V1) and the proposed implementation with synchronized blocks (V3). This implementation is, however, in the contended case twice as fast than the current implementation (V1).
-See the evaluation section for more information.
-
- class LazyCellBase { // in a Java file - we need a public bitmap_0
- public static AtomicIntegerFieldUpdater arfu_0 =
- AtomicIntegerFieldUpdater.newUpdater(LazyCellBase.class, "bitmap_0");
- public volatile int bitmap_0 = 0;
- }
-
- final class LazyCell extends LazyCellBase {
- import LazyCellBase._
- var value_0: Int = _
- @tailrec final def value(): Int = (arfu_0.get(this): @switch) match {
- case 0 =>
- if (arfu_0.compareAndSet(this, 0, 1)) {
- val result =
- value_0 = result
-
- @tailrec def complete(): Unit = (arfu_0.get(this): @switch) match {
- case 1 =>
- if (!arfu_0.compareAndSet(this, 1, 3)) complete()
- case 2 =>
- if (arfu_0.compareAndSet(this, 2, 3)) {
- synchronized { notifyAll() }
- } else complete()
- }
-
- complete()
- result
- } else value()
- case 1 =>
- arfu_0.compareAndSet(this, 1, 2)
- synchronized {
- while (arfu_0.get(this) != 3) wait()
- }
- value_0
- case 2 =>
- synchronized {
- while (arfu_0.get(this) != 3) wait()
- }
- value_0
- case 3 => value_0
- }
- }
-
-
-### Version 5 - retry in case of failure ###
-
-The current Scala semantics demand retrying the initialization in case of failure.
-The four versions presented above provide good performance characteristics in benchmarks, but may leave threads waiting forever due to failed initializations, thus leaking threads. Consider this example:
-
- class LazyCell {
- private var counter = -1
- lazy val value = {
- counter = counter + 1
- if(counter < 42)
- throw null
- else 0
- }
- }
-
-In this case, the first attempt to initialize the cell would fail. In version 4 this will leave the bitmap with a value still indicating that there's a thread currently computing the value. All the threads trying to access the value would wait for this (non-existent) thread to finish computation, causing the application to leak threads.
-
-In order to maintain current Scala semantics, we need to correctly handle failed initializations. Version 5 presented below, does this correctly:
-
-
- class LazyCellBase { // in a Java file - we need a public bitmap_0
- public static AtomicIntegerFieldUpdater arfu_0 =
- AtomicIntegerFieldUpdater.newUpdater(LazyCellBase.class, "bitmap_0");
- public volatile int bitmap_0 = 0;
- }
-
- final class LazyCell extends LazyCellBase {
- import LazyCellBase._
- var value_0: Int = _
- @tailrec final def value(): Int = (arfu_0.get(this): @switch) match {
- case 0 =>
- if (arfu_0.compareAndSet(this, 0, 1)) {
- val result =
- try {} catch {
- case x: Throwable =>
- complete(0);
- throw x
- }
- value_0 = result
-
- @tailrec def complete(newState: Int): Unit = (arfu_0.get(this): @switch) match {
- case 1 =>
- if (!arfu_0.compareAndSet(this, 1, newState)) complete()
- case 2 =>
- if (arfu_0.compareAndSet(this, 2, newState)) {
- synchronized { notifyAll() }
- } else complete()
- }
-
- complete(3)
- result
- } else value()
- case 1 =>
- arfu_0.compareAndSet(this, 1, 2)
- synchronized {
- while (arfu_0.get(this) != 3) wait()
- }
- value_0
- case 2 =>
- synchronized {
- while (arfu_0.get(this) != 3) wait()
- }
- value_0
- case 3 => value_0
- }
- }
-
-This version is basically the same as Version 4, but it handles retries in accordance with current Scala specification.
-Unfortunately, this comes with a slight performance slowdown. See the evaluation section for more information.
-
-
-### Version 6 - No synchronization on `this` and concurrent initialization of fields ###
-
-Note that the current lazy val initialization implementation is robust against the following scenario, in which the initialization block starts an asynchronous computation attempting to indefinitely grab the monitor of the current object.
-
- class A { self =>
- lazy val x: Int = {
- (new Thread() {
- override def run() = self.synchronized { while (true) {} }
- }).start()
- 1
- }
- }
-
-In the current implementation, the monitor is held throughout the lazy val initialization and released once the initialization block completes.
-All versions proposed above, release the monitor during the initialization block execution and re-acquire it back, so the code above could stall indefinitely.
-
-Additionally, usage of `this` as synchronization point may disallow concurrent initialization of different lazy vals in the same object. Consider the example below:
-
- class TwoLazies {
- lazy val slow = { Thread.sleep(100000); 0}
- lazy val fast = 1
- lazy val bad: Int = {
- (new Thread() {
- override def run() = self.synchronized { while (true) {} }
- }).start()
- 1
- }
- }
-
-Although the two `slow` and `fast` vals are independent, `fast` is required to
-wait for `slow` to be computed. This is due to the fact that they both
-synchronize on `this` for the entire initialization in the current
-implementation.
-
-In the versions presented above, a single call to `bad` may lead to the monitor
-for `this` being held forever, making calls to `slow` and `fast` also block
-forever.
-
-Note that these interactions are very surprising to users as they leak the
-internal limitations of the lazy val implementation.
-
-To overcome these limitations we propose a version that does not synchronize on
-`this` and instead uses external monitor-objects that are used solely for
-synchronization.
-
- final class LazyCell {
- import dotty.runtime.LazyVals
- var value_0: Int = _
- private var bitmap = 0
- @static private bitmap_offset = LazyVals.getOffset(classOf[LazyCell], "bitmap")
- def value(): Int = {
- var result: Int = 0
- var retry: Boolean = true
- val fieldId: Int = 0 // id of lazy val
- var flag: Long = 0L
- while retry do {
- flag = LazyVals.get(this, bitmap_offset)
- LazyVals.STATE(flag, 0) match {
- case 0 =>
- if LazyVals.CAS(this, bitmap_offset, flag, 1) {
- try {result = } catch {
- case x: Throwable =>
- LazyVals.setFlag(this, bitmap_offset, 0, fieldId)
- throw x
- }
- value_0 = result
- LazyVals.setFlag(this, bitmap_offset, 3, fieldId)
- retry = false
- }
- case 1 =>
- LazyVals.wait4Notification(this, bitmap_offset, flag, fieldId)
- case 2 =>
- LazyVals.wait4Notification(this, bitmap_offset, flag, fieldId)
- case 3 =>
- retry = false
- result = $target
- }
- }
- result
- }
- }
-
-This implementation relies on the helper functions provided in \[[11][11]\]
-module. The most important of these functions, `wait4Notification` and
-`setFlag`, are presented below:
-
- def setFlag(t: Object, offset: Long, v: Int, fieldId: Int) = {
- var retry = true
- while (retry) {
- val cur = get(t, offset)
- if (STATE(cur) == 1) retry = CAS(t, offset, cur, v)
- else {
- // cur == 2, somebody is waiting on monitor
- if (CAS(t, offset, cur, v)) {
- val monitor = getMonitor(t, fieldId)
- monitor.synchronized {
- monitor.notifyAll()
- }
- retry = false
- }
- }
- }
- }
-
- def wait4Notification(t: Object, offset: Long, cur: Long, fieldId: Int) = {
- var retry = true
- while (retry) {
- val cur = get(t, offset)
- val state = STATE(cur)
- if (state == 1) CAS(t, offset, cur, 2)
- else if (state == 2) {
- val monitor = getMonitor(t, fieldId)
- monitor.synchronized {
- monitor.wait()
- }
- }
- else retry = false
- }
- }
-
- val processors: Int = java.lang.Runtime.getRuntime.availableProcessors()
- val base: Int = 8 * processors * processors
- val monitors: Array[Object] = (0 to base).map {
- x => new Object()
- }.toArray
-
- def getMonitor(obj: Object, fieldId: Int = 0) = {
- var id = (java.lang.System.identityHashCode(obj) + fieldId) % base
- if (id < 0) id += base
- monitors(id)
- }
-
-This implementation has the following advantages compared to previous version:
-- it allows concurrent initialization of independent fields
-- it does not interact with user-written code that synchronizes on `this`
-- it does not require expanding monitor on the object to support `notifyAll`
-
-Some disadvantages:
-- the `Unsafe` class, used internally has a disadvantage that it can be disallowed with a custom `SecurityManager`.
-Note that this class is extracted from other place in standard library that uses it: scala.concurrent.util.Unsafe.instance
-- it requires usage of `identityHashCode` that is stored for every object inside object header.
-- as global arrays are used to store monitors, seemingly unrelated things may create contention. This is addressed in detail in evaluation section.
-
-Both absence of monitor expansion and usage of `identityHashCode` interact with
-each other, as both of them operate on the object header. \[[12][12]\] presents
-the complete graph of transitions between possible states of the object header.
-What can be seen from this transition graph is that in the contended case,
-versions V2-V5 were promoting object into the worst case, the `heavyweight
-monitor` object, while the new scheme only disables biasing.
-
-Note that under the schemes presented here, V2-V5, this change only happens in
-the event of contention and happens per-object.
-
-### Non-thread-safe lazy vals ###
-While the new versions introduce speedups in the contended case, they do
-generate complex byte-code and this may lead to the new scheme being less
-appropriate for lazy vals that are not used in concurrent setting. In order to
-perfectly fit this use-case we propose to introduce an encoding for
-single-threaded lazy vals that is very simple and efficient:
-
- final class LazyCell {
- var value_0 = 0
- var flag = false
- def value =
- if (flag) value_0
- else {
- value_0 = ;
- flag = true;
- }
- }
-
-This version is faster than all other versions on benchmarks but does not correctly handle safe publication in the case of multiple threads. It can be used in applications that utilize multiple threads if some other means of safe publication is used instead.
-
-### Elegant Local lazy vals ###
-Aside from lazy vals that are fields of objects, scala supports local lazy vals, defined inside methods:
-
- def method = {
- lazy val s =
- s
- }
-
-Currently, they use such encoding(we will call it L1):
-
- def method = {
- var @volatile flag: Byte = 0.toByte
- var s_0 = 0
- def s = {
- if(flag == 0){
- this.synchronized{
- if (flag == 0) {
- s_0 =
- flag = 1
- }
- }
- s_0
- }
- s
- }
-
-Which is later translated by subsequent phases to:
-
- private def method$s(flag: VolatileByteRef, s_0: IntRef) = {
- if(flag.value == 0){
- this.synchronized{
- if (flag.value == 0) {
- s_0.value =
- flag.value = 1
- }
- }
- s_0.value
- }
-
- def method = {
- var flag = new VolatileByteRef(0)
- var s_0 = new IntRef(0)
- method$s(flag, s_0)
- }
-
-
-
-The current implementation has several shortcomings:
- - it allocates two boxes
- - it synchronizes on `this`. This is most severe in case of lambdas, as lambdas do not introduce a new `this`.
-
-We propose a new scheme, that is both simpler in implementation and is more efficient and slightly more compact.
-The scheme introduces new helper classes to the standard library: such as `dotty.runtime.LazyInt`\[[17][17]\] and uses them to implement the local lazy val behavior.
-
- class LazyInt {
- var value: Int = _
- @volatile var initialized: Boolean = false
- }
-
- private def method$s(holder: LazyInt) = {
- if(!holder.initialized){
- holder.synchronized{
- if (!holder.initialized) {
- holder.value =
- holder.initialized = true
- }
- }
- holder.value
- }
-
- def method = {
- var holder = new LazyInt()
- method$s(holder)
- }
-
-This solves the problem with deadlocks introduced by using java8 lambdas.\[[14][14]\]
-
-
-### Language change ###
-To address the fact that we now have both thread safe and single-threaded lazy vals,
-we propose to bring lazy vals in sync with normal vals with regards to usage of `@volatile` annotation.
-
-In order to simplify migration, Scalafix the migration tool that will be used to migrate between versions of Scala, including Dotty, supports a `VolatileLazyVal` rewrite that adds `@volatile` to all `lazy vals` present in the codebase.
-
-
-## Evaluation ##
-
-We focus on the memory footprint increase, the performance comparison and byte-code size. Note that the fast path (i.e. the cost of accessing a lazy val after it has been initialized) stays the same as in the current implementation. Thus, the focus of our measurements is on the overheads in the lazy val initialization in both the uncontended and the contended case.
-The micro-benchmarks used for evaluation are available in a GitHub repo \[[6][6]\] and the graphs of the evaluation results are available online \[[7][7]\], \[[18][18]\], \[[19][19]\] . We used the ScalaMeter tool for measurements \[[9][9]\].
-
-### Memory usage footprint ###
-
-We expect that the proposed changes will not change the memory footprint for most objects that contain lazy vals. Each lazy val currently requires 4 or 8 bytes for the field, and an additional bit in the bitmap. As soon as the first bit is introduced into the bitmap, 1 additional byte is allocated for the object.
-
-Since we now use 2 bits per lazy val field instead of 1, for classes having 4 or less lazy val field declarations the memory footprint per instance will thus not grow. For classes having more lazy val field declarations the memory footprint per instance will in most cases not grow since the objects have to be aligned to an 8 byte boundary anyway.
-
-We measured the memory footprint of an array of objects with single lazy val fields. The memory footprint did not change with respect to the current version \[[6][6]\] \[[7][7]\].
-The detailed experimental measurements graphs of memory footprint can be seen in graphs.\[[18][18]\]
-
-### Performance ###
-
-We measured performance in both the uncontended and the contended case. We measured on an i7-2600, a 64-bit Oracle JVM, version 1.7 update 4.
-
-For the uncontended case, we measure the cost of creating N objects and initializing their lazy val fields. The measurement includes both the object creation times and their initialization, where the initialization is the dominant factor.
-
-For the contended case, we measure the cost of initializing the lazy fields of N objects, previously created and stored in an array, by 4 different threads that linearly try to read the lazy field of an object before proceeding to the next one. The goal of this test is to asses the effect of entering the synchronized block and notifying the waiting threads - since the slow path is slower, the threads that “lag” behind should quickly reach the first object with an uninitialized lazy val, causing contention.
-
-The current lazy val implementation (V1) seems to incur initialization costs that are at least 6 times greater compared to referencing a regular val. The handwritten implementation produces identical byte-code, with the difference that the calls are virtual instead of just querying the field value; this is probably the reason as to why it is up to 50% slower. The 2 synchronized blocks design with an eager notify (V2) is 3-4 times slower than the current implementation - just adding the `notifyAll` call changes things considerably. The 4 state/2 synchronized blocks approach (V3) is only 33-50% slower than the current implementation (V1). The CAS-based approach where `AtomicInteger`s are extended is as fast as the current lazy val initialization (V1), but when generalized and replaced with `AtomicReferenceFieldUpdater`s as discussed before, it is almost 50% slower than the current implementation (V1). The final version, V6 uses `Unsafe` to bring back performance and is as around twice as fast as current implementation (V1) while maintaining correct semantics.
-
-The CAS-based approaches (V4, V5 and V6) appear to offer the best performance here, being twice as fast than the current implementation (V1).
-
-The proposed solution with (V6) is 50% faster\[[19][19]\] than the current lazy val implementation in the contended case. This comes at a price of synchronizing on a global array of monitors, which may create contention between seemingly unrelated things. The more monitors that are created, the less is the probability of such contention. There's also a positive effect though, the reuse of global objects for synchronization allows the monitors on the instances containing lazy vals to not be expanded, saving on non-local memory allocation. The current implementation uses `8 * processorCount * processorCount` monitors and the benchmarks and by-hand study with "Vtune Amplifier XE" demonstrate that the positive effect dominates, introducing a 2% speedup\[[13][13]\]. It’s worth mentioning that this is not a typical use-case that reflects a practical application, but rather a synthetic edge case designed to show the worst-case comparison demonstrating cache contention.
-
-The local lazy vals implementation is around 6x faster than the current version, as it eliminates the need for boxing and reduces the number of allocations from 2 to 1.
-
-The concrete micro-benchmark code is available as a GitHub repo \[[6][6]\]. It additionally benchmarks many other implementations that are not covered in the text of this SIP, in particular it tests versions based on MethodHandles and runtime code generation as well as versions that use additional spinning before synchronizing on the monitor.
-For those wishing to reproduce the results, the benchmarking suite takes 90 minutes to run on contemporary CPUs. Enabling all the disabled benchmarks, in particular those that evaluate the `invokeDynamic` based implementation, will make the benchmarks take around 5 hours.
-
-The final result of those benchmarks is that amount proposed versions, the two that worth considering are (V4-general) and (V6).
-They both perform better than the current implementation in all the contended case.
-Specifically, in the contended case, V6 is 2 times faster than V1, while V4-general is 4 times faster.
-Unfortunately V4-general is 30% slower in the uncontended case than current implementation(V1), while V6 is in the same ballpark, being up to 5% slower or faster depending on the setup of the benchmark.
-
-Based on this, we propose V6 to be used as default in future versions of Scala.
-
-### Code size ###
-The versions presented in V2-V6 have a lot more complex implementation and this shows up the size of the byte-code. In the worst-case scenario, when the `` value is a constant, the current scheme (V1) creates an initializer method that has a size of 34 bytes, while dotty creates a version that is 184 bytes long. Local optimizations present in dotty linker\[[14][14]\] are able to reduce this size down to 160 bytes, but this is still substantially more than the current version.
-
-On the other hand, the single-threaded version does not need separate initializer method and is around twice smaller than the current scheme (V1).
-
-The proposed local lazy val transformation scheme also creates less byte-code, introducing 34 bytes instead of 42 bytes, mostly due to reduction in constant table size.
-
-## Current status ##
-Version V6 is implemented and used in Dotty, together with language change that makes lazy vals thread-unsafe if `@volatile` annotation is not specified.
-Dotty implementation internally uses `@static` proposed in \[[16][16]\].
-
-Both Dotty and released Scala 2.12 already implement "Elegant Local lazy vals". This was incorporated in the 2.12 release before this SIP was considered, as it was fixing a bug that blocked release\[[14][14]\].
-
-### Unsafe ###
-The proposed version, V6 relies on `sun.misc.Unsafe` in order to implement it's behaviour.
-While `sun.misc.Unsafe` will remain available in Java9 there's an intention to deprecate it and replace it with VarHandles.\[[20][20]\].
-The proposed version V6 can be implemented with using functionality present in Var Handles.
-
-## Acknowledgements ##
-
-We would like to thank Peter Levart and the other members of the concurrency-interest mailing list for their suggestions, as well as the members of the scala-internals mailing list for the useful discussions and input.
-
-
-## References ##
-1. [Summary of lazy vals discussions, Scala Internals Mailing list, May 2013][1]
-2. [The cost of `notifyAll`, Concurrency Interest Mailing List, May 2013][2]
-3. [Scala Parallel Collection in Object Initializer Causes a Program to Hang][3]
-4. [Program Hangs If Thread Is Created In Static Initializer Block][4]
-5. [Java Language Specification, 12.4.2][5]
-6. [GitHub Repo with Microbenchmarks][6]
-7. [Uncontended Performance Evaluation Results][7]
-8. [ScalaMeter GitHub Repo][8]
-9. [Lazy Vals in Dotty, Scala Internals Mailing list, February 2014][9]
-10. [Lazy Vals in Dotty, Dotty Internals Mailing list, February 2014][10]
-11. [LazyVals runtime module, Dotty sourcecode, February 2014][11]
-12. [Synchronization, HotSpot internals wiki, April 2008][12]
-13. [Lazy Vals in Dotty, cache contention discussion, February 2014][13]
-14. [SI-9824 SI-9814 proper locking scope for lazy vals in lambdas, April 2016][14]
-15. [Introducing Scalafix: a migration tool for Scalac to Dotty, October 2016][15]
-16. [@static sip, January 2016][16]
-17. [LazyVal Holders in Dotty][17]
-18. [Memory Footprint Evaluation Results][18]
-19. [Contended Performance Evaluation Results][19]
-20. [JEP 193: Variable Handles][20]
-
- [1]: https://groups.google.com/forum/#!topic/scala-internals/cCgBMp5k8R8 "scala-internals"
- [2]: https://cs.oswego.edu/pipermail/concurrency-interest/2013-May/011354.html "concurrency-interest"
- [3]: https://stackoverflow.com/questions/15176199/scala-parallel-collection-in-object-initializer-causes-a-program-to-hang "pc-object-hang"
- [4]: https://stackoverflow.com/questions/7517964/program-hangs-if-thread-is-created-in-static-initializer-block "static-init-hang"
- [5]: https://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.2 "jls-spec"
- [6]: https://github.com/DarkDimius/lazy-val-bench/blob/CallSites/src/test/scala/example/package.scala "lazy-val-bench-code"
- [7]: https://d-d.me/tnc/30/lazy-sip-perf/report/#config=%7B%22filterConfig%22%3A%7B%22curves%22%3A%5B%220%22%2C%221%22%2C%225%22%2C%226%22%2C%227%22%2C%228%22%2C%2210%22%2C%2212%22%5D%2C%22order%22%3A%5B%22param-size%22%2C%22date%22%5D%2C%22filters%22%3A%5B%5B%22100000%22%2C%22300000%22%2C%22500000%22%2C%221000000%22%2C%223000000%22%2C%225000000%22%5D%2C%5B%221477397877000%22%5D%5D%7D%2C%22chartConfig%22%3A%7B%22type%22%3A0%2C%22showCI%22%3Afalse%7D%7D "lazy-val-bench-report"
- [8]: https://axel22.github.io/scalameter/ "scalameter-code"
- [9]: https://groups.google.com/forum/#!msg/scala-internals/4sjw8pcKysg/GlXYDDzCgI0J "scala-internals"
- [10]: https://groups.google.com/forum/#!topic/dotty-internals/soWIWr3bRk8 "dotty-internals"
- [11]: https://github.com/lampepfl/dotty/blob/5cbd2fbc8409b446f8751792b006693e1d091055/src/dotty/runtime/LazyVals.scala
- [12]: https://wiki.openjdk.java.net/display/HotSpot/Synchronization
- [13]: https://groups.google.com/d/msg/scala-internals/4sjw8pcKysg/gD0au4dmTAsJ
- [14]: https://github.com/scala/scala-dev/issues/133
- [15]: https://scala-lang.org/blog/2016/10/24/scalafix.html
- [16]: https://github.com/scala/docs.scala-lang/pull/491
- [17]: https://github.com/lampepfl/dotty/blob/f92f278ab686ab218e841082dcb026c6c8ef89b7/library/src/dotty/runtime/LazyHolders.scala
- [18]: https://d-d.me/tnc/30/lazy-mem/report/#config=%7B%22filterConfig%22%3A%7B%22curves%22%3A%5B%22-1%22%2C%220%22%2C%221%22%2C%222%22%2C%223%22%2C%224%22%2C%225%22%2C%226%22%2C%227%22%2C%228%22%5D%2C%22order%22%3A%5B%22param-size%22%2C%22date%22%5D%2C%22filters%22%3A%5B%5B%221000000%22%2C%222000000%22%2C%223000000%22%2C%224000000%22%2C%225000000%22%5D%2C%5B%221477396691000%22%5D%5D%7D%2C%22chartConfig%22%3A%7B%22type%22%3A0%2C%22showCI%22%3Afalse%7D%7D
- [19]: https://d-d.me/tnc/30/lazy-sip-perf/report/#config=%7B%22filterConfig%22%3A%7B%22curves%22%3A%5B%2216%22%2C%2217%22%2C%2218%22%2C%2219%22%2C%2221%22%2C%2222%22%2C%2223%22%5D%2C%22order%22%3A%5B%22param-size%22%2C%22date%22%5D%2C%22filters%22%3A%5B%5B%22100000%22%2C%22300000%22%2C%22500000%22%2C%221000000%22%2C%223000000%22%2C%225000000%22%5D%2C%5B%221477397877000%22%5D%5D%7D%2C%22chartConfig%22%3A%7B%22type%22%3A0%2C%22showCI%22%3Afalse%7D%7D
- [20]: https://openjdk.java.net/jeps/193
diff --git a/_sips/sips/2013-06-10-spores.md b/_sips/sips/2013-06-10-spores.md
deleted file mode 100644
index 1868410121..0000000000
--- a/_sips/sips/2013-06-10-spores.md
+++ /dev/null
@@ -1,459 +0,0 @@
----
-layout: sip
-title: SIP-21 - Spores
-vote-status: "dormant"
-vote-text: There is an implementation for Scala 2.11. A new owner is needed to champion this proposal for the current Scala version. The proposal needs to be updated to explain how to handle transitive spores.
-permalink: /sips/:title.html
-redirect_from: /sips/pending/spores.html
----
-
-**By: Heather Miller, Martin Odersky, and Philipp Haller**
-
-Updated September 15th, 2013
-
-
-
-Functional programming languages are regularly touted as an enabling force, as
-an increasing number of applications become concurrent and distributed.
-However, managing closures in a concurrent or distributed environment, or
-writing APIs to be used by clients in such an environment, remains
-considerably precarious-- complicated environments can be captured by these
-closures, which regularly leads to a whole host of potential hazards across
-libraries/frameworks in Scala's standard library and its ecosystem.
-
-Potential hazards when using closures incorrectly:
-
-- Memory leaks
-- Race conditions, due to capturing mutable references
-- Runtime serialization errors, due to unintended capture of references
-
-This SIP outlines an abstraction, called _spores_, which enables safer use of
-closures in concurrent and distributed environments. This is achieved by
-controlling the environment which a spore can capture. Using an
-_assignment-on-capture_ semantics, certain concurrency bugs due to capturing mutable
-references can be avoided.
-
-## Motivating Examples
-
-### Futures and Akka Actors
-
-In the following example, an Akka actor spawns a future to concurrently
-process incoming requests.
-
-**Example 1:**
-
- def receive = {
- case Request(data) =>
- Future {
- val result = transform(data)
- sender ! Response(result)
- }
- }
-
-Capturing `sender` in the above example is problematic, since it does not
-return a stable value. It is possible that the future's body is executed at a
-time when the actor has started processing the next `Request` message which
-could be originating from a different actor. As a result, the `Response`
-message of the future might be sent to the wrong receiver.
-
-
-### Serialization
-
-The following example uses Java Serialization to serialize a closure. However,
-serialization fails with a `NotSerializableException` due to the unintended
-capture of a reference to an enclosing object.
-
-**Example 2:**
-
- case class Helper(name: String)
-
- class Main {
- val helper = Helper("the helper")
-
- val fun: Int => Unit = (x: Int) => {
- val result = x + " " + helper.toString
- println("The result is: " + result)
- }
- }
-
-Given the above class definitions, serializing the `fun` member of an instance
-of `Main` throws a `NotSerializableException`. This is unexpected, since `fun`
-refers only to serializable objects: `x` (an `Int`) and `helper` (an instance
-of a case class).
-
-Here is an explanation of why the serialization of `fun` fails: since `helper`
-is a field, it is not actually copied when it is captured by the closure.
-Instead, when accessing helper its getter is invoked. This can be made
-explicit by replacing `helper.toString` by the invocation of its getter,
-`this.helper.toString`. Consequently, the `fun` closure captures `this`, not
-just a copy of `helper`. However, `this` is a reference to class `Main` which
-is not serializable.
-
-The above example is not the only possible situation in which a closure can
-capture a reference to `this` or to an enclosing object in an unintended way.
-Thus, runtime errors when serializing closures are common.
-
-## Basic Usage
-
-Spores have a few modes of usage. The simplest form is:
-
- val s = spore {
- val h = helper
- (x: Int) => {
- val result = x + " " + h.toString
- println("The result is: " + result)
- }
- }
-
-In this example, no transformation is actually performed. Instead, the
-compiler simply ensures that the spore is _well-formed_, i.e., anything that's
-captured is explicitly listed as a value definition before the spore's
-closure. This ensures that the enclosing `this` instance is not accidentally
-captured, in this example.
-
-Spores can also be used in for-comprehensions:
-
- for { i <- collection
- j <- doSomething(i)
- } yield s"${capture(i)}: result: $j"
-
-Here, the fact that a spore is created is implicit, that is, the `spore`
-marker is not used explicitly. Spores come into play because the underlying
-`map` method of the type of `doSomething(i)` takes a spore as a parameter. The
-`capture(i)` syntax is an alternative way of declaring captured variables, in
-particular for use in for-comprehensions.
-
-Finally, a regular function literal can be used as a spore. That is, a method
-that expects a spore can be passed a function literal so long as the function
-literal is well-formed.
-
- def sendOverWire(s: Spore[Int, Int]): Unit = ...
- sendOverWire((x: Int) => x * x - 2)
-
-## Design
-
-The main idea behind spores is to provide an alternative way to create
-closure-like objects, in a way where the environment is controlled.
-
-A spore is created as follows.
-
-**Example 3:**
-
- val s = spore {
- val h = helper
- (x: Int) => {
- val result = x + " " + h.toString
- println("The result is: " + result)
- }
- }
-
-The body of a spore consists of two parts:
-
-1. **the spore header:** a sequence of local value (val) declarations only, and
-2. **the closure**.
-
-In general, a `spore { ... }` expression has the following shape.
-
-Note that the value declarations described in point 1 above can be `implicit`
-but not `lazy`.
-
-**Figure 1:**
-
- spore {
- val x_1: T_1 = init_1
- ...
- val x_n: T_n = init_n
- (p_1: S_1, ..., p_m: S_m) => {
-
- }
- }
-
-The types `T_1, ..., T_n` can also be inferred.
-
-The closure of a spore has to satisfy the following rule. All free variables
-of the closure body have to be either
-
-1. parameters of the closure, or
-2. declared in the preceding sequence of local value declarations, or
-3. marked using `capture` (see corresponding section below).
-
-**Example 4:**
-
- case class Person(name: String, age: Int)
- val outer1 = 0
- val outer2 = Person("Jim", 35)
- val s = spore {
- val inner = outer2
- (x: Int) => {
- s"The result is: ${x + inner.age + outer1}"
- }
- }
-
-In the above example, the spore's closure is invalid, and would be rejected
-during compilation. The reason is that the variable `outer1` is neither a
-parameter of the closure nor one of the spore's value declarations (the only
-value declaration is: `val inner = outer2`).
-
-### Evaluation Semantics
-
-In order to make the runtime behavior of a spore as intuitive as possible, the
-design leaves the evaluation semantics unchanged compared to regular closures.
-Basically, leaving out the `spore` marker results in a closure with the same
-runtime behavior.
-
-For example,
-
- spore {
- val l = this.logger
- () => new LoggingActor(l)
- }
-
-and
-
- {
- val l = this.logger
- () => new LoggingActor(l)
- }
-
-have the same behavior at runtime. The rationale for this design decision is
-that the runtime behavior of closure-heavy code can already be hard to reason
-about. It would become even more difficult if we would introduce additional
-rules for spores.
-
-### Spore Type
-
-The type of the spore is determined by the type and arity of the closure. If
-the closure has type `A => B`, then the spore has type `Spore[A, B]`. For
-convenience we also define spore types for two or more parameters.
-
-In example 3, the type of s is `Spore[Int, Unit]`.
-Implementation
-The spore construct is a macro which
-
-- performs the checking described above, and which
-- replaces the spore body so that it creates an instance of one of the Spore traits, according to the arity of the closure of the spore.
-
-The `Spore` trait for spores of arity 1 is declared as follows:
-
- trait Spore[-T, +R] extends Function1[T, R]
-
-For each function arity there exists a corresponding `Spore` trait of the same
-arity (called `Spore2`, `Spore3`, etc.)
-
-### Implicit Conversion
-
-Regular function literals can be implicitly converted to spores. This implicit
-conversion has two benefits:
-
-1. it enables the use of spores in for-comprehensions.
-2. it makes the spore syntax more lightweight, which is important in frameworks such as [Spark](https://spark.incubator.apache.org/) where users often create many small function literals.
-
-This conversion is defined as a member of the `Spore` companion object, so
-it's always in the implicit scope when passing a function literal as a method
-argument when a `Spore` is expected. For example, one can do the following:
-
- def sendOverWire(s: Spore[Int, Int]): Unit = ...
- sendOverWire((x: Int) => x * x - 2)
-
-This is arguably much lighter-weight than having to declare a spore before
-passing it to `sendOverWire`.
-
-In general, the implicit conversion will be successful if and only if the
-function literal is well-formed according to the spore rules (defined above in
-the _Design_ section). Note that _only function literals can be converted to spores_.
-This is due to the fact that the body of the function literal has to be checked
-by the spore macro to make sure that the conversion is safe. For _named_ function
-values (i.e., not literals) on the other hand, it's not guaranteed that the
-function value's body is available for the spore macro to check.
-
-### Capture Syntax and For-Comprehensions
-
-To enable the use of spores with for-comprehensions, a `capture` syntax has
-been introduced to assist in the spore checking.
-
-To see why this is necessary, let's start with an example. Suppose we have a
-type for distributed collections:
-
- trait DCollection[A] {
- def map[B](sp: Spore[A, B]): DCollection[B]
- def flatMap[B](sp: Spore[A, DCollection[B]]): DCollection[B]
- }
-
-This type, `DCollection`, might be implemented in a way where the data is
-distributed across machines in a cluster. Thus, the functions passed to `map`,
-`flatMap`, etc. have to be serializable. A simple way to ensure this is to
-require these arguments to be spores. However, we also would like for-comprehensions
-like the following to work:
-
- def lookup(i: Int): DCollection[Int] = ...
- val indices: DCollection[Int] = ...
-
- for { i <- indices
- j <- lookup(i)
- } yield j + i
-
-A problem here is that the desugaring done by the compiler for
-for-comprehensions doesn't know anything about spores. This is what
-the compiler produces from the above expression:
-
- indices.flatMap(i => lookup(i).map(j => j + i))
-
-The problem is that `(j => j + i)` is not a spore. Furthermore, making it a
-spore is not straightforward, as we can't change the way for-comprehensions
-are translated.
-
-We can overcome this by using the implicit conversion introduced in the
-previous section to convert the function literal implicitly to a spore.
-
-However, in continuing to look at this example, it's evident that the lambda
-still has the wrong shape. The captured variable `i` is not declared in the
-spore header (the list of value definitions preceding the closure within the
-spore), like a spore demands.
-
-We can overcome this using the `capture` syntax – an alternative way of
-capturing paths. That is, instead of having to write:
-
- {
- val captured = i
- j => j + i
- }
-
-One can also write:
-
- (j => j + capture(i))
-
-Thus, the above for-comprehension can be rewritten using spores and `capture`
-as follows:
-
- for { i <- indices
- j <- lookup(i)
- } yield j + capture(i)
-
-Here, `i` is "captured" as it occurs syntactically after the arrow of another
-generator (it occurs after `j <- lookup(i)`, the second generator in the
-for-comprehension).
-
-**Note:** anything that is "captured" using `capture` may only be a path.
-
-**A path** (as defined by the Scala Language Specification, section 3.1) is:
-
-- The empty path ε (which cannot be written explicitly in user programs).
-- `C.this`, where `C` references a class.
-- `p.x` where `p` is a path and `x` is a stable member of `p`.
-- `C.super.x` or `C.super[M].x` where `C` references a class and `x` references a stable member of the super class or designated parent class `M` of `C`.
-
-The reason why captured expressions are restricted to paths is that otherwise
-the two closures
-
- (x => + capture())
-
-and
-
- (x => + )
-
-(where `` and `` are not just paths) would not have the same
-runtime behavior, because in the first case, the closure would have to be
-transformed in a way that would evaluate `` "outside of the closure".
-Not only would this complicate the reasoning about spore-based code (see the
-section Evaluation Semantics above), but it's not clear what "outside of the
-closure" even means in a context such as for-comprehensions.
-
-### Macro Expansion
-
-An invocation of the spore macro expands the spore's body as follows. Given
-the general shape of a spore as shown above, the spore macro produces the
-following code:
-
- new [S_1, ..., S_m, R]({
- val x_1: T_1 = init_1
- ...
- val x_n: T_n = init_n
- (p_1: S_1, ..., p_m: S_m) => {
-
- }
- })
-
-Note that, after checking, the spore macro need not do any further
-transformation, since implementation details such as unneeded remaining outer
-references are removed by the new backend intended for inclusion in Scala
-2.11. It's also useful to note that in some cases these unwanted outer
-references are already removed by the existing backend.
-
-The spore implementation classes follow a simple pattern. For example, for
-arity 1, the implementation class is declared as follows:
-
- class SporeImpl[-T, +R](f: T => R) extends Spore[T, R] {
- def apply(x: T): R = f(x)
- }
-
-### Type Inference
-
-Similar to regular functions and closures, the type of a spore should be
-inferred. Inferring the type of a spore amounts to inferring the type
-arguments when instantiating a spore implementation class:
-
- new [S_1, ..., S_m, R]({
- // ...
- })
-
-In the above expression, the type arguments `S_1, ..., S_m`, and `R` should be
-inferred from the expected type.
-
-Our current proposal is to solve this type inference problem in the context of
-the integration of Java SAM closures into Scala. Given that it is planned to
-eventually support such closures, and to support type inference for these
-closures as well, we plan to piggyback on the work done on type inference for
-SAMs in general to achieve type inference for spores.
-
-## Motivating Examples, Revisited
-
-We now revisit the motivating examples we described in the above section, this
-time in the context of spores.
-
-### Futures and Akka actors
-
-The safety of futures can be improved by requiring the body of a new future to
-be a nullary spore (a spore with an empty parameter list).
-
-Using spores, example 1 can be re-written as follows:
-
- def receive = {
- case Request(data) =>
- future(spore {
- val from = sender
- val d = data
- () => {
- val result = transform(d)
- from ! Response(result)
- }
- })
- }
-
-In this case, the problematic capturing of `this` is avoided, since the result
-of `this.sender` is assigned to the spore's local value `from` when the spore
-is created. The spore conformity checking ensures that within the spore's
-closure, only `from` and `d` are used.
-
-### Serialization
-
-Using spores, example 2 can be re-written as follows:
-
- case class Helper(name: String)
-
- class Main {
- val helper = Helper("the helper")
-
- val fun: Spore[Int, Unit] = spore {
- val h = helper
- (x: Int) => {
- val result = x + " " + h.toString
- println("The result is: " + result)
- }
- }
- }
-
-Similar to example 1, the problematic capturing of `this` is avoided, since
-`helper` has to be assigned to a local value (here, `h`) so that it can be
-used inside the spore's closure. As a result, `fun` can now be serialized
-without runtime errors, since `h` refers to a serializable object (a case
-class instance).
diff --git a/_sips/sips/2013-06-30-async.md b/_sips/sips/2013-06-30-async.md
deleted file mode 100644
index a83bb6f5a4..0000000000
--- a/_sips/sips/2013-06-30-async.md
+++ /dev/null
@@ -1,298 +0,0 @@
----
-layout: sip
-title: SIP-22 - Async
-vote-status: dormant
-vote-text: Authors have marked this proposal as dormant. Details in the implementation need to be figured out. Check July 2016's minutes.
-permalink: /sips/:title.html
-redirect_from: /sips/pending/async.html
----
-
-**By: Philipp Haller and Jason Zaugg**
-
-## Introduction
-
-This is a proposal to add constructs that simplify asynchronous and concurrent programming in Scala. The main constructs, async and await, are inspired by similar constructs introduced in C# 5.0. The main purpose of async/await is to make it possible to express efficient asynchronous code in a familiar direct style (where suspending operations look as if they were blocking). As a result, non-blocking code using Scala’s futures API \[[1][1]\] can be expressed without using higher-order functions, such as map and flatMap, or low-level callbacks.
-
-On the level of types, async and await are methods with simple, intuitive types:
-
- def async[T](body: => T): Future[T]
- def await[T](future: Future[T]): T
-
-Here, `Future[T]` refers to the `Future` trait in package `scala.concurrent`. (The system can be adapted to other implementations of future-like abstractions; at the moment the API with the required extension points is internal, though.) The above methods are used as follows:
-
- val fut = async {
- slowComputation()
- }
-
-The async construct marks a block of asynchronous code, and returns a future. Depending on the execution context in the implicit scope (see \[[1][1]\]), the block of asynchronous code is either executed on the current thread or in a thread pool. The async block can contain calls to await:
-
- val futureDOY: Future[Response] =
- WS.url("https://api.day-of-year/today").get
-
- val futureDaysLeft: Future[Response] =
- WS.url("https://api.days-left/today").get
-
- val respFut = async {
- val dayOfYear = await(futureDOY).body
- val daysLeft = await(futureDaysLeft).body
- Ok(s"$dayOfYear: $daysLeft days left!")
- }
-
-Line 1 and 4 define two futures obtained as results of asynchronous requests to two hypothetical web services using an API inspired by Play Framework \[[2][2]\] (for the purpose of this example, the definition of type `Response` is unimportant). The `await` on line 8 causes the execution of the `async` block to suspend until `futureDOY` is completed (with a successful result or with an exception). When the future is completed successfully, its result is bound to the `dayOfYear` val, and the execution of the `async` block is resumed. When the future is completed with an exception (for example, because of a timeout), the invocation of `await` re-throws the exception that the future was completed with. In turn, this completes future respFut with the same exception. Likewise, the `await` on line 9 suspends the execution of the `async` block until futureDaysLeft is completed.
-
-## Comparison with Scala’s Futures API
-
-The provided async and await constructs can significantly simplify code coordinating multiple futures. Consider the following example, written using Scala’s futures API together with for-comprehensions:
-
- def nameOfMonth(num: Int): Future[String] = ...
- val date = “““(\d+)/(\d+)“““.r
-
- for { doyResponse <- futureDOY
- dayOfYear = doyResponse.body
- response <- dayOfYear match {
- case date(month, day) =>
- for (name <- nameOfMonth(month.toInt))
- yield Ok(s“It’s $name!“)
- case _ =>
- Future.successful(NotFound(“Not a...“))
- }
- } yield response
-
-Line 1 defines an asynchronous method that converts an integer representing the number of a month to the name of the month (for example, the integer 2 is converted to "February"). Since the method is asynchronous, it returns a `Future[String]`. Line 2 defines a regular expression used to extract the month from a date string such as "07/24". The for-comprehension starting on line 4 first awaits the result of `futureDOY` (the example re-uses the definition of `futureDOY` shown earlier). Scala's futures provide methods like `map` and `flatMap`, and can thus be used as generators in for-comprehensions (for a more in-depth introduction of this feature see the official documentation \[[1][1]\]). The use of for-comprehensions can help make future-based code more clear, but in many cases it requires a significant amount of unnatural clutter and workarounds. The above example suffers from the following issues:
-
-- To extract `dayOfYear`, we are forced to introduce the name `doyResponse`, a useless intermediate result (line 4);
-- to await the completion of the future returned by `nameOfMonth`, we are forced to use a nested for-comprehension (line 8);
-- the nested for-comprehension forces us to bind the result of nameOfMonth to name, a useless intermediate variable (line 8);
-- the nested for-comprehension forces us to introduce an artificial future that's completed upon creation (line 11);
-- the artificial future introduces additional overhead and garbage (line 11);
-- finally, the use of for-yield might obscure the actual domain which is asynchronous computations with non-blocking awaits.
-
-The same example can be written using async/await as follows:
-
- async {
- await(futureDOY).body match {
- case date(month, day) =>
- Ok(s“It’s ${await(nameOfMonth(month.toInt))}!“)
- case _ =>
- NotFound(“Not a date, mate!“)
- }
- }
-
-This version avoids all drawbacks of the previous version listed above. In addition, the generated code is more efficient, because it creates fewer closures.
-
-## Illegal Uses
-
-The following uses of await are illegal and are reported as errors:
-- await requires a directly-enclosing async; this means await must not be used inside a closure nested within an async block, or inside a nested object, trait, or class.
-- await must not be used inside an expression passed as an argument to a by-name parameter.
-- await must not be used inside a Boolean short-circuit argument.
-- return expressions are illegal inside an async block.
-
-## Implementation
-
-We have implemented the present proposal using the macro system which has been introduced in Scala 2.10 as an experimental feature. Our implementation \[[3][3]\] is targeted at Scala 2.11.0, but runs on using Scala 2.10.1 without any limitations.
-
-## Async Transform Specification
-
-In the following we consider the transformation of an invocation `async { }` of the async macro.
-Before the block of code (``) is transformed, it is normalized into a form amenable to a transformation into a state machine. This form is called the "A-Normal Form" (ANF), and roughly means that:
-
-- `if`, `match`, and other control-flow constructs are only used as statements; they cannot be used as expressions;
-- calls to `await` are not allowed in compound expressions.
-
-After the ANF transform, the async macro prepares the state machine
-transformation by identifying vals, vars and defs that are accessed
-from multiple states. These will be lifted out to fields in the state
-machine object.
-
-The next step of the transformation breaks the code into "chunks."
-Each chunk contains a linear sequence of statements that concludes
-with a branching decision, or with the registration of a subsequent
-state handler as the continuation (the "on-completion handler"). Once
-all chunks have been built, the macro synthesizes a class representing
-the state machine. The class contains:
-
-- an integer representing the current state ID
-- the lifted definitions
-- an `apply(value: Try[Any]): Unit` method that will be called on completion of each future. The behavior of this method is determined by the current state. It records the downcast result of the future in a field, and calls the `resume()` method.
-- the `resume(): Unit` method that switches on the current state and runs the users code for one "chunk," and either: (a) registers the state machine as the handler for the next future, or (b) completes the result promise of the async block, if at the terminal state.
-- an `apply(): Unit` method that starts the evaluation of the async block's body.
-
-### Example
-
- val future = async {
- val f1 = async { true }
- val x = 1
- def inc(t: Int) = t + x
- val t = 0
- val f2 = async { 42 }
- if (await(f1)) await(f2) else { val z = 1; inc(t + z) }
- }
-
-After the ANF transform:
-- `await` calls are moved to only appear on the RHS of a value definition;
-- `if` is no longer used as an expression; instead each branch writes its result to a synthetic var;
-- the `ExecutionContext` used to run the async block is obtained as an implicit argument.
-
-Follows the end result of the ANF transform (with very minor
-simplifications).
-
- {
- ();
- val f1: scala.concurrent.Future[Boolean] = {
- scala.concurrent.Future.apply[Boolean](true)(scala.concurrent.ExecutionContext.Implicits.global)
- };
- val x: Int = 1;
- def inc(t: Int): Int = t.+(x);
- val t: Int = 0;
- val f2: scala.concurrent.Future[Int] = {
- scala.concurrent.Future.apply[Int](42)(scala.concurrent.ExecutionContext.Implicits.global)
- };
- val await$1: Boolean = scala.async.Async.await[Boolean](f1);
- var ifres$1: Int = 0;
- if (await$1)
- {
- val await$2: Int = scala.async.Async.await[Int](f2);
- ifres$1 = await$2
- }
- else
- {
- ifres$1 = {
- val z: Int = 1;
- inc(t.+(z))
- }
- };
- ifres$1
- }
-
-After the full async transform:
-
-- one class is synthesized that represents the state machine. Its `apply()` method is used to start the computation (even the code before the first await call is executed asynchronously), and the `apply(tr: scala.util.Try[Any])` method will continue after each completed future that the async block awaits;
-
-- each chunk of code is moved into the a branch of the pattern match in `resume$async`;
-
-- value and function definitions accessed from multiple states are lifted to be members of class `stateMachine`; others remain local, e.g. `val z`;
-
-- `result$async` holds the promise which is completed with the result of the async block;
-
-- `execContext$async` holds the `ExecutionContext` that has been inferred.
-
-Follows the end result of the full async transform (with very minor
-simplifications).
-
- {
- class stateMachine$7 extends StateMachine[scala.concurrent.Promise[Int], scala.concurrent.ExecutionContext] {
- var state$async: Int = 0;
- val result$async: scala.concurrent.Promise[Int] = scala.concurrent.Promise.apply[Int]();
- val execContext$async = scala.concurrent.ExecutionContext.Implicits.global;
- var x$1: Int = 0;
- def inc$1(t: Int): Int = t.$plus(x$1);
- var t$1: Int = 0;
- var f2$1: scala.concurrent.Future[Int] = null;
- var await$1: Boolean = false;
- var ifres$1: Int = 0;
- var await$2: Int = 0;
- def resume$async(): Unit = try {
- state$async match {
- case 0 => {
- ();
- val f1 = {
- scala.concurrent.Future.apply[Boolean](true)(scala.concurrent.ExecutionContext.Implicits.global)
- };
- x$1 = 1;
- t$1 = 0;
- f2$1 = {
- scala.concurrent.Future.apply[Int](42)(scala.concurrent.ExecutionContext.Implicits.global)
- };
- f1.onComplete(this)(execContext$async)
- }
- case 1 => {
- ifres$1 = 0;
- if (await$1)
- {
- state$async = 2;
- resume$async()
- }
- else
- {
- state$async = 3;
- resume$async()
- }
- }
- case 2 => {
- f2$1.onComplete(this)(execContext$async);
- ()
- }
- case 5 => {
- ifres$1 = await$2;
- state$async = 4;
- resume$async()
- }
- case 3 => {
- ifres$1 = {
- val z = 1;
- inc$1(t$1.$plus(z))
- };
- state$async = 4;
- resume$async()
- }
- case 4 => {
- result$async.complete(scala.util.Success.apply(ifres$1));
- ()
- }
- }
- } catch {
- case NonFatal((tr @ _)) => {
- {
- result$async.complete(scala.util.Failure.apply(tr));
- ()
- };
- ()
- }
- };
- def apply(tr: scala.util.Try[Any]): Unit = state$async match {
- case 0 => {
- if (tr.isFailure)
- {
- result$async.complete(tr.asInstanceOf[scala.util.Try[Int]]);
- ()
- }
- else
- {
- await$1 = tr.get.asInstanceOf[Boolean];
- state$async = 1;
- resume$async()
- };
- ()
- }
- case 2 => {
- if (tr.isFailure)
- {
- result$async.complete(tr.asInstanceOf[scala.util.Try[Int]]);
- ()
- }
- else
- {
- await$2 = tr.get.asInstanceOf[Int];
- state$async = 5;
- resume$async()
- };
- ()
- }
- };
- def apply: Unit = resume$async()
- };
- val stateMachine$7: StateMachine[scala.concurrent.Promise[Int], scala.concurrent.ExecutionContext] = new stateMachine$7();
- scala.concurrent.Future.apply(stateMachine$7.apply())(scala.concurrent.ExecutionContext.Implicits.global);
- stateMachine$7.result$async.future
- }
-
-## References
-
-1. [The Scala Futures API][1]
-2. [The Play! Framework][2]
-3. [Scala Async on GitHub][3]
-
- [1]: https://docs.scala-lang.org/overviews/core/futures.html "ScalaFutures"
- [2]: https://www.playframework.com/ "Play"
- [3]: https://github.com/scala/async "ScalaAsync"
diff --git a/_sips/sips/2015-6-18-repeated-byname.md b/_sips/sips/2015-6-18-repeated-byname.md
deleted file mode 100644
index ee71571b6a..0000000000
--- a/_sips/sips/2015-6-18-repeated-byname.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-layout: sip
-title: SIP-24 - Repeated By Name Parameters
-vote-status: dormant
-vote-text: Looking for a new owner. This proposal needs to be updated according to the SIP meeting in November 2016.
-permalink: /sips/:title.html
-redirect_from: /sips/pending/repeated-byname.html
-
----
-
-**By: Martin Odersky**
-
-## Motivation
-
-Scala so far does not allow by-name repeated parameters. But I can't see a good reason why this combination should be disallowed. Also, the combination is necessary to allow vararg parameters that are passed as expressions to inline methods (instead of being lifted out).
-
-## Syntax
-
-The syntax for `ParamType` becomes
-
- ParamType ::= [`=>'] ParamValueType
- ParamValueType ::= Type [`*']
-
-The syntax implies that a type such as `=> T*`, which is both by-name and repeated is interpreted as `=> (T*)`, that is, as a by-name type of a repeated type.
-
-## Translation Rules
-
-If a parameter has a by-name repeated type `=> T*` it matches an arbitrary number of actual arguments of type `T`. As usual for by-name parameters, the arguments are not evaluated at the point of call. Instead, all arguments are evaluated each time the parameter is referenced in the called method.
-
-The same holds for an vararg argument of the form `e: _*`. The argument expression `e` is evaluated each time the parameter is referenced in the called method.
-
-## See also
-
-[Dotty Issue #499](https://github.com/lampepfl/dotty/issues/499)
diff --git a/_sips/sips/2016-07-25-unsigned-integers.md b/_sips/sips/2016-07-25-unsigned-integers.md
deleted file mode 100644
index ef8ecd7bf1..0000000000
--- a/_sips/sips/2016-07-25-unsigned-integers.md
+++ /dev/null
@@ -1,636 +0,0 @@
----
-layout: sip
-title: SIP-26 - Unsigned Integers
-
-vote-status: rejected
-vote-text: The committee votes to reject the proposal because of a 6% performance hit on the provided implementation by the authors.
-permalink: /sips/:title.html
-redirect_from: /sips/pending/unsigned-integers.html
----
-
-__Sébastien Doeraene and Denys Shabalin__
-
-**Summary**: We propose the addition of 4 "primitive" types to represent
-unsigned integers: `UByte`, `UShort`, `UInt` and `ULong`.
-
-A prototype implementation of this proposal, with unit tests and benchmarks,
-can be found [here](https://github.com/scala/scala/compare/2.12.x...sjrd:uints).
-
-## History
-
-| Date | Version |
-|--------------|---------------|
-| Nov 9th 2015 | Initial Draft |
-
-## Introduction - Motivation - Abstract
-
-Scala was initially designed to target the JVM, and, as such, defines exactly
-9 primitive types corresponding to the 9 primitive types of the JVM (including
-`void`):
-
-* `Boolean`
-* `Char`
-* `Byte`
-* `Short`
-* `Int`
-* `Long`
-* `Float`
-* `Double`
-* `Unit`
-
-Compared to other languages, especially those in the tradition of
-compile-to-machine code, this list is missing types for unsigned integer types.
-
-When compiling Scala to other platforms than the JVM, such as JavaScript with
-Scala.js or native code/LLVM with the upcoming ScalaNative, the missing unsigned
-integer types are a liability, especially when it comes to *interoperability
-with host language libraries*.
-
-For example, if a C library defines a function accepting a `uint32_t`, how would
-we type it in a FFI definition? Even in JavaScript, which supposedly has only
-`Double`s, there are APIs working with unsigned integers. The most well-known
-one is
-[the TypedArray API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray).
-Currently, because of the lack of unsigned integers in Scala, the
-[facade types for `Uint8Array` in Scala.js](https://github.com/scala-js/scala-js/blob/v0.6.5/library/src/main/scala/scala/scalajs/js/typedarray/Uint8Array.scala)
-is forced to use `Short` elements instead of a more appropriate `UByte`. Worse,
-[the one for `Uint32Array`](https://github.com/scala-js/scala-js/blob/v0.6.5/library/src/main/scala/scala/scalajs/js/typedarray/Uint32Array.scala)
-has to work with *Doubles*, because there is no signed integer type existing on
-JavaScript that can represent all values of a 32-bit unsigned int.
-
-On the JVM, interoperability is not an issue. However, it is still sometimes
-useful to manipulate unsigned integers. An evidence of this fact is that Java 8
-has added methods in the JDK to *manipulate* signed integers *as if* they were
-unsigned. One example is
-[`java.lang.Integer.divideUnsigned`](https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#divideUnsigned-int-int-).
-Using signed integer types but interpreting them as unsigned is an obvious lack
-of type safety, however. Java cannot decently add new primitive types for
-compatibility reasons, but Scala has custom-made `AnyVal`s and other
-Object-Oriented abstractions on top of primitive types that can allow for
-additional, zero-overhead "primitive" types.
-
-We therefore propose to extend the Scala programming language with 4 new
-primitive data types, representing unsigned integer types:
-
-* `scala.UByte`, an unsigned 8-bit integer
-* `scala.UShort`, an unsigned 16-bit integer
-* `scala.UInt`, an unsigned 32-bit integer
-* `scala.ULong`, an unsigned 64-bit integer
-
-These data types will support a set of operations similar to their signed
-counterparts, except that they will obviously encode the unsigned behavior.
-
-For example:
-
-```scala
-val x = Int.MaxValue.toUInt + 1.toUInt // 2147483648
-assert(x.toString == "2147483648")
-val y = Int.MaxValue.toUInt + 5.toUInt // 2147483652
-val z = x / y // unsigned division of 2147483652 by 2147483648
-assert(z == 1.toUInt)
-assert(x % y == 4.toUInt)
-```
-
-## Motivating Examples
-
-### Examples
-
-#### Interoperability with host language unsigned integers
-
-The most important use case for true unsigned integers specified by the
-language is interoperability with host languages with unsigned data types.
-
-If we try to manipulate an `Uint32Array` in Scala.js as currently defined, we
-end up manipulating `Double`s, which can become extremely confusing:
-
-```scala
-val array = new Uint32Array(js.Array(5, 7, 6, 98))
-val x = array(3) / array(0)
-println(x) // 19.6 (!)
-```
-
-This also causes type safety issues, since nothing prevents the developer from
-introducing a non-integer `Double` into such an array:
-
-```scala
-array(2) = 6.4 // compiles, silent drop of precision
-println(array(2)) // 6
-```
-
-If we can define `Uint32Array` as an array of `UInt` instead, our problems are
-solved:
-
-```scala
-val array = new Uint32Array(js.Array(5, 7, 6, 98).map(_.toUInt))
-val x = array(3) / array(0)
-println(x) // 19, as expected
-
-array(2) = 6.4 // does not compile, yeah!
-```
-
-#### Implementation of algorithms requiring unsigned operations
-
-No matter the platform, even on the JVM, we sometimes have to implement
-algorithms that are best defined in terms of unsigned operations. Particularly,
-more often than not, we want to treat bytes in a buffer as unsigned.
-
-For example, here is a (buggy) algorithm to decode text encoded in ISO-8859-1
-(latin1) into Unicode code points. Can you spot the issue?
-
-```scala
-def decodeISO88591(buffer: Array[Byte]): String = {
- val result = new StringBuilder(buffer.length)
- for (i <- 0 until buffer.length)
- result.append(buffer(i).toChar)
- result.toString()
-}
-```
-
-The problem is that `buffer(i).toChar` will first *sign-extend* the signed
-`Byte` to an `Int`, then cut off the 16 most significant bits. If the initial
-`Byte` was ">= 0x80", it was actually *negative*, and therefore the resulting
-`Char` will have its 8 most significant bits set to 1, which is a bug.
-
-Fixing the algorithm requires knowledge of 2's complement properties and how
-the bits are affected by arithmetic operations. The solution is
-`(buffer(i) & 0xff).toChar`, which is totally non-obvious.
-
-With unsigned bytes, the problem does not happen by construction, and the
-algorithm is straightforward:
-
-```scala
-def decodeISO88591(buffer: Array[UByte]): String = {
- val result = new StringBuilder(buffer.length)
- for (i <- 0 until buffer.length)
- result.append(buffer(i).toChar) // correct: UByte.toChar does not sign-extend
- result.toString()
-}
-```
-
-### Comparison Examples
-
-The blog post
-[Unsigned int considered harmful for Java](https://www.nayuki.io/page/unsigned-int-considered-harmful-for-java)
-explains in detail how to correctly manipulate signed integer types to make
-them behave as unsigned.
-
-There are two main problems with this, considering only the JVM target:
-
-* We have to remember what operations need dedicated methods to deal with the
- unsigned case.
-* We cannot express in the type of a value whether it is to be interpreted as
- a signed or unsigned integer. Effectively, we're back to *Assembly*-grade
- weak typing.
-
-In addition, those separate manipulations do not allow back-ends to other
-targets to effectively interoperate with host language unsigned data types.
-
-### Counter-Examples
-
-We do not intend to generalize unsigned numbers to Big integers nor to
-floating-point numbers.
-
-Also, it is out of the scope of this proposal to provide literal constant
-notations for unsigned integers. They should be constructed from their
-corresponding signed literals, and reinterpreted using `.toUInt` and similar.
-
-## Drawbacks
-
-### Performance of arrays
-
-Unless the implementation of unsigned integer types is very much special-cased
-in the compiler, arrays of unsigned integer types will likely suffer from the
-same performance penalty as arrays of user-defined `AnyVal`s, because the
-elements will be boxed.
-
-This might cause unexpected performance issues, as developers will think that
-`Array[UByte]` is as fast as `Array[Byte]`, when in fact it is not.
-Performance-critical code should still use `Array[Byte]`, and reinterpret the
-bytes into unsigned bytes and back using `sb.toUByte` and `ub.toByte`,
-respectively.
-
-## Alternatives
-
-The only other alternative is the status quo, where no unsigned integer types
-exist, and difficult 2's complement-aware manipulations must be done when we
-need them.
-
-## Design
-
-Naively, the design of the API is straightforward. We would define 4 new
-data types `UByte`, `UShort`, `UInt` and `ULong`, corresponding to the 4
-signed integer data types. They feature the same set of arithmetic and logic
-operations, as well as comparisons. However, such a naive design causes
-several issues, especially when signed integers and unsigned integers interact
-in operations.
-
-Here, we discuss the set of operations available, and their semantics.
-
-### No arithmetic/logic operations between signed and unsigned integers
-
-To prevent typical caveats when mixing signed and unsigned integers in most
-languages, we simply *forbid* any arithmetic or logic operations with operands
-of different signedness.
-
-### Universal equality, and hash codes
-
-The universal equality operators (`==` and `!=`) should behave consistently
-across signed and unsigned types. Since `5.toByte == 5` in Scala, we should
-also have `5.toUInt == 5`. This requires to modify the `==` implementation
-(in `BoxesRunTime`) to implement cooperative equality checks between all
-combinations of signed and unsigned values.
-
-Negative values of signed integers are *not* equal to any unsigned integer
-value. For example, this means that `(-1).toUInt != -1`. This is very simply
-explained by the fact that the mathematical value of `(-1).toUInt` is
-4294967295.
-
-Because of transitivity of equality, it must be the case that a large value of
-an unsigned integer (whose signed reinterpretation is negative, such as
-`0xffffffff.toUInt`) *is* equal to values of a larger signed integer types
-(such as `0xffffffffL`).
-
-Hash codes, as computed by `##`, must be made consistent with the generalized
-form of universal equality.
-
-Note that this definition of universal equality is *essential* for these new
-primitives to be usable for interoperability scenarios in Scala.js. This is
-because, at runtime, "boxed" versions of numeric types loose their type
-information, as they are all stuffed into primitive JavaScript numbers.
-Therefore, `0xffff.toUShort` is indistinguishable from `0xffff`, and they must
-be equal for this "non-boxing" to be valid.
-
-### Operations on `UByte` and `UShort`
-
-By analogy to the fact that operations on `Byte`s and `Short` start by
-converting their operands to `Int`s (using sign-extend), operations on `UByte`s
-and `UShort`s convert their operands to `UInt`s (without sign-extend,
-obviously).
-
-### Arithmetic operations on `UInt`s and `ULong`s.
-
-For two operands of the same unsigned integer type with N bits, `a + b`,
-`a - b`, `a * b`, `a / b` and `a % b` are computed modulo `2^N`.
-For `+`, `-` and `*`, this boils down to a primitive (signed) equivalent
-operations, on the JVM. `/` and `%` correspond to
-`java.lang.{Integer,Long}.divideUnsigned` and `remainderUnsigned`.
-
-If one of the operand is a `ULong` but the other isn't, the latter is converted
-to a `ULong` before performing the operation.
-
-There is no `unary_-`, because unsigned integers have no opposite. It could be
-argued that `-x` could be useful for low-level bit-twiddling-based algorithms.
-However, in that case, `~x + 1.toUInt` can be used instead. A basic peephole
-optimizer can simplify the latter as `-x` on platforms where this is relevant.
-
-### Logic (bitwise) operations on `UInt`s and `ULong`s
-
-`unary_~`, `|`, `&` and `^` behave in the obvious way. If you want a precise
-spec, they always behave as if the operand was reinterpreted into its signed
-equivalent, then the operation performed, then the result reinterpreted back
-into unsigned.
-
-### Bit shifting operations on `UInt`s and `ULong`s
-
-Shift left `<<` and shift logical right `>>>` behave in the obvious way.
-
-The case of shift arithmetic right `>>` is debatable. We argue that it should
-*not* be available on unsigned integers for two reasons.
-
-First, a shift arithmetic right does not appear to have any *meaning* on
-unsigned integers. The correct *arithmetic* shift if `>>>`. Therefore,
-similarly to `unary_-`, it should not be introduced.
-
-Second, existing languages that do have unsigned integer types, such as the C
-family, actually give different semantics to `>>` depending on whether it has
-a signed or unsigned operand: a `>>` on an unsigned operand does *not*
-sign-extend. It would be confusing to a C developer for `x >> 3` to sign-extend
-in Scala, but it would be equally confusing to a Scala developer that `x >> 3`
-*not* sign-extend. Therefore, we prefer to leave it out completely, and let a
-compiler error be raised.
-
-If a bit-twiddling-based algorithm needs the sign-extending shift right, it is
-always possible to reinterpret as signed, do the operation, and reinterpret
-back as unsigned: `(x.toInt >> 3).toUInt`.
-
-Note: the current implementation does provide `>>`, until we agree on this
-point.
-
-### Inequality operators
-
-`<`, `<=`, `>`, `>=` perform unsigned comparisons. On the JVM, they correspond
-to `java.lang.{Integer,Long}.compareUnsigned`.
-
-### String representation
-
-The string representation is similar to that of signed integers, except that
-all numbers are positive, obviously. On the JVM, they correspond to
-`java.lang.{Integer,Long}.toUnsignedString`.
-
-### Implicit widening conversions
-
-Unsigned integers can be implicitly widened to "larger" unsigned integer types.
-For example, `UShort` can be implicitly converted to `UInt` and `ULong`.
-
-There are no implicit conversions between signed and unsigned integers. It might
-be tempting to allow unsigned integers to be widened to larger signed integer
-types, since they can always accommodate their mathematical values. However,
-this consequently allows operations between signed and unsigned integers, such
-as `5L + 4.toUInt`, because of the conversion from `UInt` to `Long`. Since we
-want to disallow those to prevent caveats, we do not allow the implicit
-conversions.
-
-### Explicit conversions between signed and unsigned
-
-We have already extensively used explicit conversions between signed and
-unsigned integer types *of the same size* in this document, such as
-`someInt.toUInt`. These are specified as reinterpreting the bit pattern into
-the other type, with the common specification that integer types are represented
-in 2's complement.
-
-*Narrowing* conversions are also allowed in both directions, such as
-`someInt.toUByte` or `someUInt.toByte`. They are equally well specified as
-either `someInt.toUInt.toUByte` or `someInt.toByte.toUByte`, with the same
-results, and therefore no ambiguity exists.
-
-*Widening* conversions from unsigned integers to larger signed integers is
-allowed, and is specified by conserving the mathematical value, i.e., the
-widening does *not* sign-extend.
-
-Finally, widening conversions from signed integers to larger unsigned integers
-is *disallowed*, because both interpretations are equally valid, and therefore
-half of the developers will have the wrong expectation. For example,
-`someInt.toULong` can be equally validly specified as `someInt.toUInt.toULong`
-or `someInt.toLong.toULong`, but those do not yield the same result (the former
-does not sign-extend while the latter does).
-
-### Consequences on other parts of the library
-
-`scala.math` should receive new overloads of `max` and `min`, taking unsigned
-integer types as parameters, and performing the comparisons with unsigned
-semantics.
-
-There should be instances of the `Ordering` typeclass for unsigned integer
-types.
-
-There should *not* be instances of the `Numeric` and `Integral` typeclasses
-for unsigned integer types, since they do not support `unary_-`.
-
-It might be tempting to define `Range`s over unsigned integers, but we do not
-want to go there.
-
-### Performance considerations
-
-Since they will inevitably be "branded" as primitive data types, unsigned
-integer types should be as efficient as signed integer types.
-
-Fortunately, the JDK 8 added the necessary methods in the standard JDK to
-trivially implement all the operations on unsigned integers. It is expected
-that these methods be as fast primitive operations, since they can be
-intrinsified easily.
-
-There also exist efficient implementations of these methods in Scala.js. LLVM
-supports the relevant operations by default for ScalaNative, obviously.
-
-The implementations in `BoxesRunTime` for universal equality and hash codes
-receives additional cases, which could slow down `==` on `Any`s and generic
-values. However, if a codebase does not use any unsigned integer, the JVM,
-using global knowledge, can statically determine that the new type tests are
-always `false` and therefore remove them. There should be no performance
-penalty on such codebases.
-
-## Implementation
-
-Because of the cooperative equality with primitive signed integers, the
-addition of unsigned integers must necessarily integrate the core library.
-
-Besides that, there are two major strategies for the implementation: mostly
-user-space or mostly in compiler-space.
-
-### Mostly user-space vs compiler-space
-
-An existing implementation living mostly in user-space can be found at
-https://github.com/scala/scala/compare/2.12.x...sjrd:uints
-
-In this approach, unsigned integer types are user-defined `AnyVal`s, and all
-the new methods are implemented in the library. The compiler needs very little
-adaptations; basically only to dispatch `==` of unsigned integers to
-`BoxesRunTime` (otherwise, it is "optimized" as directly calling `equals()`).
-
-This approach has obvious advantages:
-* Little room for mistakes
-* Very simple implementation
-* Minimal impact on the compiler
-
-However, it also suffers from a couple of limitations, because the new
-"primitive" data types are not really primitive, and do not receive some of the
-semantic treatment of primitives.
-
-First, unboxing from `null`: a primitive data type unboxes `null` to its zero,
-but user-defined `AnyVal`s throw in those situations. One way to fix this would
-be to "fix" the behavior on `AnyVal`s in general, which we think would be a good
-idea on its own anyway.
-
-Second, weak conformance: unsigned integers don't receive the weak conformance
-properties. However, we argue that this is no big deal. The main use case for
-weak conformance is so that `List(1, 5, 3.5)` can be inferred as a
-`List[Double]` instead of a `List[AnyVal]`. The problem initially happens
-because of the way we write literal integers and literal doubles. Since unsigned
-integers have no literal notation, and are not implicitly compatible with
-signed integers nor doubles, this point is moot.
-
-In the short term, these limitations do not appear important, and we could live
-with them.
-
-More importantly, however, this implementation prevents specialization to be
-applied on unsigned integers, and imposes harsh constraints on how back-ends
-can implement unsigned integers.
-
-In Scala.js these constraints are not too hard from the point of view of
-interoperability scenarios, although they could limit the performance we can
-get out of unsigned integers. Since interoperability is paramount, we can again
-live with the constraints for the time being.
-
-For ScalaNative, the consequences of these constraints are, as of yet, unknown,
-but they could affect interoperability scenarios, and will most probably affect
-performance.
-
-In the longer term, we should therefore consider more tightly integrating
-unsigned integer types as true primitives of the compiler.
-
-Such a strategy will however be much riskier, and will take much more time to
-get right.
-
-### Performance evaluation
-
-To evaluate performance of our prototype we've implemented a simple jmh
-benchmark generator that checks composite performance of evaluation of complex
-arithmetic expressions for all number types (both primitive signed ones and
-user-defined unsigned ones.)
-
-For each type we've generated 4 benchmarks that use `+, -, *` ops (fastops)
-and 4 benchmarks that use `+, -, *, /, %` (allops). Each of the 4 benchmarks uses exactly
-the same arithmetic expressions for all types. Benchmarks on bytes and shorts wrap back
-to corresponding type after each operation.
-
-The split between fastops and allops is important because unsigned division is
-quite a bit slower than signed one on latest release of JDK 8:
-
- Benchmark Type Score Error Units
-
- division Int 289644141.092 ± 1544.707 ops/s
- division UInt 129838344.866 ± 95523.094 ops/s
- division Long 129839962.558 ± 90581.655 ops/s
- division ULong 116493219.034 ± 67688.631 ops/s
-
- remainder Int 289454769.011 ± 94380.057 ops/s
- remainder UInt 111032938.420 ± 679921.289 ops/s
- remainder Long 128315753.345 ± 35932.509 ops/s
- remainder ULong 97470062.788 ± 346773.054 ops/s
-
-And here are the results of composite benchmarks.
-
- Benchmark Type Score Error Units
-
- allop0 Byte 76612958.318 ± 97814.015 ops/s
- allop0 UByte 26160709.822 ± 2098.556 ops/s
- allop0 Short 76800575.238 ± 75373.970 ops/s
- allop0 UShort 27172978.979 ± 3244.075 ops/s
- allop0 Int 82816920.142 ± 50194.565 ops/s
- allop0 UInt 27232792.726 ± 5116.920 ops/s
- allop0 Long 28648964.226 ± 6115.162 ops/s
- allop0 ULong 29657228.040 ± 159758.363 ops/s
-
- allop1 Byte 73715102.215 ± 17282.291 ops/s
- allop1 UByte 26490808.836 ± 86628.862 ops/s
- allop1 Short 73718029.884 ± 19413.132 ops/s
- allop1 UShort 27041330.181 ± 4533.663 ops/s
- allop1 Int 83239625.538 ± 13575.756 ops/s
- allop1 UInt 28425497.966 ± 10927.728 ops/s
- allop1 Long 29251967.961 ± 8278.100 ops/s
- allop1 ULong 30537156.474 ± 14283.996 ops/s
-
- allop2 Byte 53138040.117 ± 7692.219 ops/s
- allop2 UByte 19912528.484 ± 104896.763 ops/s
- allop2 Short 52989318.748 ± 10075.293 ops/s
- allop2 UShort 19828139.740 ± 217.796 ops/s
- allop2 Int 60104405.263 ± 1888.322 ops/s
- allop2 UInt 20576204.367 ± 446.445 ops/s
- allop2 Long 20752333.428 ± 789.741 ops/s
- allop2 ULong 22949083.651 ± 5766.597 ops/s
-
- allop3 Byte 68147811.661 ± 7349.838 ops/s
- allop3 UByte 28016596.929 ± 4795.992 ops/s
- allop3 Short 68147020.665 ± 8444.864 ops/s
- allop3 UShort 29092855.210 ± 12323.477 ops/s
- allop3 Int 93592095.470 ± 2970.030 ops/s
- allop3 UInt 33298135.046 ± 15681.174 ops/s
- allop3 Long 32276341.887 ± 3748.706 ops/s
- allop3 ULong 53345993.564 ± 5486.483 ops/s
-
- fastop0 Byte 174384841.686 ± 13685.151 ops/s
- fastop0 UByte 172490336.775 ± 42178.142 ops/s
- fastop0 Short 174388762.469 ± 10303.837 ops/s
- fastop0 UShort 172545184.374 ± 37150.012 ops/s
- fastop0 Int 335919041.150 ± 121423.806 ops/s
- fastop0 UInt 335925277.378 ± 120408.170 ops/s
- fastop0 Long 339125057.494 ± 71538.513 ops/s
- fastop0 ULong 339306595.964 ± 70387.619 ops/s
-
- fastop1 Byte 174736448.461 ± 9934.579 ops/s
- fastop1 UByte 173817403.787 ± 20752.221 ops/s
- fastop1 Short 174734415.599 ± 9850.473 ops/s
- fastop1 UShort 173460828.250 ± 18068.154 ops/s
- fastop1 Int 285178506.838 ± 129027.835 ops/s
- fastop1 UInt 285137070.275 ± 145958.174 ops/s
- fastop1 Long 285590926.722 ± 147048.419 ops/s
- fastop1 ULong 274695574.679 ± 4878290.228 ops/s
-
- fastop2 Byte 168971931.233 ± 40481.486 ops/s
- fastop2 UByte 169665745.096 ± 27401.842 ops/s
- fastop2 Short 168979347.127 ± 11033.548 ops/s
- fastop2 UShort 169675543.605 ± 19494.266 ops/s
- fastop2 Int 287563728.176 ± 122987.272 ops/s
- fastop2 UInt 287559086.868 ± 126833.074 ops/s
- fastop2 Long 296129286.397 ± 171488.897 ops/s
- fastop2 ULong 296142819.979 ± 167330.949 ops/s
-
- fastop3 Byte 333536457.973 ± 63928.967 ops/s
- fastop3 UByte 339343014.623 ± 119819.041 ops/s
- fastop3 Short 333535961.005 ± 69587.789 ops/s
- fastop3 UShort 339354474.225 ± 121131.393 ops/s
- fastop3 Int 475167307.642 ± 140060.266 ops/s
- fastop3 UInt 475181473.416 ± 116982.494 ops/s
- fastop3 Long 487109297.325 ± 580807.835 ops/s
- fastop3 ULong 487190439.786 ± 737565.041 ops/s
-
-As you can see, fastops results have statistically insignificant differences
-between signed and unsigned numbers. The same is true for allops for `Long` vs
-`ULong`.
-
-Allops are 2-3x slower for `Byte`s, `Short`s and `Int`s, due to the fact that
-unsigned division isn't as well optimised. We can probably make divisions for
-`UByte` and `UShort` faster by using the regular division at the `Int` level,
-but the current implementation does not do that yet.
-
-### Time frame
-
-We propose that unsigned integers be integrated in their user-space form as
-early as possible, ideally in Scala 2.12, should this proposal be accepted in
-time. An implementation is already available for Scalac, and it comes with an
-exhaustive unit test suite.
-
-In the longer term, for 2.13 or 2.14, we propose to evaluate whether the
-benefits of a compiler-space implementation outweigh the risks. The existing
-test suite will make sure that the behavior of operations is unchanged. This
-second phase should probably be studied jointly with the developments of
-ScalaNative.
-
-## Previous discussions and implementations
-
-When
-[Value Classes (SIP-15)](https://docs.scala-lang.org/sips/value-classes.html)
-were first introduced, the possibility to have new numeric types such as
-unsigned integers was mentioned as a motivation. Subsequently, several people
-[came up with implementations](https://groups.google.com/forum/#!topic/scala-sips/xtmUjsY9gTY)
-of unsigned Ints and Longs. Those implementations were however more hacky
-proofs of concept than a really thought-out proposal.
-
-Our proposal improves on those early attempts in several aspects:
-
-* Comprehensive but curated set of operations that are available on unsigned
- integers, in particular no mixing signed and unsigned integers (avoid common
- pitfalls found in other languages)
-* Precise semantics for all operations (a specification)
-* A meaningful notion of equality, which works well with other primitive types
-* Use JDK 8 methods to implement operations that are specific to unsigned
- integers, such as division
-* Complete implementation with a test and benchmark suites
-
-## Out of scope
-
-The following related aspects are out of the scope of this proposal:
-
-### Literal notation for unsigned integers
-
-This proposal does not introduce any literal notation for unsigned integers.
-Instead, we always convert from signed literals, e.g., `5.toUInt`.
-
-Providing literal notation should be done in the context of a SIP for
-generalized user-defined literals.
-
-### Efficient arrays of unsigned integers
-
-We do not plan to address the issue of efficient arrays of unsigned integers.
-Solving this should be part of a broader context for efficient arrays of
-user-defined value classes in general, such as the encoding used in Dotty.
-
-## Unresolved questions
-
-* Should `>>` be available on unsigned integers?
-* Should `null` unbox to 0 for unsigned integers even in their user-space
- implementation? This would require some more changes to the compiler.
-
-## References
-
-1. [Implementation mostly in user-space for scalac/JVM](https://github.com/scala/scala/compare/2.12.x...sjrd:uints)
diff --git a/_sips/sips/2016-09-09-inline-meta.md b/_sips/sips/2016-09-09-inline-meta.md
deleted file mode 100644
index 8aa401d125..0000000000
--- a/_sips/sips/2016-09-09-inline-meta.md
+++ /dev/null
@@ -1,1012 +0,0 @@
----
-layout: sip
-title: SIP-28 and SIP-29 - Inline meta
-vote-status: dormant
-vote-text: This proposal needs an owner.
-permalink: /sips/:title.html
-redirect_from: /sips/pending/inline-meta.html
----
-
-**By: Eugene Burmako, Sébastien Doeraene, Vojin Jovanovic, Martin Odersky, Dmitry Petrashko, Denys Shabalin**
-
-## History
-
-| Date | Version |
-| ---------------|----------------------------------------------|
-| Aug 22nd 2016 | Initial Pre-SIP |
-| Sep 9th 2016 | Initial SIP |
-
-## Preface
-
-This document represents the culmination of a design process that spans several years.
-We did our best to extensively evaluate the design space and comprehensively document our findings.
-
-As a result, this is going to be a very long read. If you're just interested in getting a quick idea
-of the proposal, you can read just the ["Intuition"][Intuition] section.
-
-## Motivation
-
-Def macros and macro annotations have become an integral
-part of the Scala ecosystem. They marry metaprogramming with types
-and work in synergy with other language features, enabling [practically important use cases][MacroUsecases].
-
-However, in addition to having the reputation of an indispensable tool, Scala macros have also gained notoriety
-as an arcane and brittle technology. The most common criticisms of Scala macros concern their
-subpar tool support and overcomplicated metaprogramming API powered by scala.reflect.
-
-While trying to fix these problems via evolutionary changes to the current macro system,
-we have realized that they are all caused by the decision to use compiler internals as the underlying metaprogramming API.
-Extensive use of desugarings and existence of multiple independent program representations may have worked well
-for compiler development, but they turned out to be inadequate for a public API.
-
-The realization that we cannot make meaningful progress while staying within the confines of scala.reflect
-meant that our macro system needs a redesign. We took the best part of the current macros - their smooth integration
-into the language - and discarded the rest, replacing scala.reflect with a better metaprogramming API
-and coming up with a lightweight declaration syntax. In this document, we present the current version of the design.
-
-## Table of contents
-
- * [Intuition](#intuition)
- * [Def macros](#def-macros)
- * [Discussion](#discussion)
- * [Inline/meta](#inlinemeta)
- * [Language features](#language-features)
- * [Inline definitions](#inline-definitions)
- * [Inline reduction](#inline-reduction)
- * [Meta expressions](#meta-expressions)
- * [Meta expansion](#meta-expansion)
- * [Meta APIs](#meta-apis)
- * [Design considerations](#design-considerations)
- * [Scala.meta](#scalameta)
- * [Tool support](#tool-support)
- * [Losing whiteboxity](#losing-whiteboxity)
- * [Losing compiler internals](#losing-compiler-internals)
- * [Macro annotations](#macro-annotations)
- * [Why inline](#why-inline)
- * [Out of scope](#out-of-scope)
- * [Conclusion](#conclusion)
- * [Credits](#credits)
-
-## Intuition
-
-In this section, we will walk through writing and using compile-time metaprograms that implement a subset of functionality
-expected of language-integrated queries. Without going into much detail,
-we will obtain high-level intuition behind the underlying mechanisms
-
-[Language-integrated query][Linq] is a technique that achieves smooth integration of database queries with programming languages.
-A common approach to LINQ, popularized by .NET Framework 3.5, consists in representing datasources
-by collection-like library types and then allowing users to write queries as series of calls to these types
-using familiar higher-order methods like `map`, `filter` and others.
-
-We will now develop a sketch of a database access library built in the spirit of LINQ.
-In this sketch, we will intentionally forgo the practicalities of building a LINQ library
-(e.g. mapping from classes to datasources, design of internal ASTs, error reporting, etc.)
-in order to clearly illustrate the role played by compile-time metaprogramming.
-
-Below we define a trait `Query[T]` that encapsulates a query returning a collection
-of objects of type `T`. Next to it, we define its children `Table` and `Map` that represent
-particular types of queries. `Table` stands for a datasource that knows about the underlying type
-(in this sketch, we use an imaginary typeclass `TypeInfo` for that purpose).
-`Map` models a restricted subset of SQL SELECT statements via a simple `Node` AST.
-
-```
-trait Query[T]
-case class Table[T: TypeInfo]() extends Query[T]
-case class Select[T, U](q: Query[T], fn: Node[U]) extends Query[U]
-
-trait Node[T]
-case class Ref[T](name: String) extends Node[T]
-
-object Database {
- def execute[T](q: Query[T]): List[T] = { ... }
-}
-```
-
-In this model, a SQL query string `"SELECT name FROM users"` is represented as `Select(Table[User](), Ref[String]("name"))`.
-Queries like the one just mentioned can be run via `Database.execute` that translates them into SQL, sends the SQL to the database,
-receives the response and finally translates it to data objects. For the sake of simplicity, we will assume such implementation as a given.
-
-The key aspect of a LINQ facility is a convenient notation for queries.
-Arguably, none of the aforementioned ways to write queries can be called convenient.
-SQL, as any string-based representation, is prone to syntax errors, type errors and injections.
-Explicit instantiation of `Query` objects is very verbose, and still doesn't solve all type errors.
-
-In this sketch, we define a LINQ API in the form of methods that mirror the collection API
-from the standard library. We would like our users to be able to encode queries in intuitively looking,
-statically typed calls to this API, e.g. `users.map(u => u.name)`, and then have our library translate these
-calls into calls to `Query` constructors.
-
-```
-object Query {
- implicit class QueryApi[T](q: Query[T]) {
- def map[U](fn: T => U): Query[U] = { ... }
- }
-}
-
-case class User(name: String)
-val users = Table[User]()
-users.map(u => u.name)
-// translated to: Select(users, Ref[String]("name"))
-```
-
-Among other ways, the desired effect can be achieved with compile-time metaprogramming.
-A metaprogram that runs at compile time can detect all calls to `Query.map` and rewrite them
-to invocations of `Select` with parameters of `map` transformed to corresponding instances of `Node`.
-
-### Def macros
-
-Before looking into the design of the new macro system, let's see how the problem at hand
-can be solved using the currently available macro system.
-
-```
-import scala.language.experimental.macros
-
-object Query {
- implicit class QueryApi[T](q: Query[T]) {
- def map[U](fn: T => U): Query[U] = macro QueryMacros.map
- }
-}
-```
-
-`QueryApi.map` is called a macro def. Since macros are experimental,
-in order to define a macro def, it is required to either have `import scala.language.experimental.macros`
-in the lexical scope of the definition or to enable the corresponding setting in compiler flags.
-This is only necessary to define a macro def, not to use it.
-
-Macro defs look like normal methods in the sense that
-they can have term parameters, type parameters and return types.
-Just like regular methods, macro defs can be declared either inside or outside of classes,
-can be monomorphic or polymorphic, and can participate in type inference and implicit search.
-Refer to [Appendix A][AppendixInteraction] for a detailed account of differences
-between macro defs and regular defs.
-
-Bodies of macro defs have an unusual syntax. The body of a macro def starts with the conditional keyword `macro` and
-is followed by a possibly qualified identifier that refers to a macro impl,
-an associated metaprogram run by the compiler when it encounters corresponding macro applications.
-Macro impls are defined as shown below.
-
-```
-import scala.reflect.macros.blackbox.Context
-
-object QueryMacros {
- def map(c: Context)(fn: c.Tree): c.Tree = {
- import c.universe._
- ...
- }
-}
-```
-
-Macro impls take a compiler context that represents the entry point into the macro API.
-The macro API consists of a general-purpose metaprogramming toolkit provided by scala.reflect
-and several specialized facilities exclusive to macro expansion.
-A typical first line of a macro impl is `import c.universe._` that makes the entire scala.reflect API available to the metaprogrammer.
-
-In addition to the compiler context, for every term parameter of a macro def, its macro impl
-takes a term parameter that carries a representation of the corresponding argument of the macro application.
-Macro impls can also get ahold of representation of type arguments, but this functionality is unnecessary for this example.
-
-A macro impl returns an abstract syntax tree, and this AST replaces the original macro application in the compilation pipeline.
-This is how we're going to perform the LINQ translation of calls to `Query.map`.
-
-```
-import scala.reflect.macros.blackbox.Context
-
-object QueryMacros {
- def map(c: Context)(fn: c.Tree): c.Tree = {
- import c.universe._
-
- // c.prefix looks like:
- // Query.QueryApi[]()
- val q"$_.$_[$_]($prefix)" = c.prefix
-
- val node: Tree = fn match {
- case q"($param) => $body" =>
- val sym = param.symbol
- body match {
- case q"$qual.$_" if qual.symbol == sym =>
- q"Ref[${body.tpe}](${sym.name.decodedName.toString})"
- }
- }
-
- q"Select($prefix, $node)"
- }
-}
-```
-
-In the listing above, we handle several challenges of macro writing.
-First, we get ahold of the prefix of the application, i.e. the `users` part of `users.map(u => u.name)`.
-Unlike macro arguments, prefixes aren't mapped onto parameters of macro impls,
-so we need to use the dedicated `c.prefix` API.
-
-The next challenge is to extract the prefix from the macro application.
-Since `Query.map` is an extension method, the actual prefix is going to be `QueryApi(users)`, not `users`,
-therefore we need to apply some non-trivial effort.
-
-One way of getting to the query is to access the corresponding field of the implicit class,
-doing something like `QueryApi(users).q`. Unfortunately, this is out of the question, because `q` is private,
-and we cannot make it public without adding an extension method called `q` to `Query`.
-
-Another way of achieving the desired result is to take apart the abstract syntax tree representing `QueryApi(users)`,
-extracting `users` as the argument of the application.
-It looks like quasiquotes,
-which are supposed to provide a convenient WYSIWYG interface to deconstructing Scala code,
-are going to be a perfect fit.
-
-Unfortunately for macro writers, the Scala compiler heavily desugars code during compilation,
-so even the modest `QueryApi(users)`
-will get to the macro impl in the form of `Query.QueryApi[User](users)`.
-Therefore the naive `q"$_($query)"` quasiquote is not going to work,
-and we need to apply additional effort. With a bit of knowledge about compiler internals,
-we take care of this.
-
-The final challenge is code generation.
-The pattern match in listing above transforms the user-provided lambda expression into an equivalent `Node`.
-Since our sketch only supports `Ref`, we only support simple lambdas that select a field from a parameter.
-Finally, we produce the macro expansion that has the desired shape.
-
-### Discussion
-
-Note how the ability of def macros to access types dramatically improves user experience in comparison with purely syntactic translation.
-First, even before `Query.map` gets to expand, the compiler typechecks its argument, making sure that
-queries are well-typed. Secondly, we have a way to reliably check the shape of the supported lambda.
-The symbol comparison in the nested pattern match makes sure that
-the qualifier of field selection refers precisely to the parameter of the lambda
-and not to something else accidentally having the same name. Finally, we use information about the type of the body
-in order to figure our the mandatory type parameter of `Ref`.
-
-Also note another piece of knowledge about compiler internals that was essential to robust operation of the macro.
-When generating a `Ref`, we can't simply call `sym.name.toString`, because the Scala compiler internally mangles non-alphanumeric names.
-If the parameter of the lambda has such a name, a simple `toString` will produce unsatisfying results,
-which is why we have to call `Name.decodedName` first.
-
-Before we conclude, let's highlight a very common metaprogramming mistake that we've just made in `QueryMacros.map`.
-Def macros are unhygienic, which means that they don't prevent inadvertent name capture, i.e. scenarios like the following.
-
-```
-val Select = "hijacked!"
-users.map(u => u.name)
-
-// error: too many arguments for
-// method apply: (index: Int)Char in class StringOps
-// users.map(u => u.name)
-// ^
-```
-
-If the macro user accidentally defines a term called `Select` or `Ref`, our macro is going to stop working
-with what looks like a nonsensical error message. Because principled tool support wasn't among the design goals of
-our macro system, a macro user getting this error is mostly helpless apart from trying to use internal compiler options
-that print all macro expansions and then going through the resulting wall of text.
-
-One reliable approach to prevent hygiene errors is to use fully-qualified names for external references and
-to generate unique names for local variables. A somewhat more concise, but potentially much more laborious approach is to explicitly
-assign symbols to references and definitions emitted in macro expansions.
-This approach often requires extensive knowledge of compiler internals, so it is less frequent in the wild.
-Common to both of these approaches is that they require explicit attention from metaprogrammers and
-failures to apply them typically go unnoticed.
-
-To sum it up, even in this simple macro we encountered situations where knowledge of compiler internals
-(the desugaring of the `QueryApi` application, the fact that non-alphanumeric names are encoded) was essential.
-We also ran into problems with tool support and hygiene, which demonstrates how important they are to a macro system.
-These are all common criticisms of def macros.
-
-### Inline/meta
-
-User interface of def macros is a seamless extension to the existing language interface.
-Thanks to macro defs looking like regular methods and macro applications looking like regular method applications,
-macro users are likely to not even realize that they are using macros.
-
-Unfortunately, metaprogrammer interface leaves much to be desired. First, in the current macro system,
-metaprograms have to be defined separately from their signatures, typically involving helper objects and
-duplication of parameters. Secondly, the underlying metaprogramming API requires
-knowing bits and pieces of compiler internals. For example, in the case of `Query.map`,
-the metaprogrammer had to know the internal representation of the `QueryApi` application
-and internal details of how names are represented.
-
-New-style macros provide the same user interface, and at the same time significantly improve metaprogrammer
-interface by enabling lightweight macro declaration syntax and using a better metaprogramming API.
-
-```
-object Query {
- implicit class QueryApi[T](q: Query[T]) {
- inline def map[U](fn: T => U): Query[U] = meta {
- import scala.meta._
-
- val q"$_($prefix)" = this
-
- val node: Tree = fn match {
- case q"($name: $_) => $body" =>
- body match {
- case q"$qual.$_" if qual =:= name =>
- q"Ref[${body.tpe}](${name.toString})"
- }
- }
-
- q"Select($prefix, $node)"
- }
- }
-}
-```
-
-At a glance, new-style macros simply forgo a noticeable amount of ceremony,
-merging the previously disparate macro defs and macro impls as well as swapping around a few keywords in the process.
-The underlying metaprogram doesn't seem to have changed much,
-still using quasiquotes and key APIs like `Tree.tpe` and `Name.toString`.
-
-First impression notwithstanding, the new design revamps a lot of underlying mechanisms.
-Below we provide a high-level overview of our new approach to compile-time metaprogramming,
-and refer curious readers to ["Language features"][LanguageFeatures] for information concerning the new expansion mechanism
-and to ["Scala.meta"][ScalaMetaSection] for details about the new metaprogramming API.
-
-**Expansion mechanism**. The new design takes the notions of inlining and compile-time execution
-from the current macro system and turns them into separate language features.
-
-The goal of the `inline` modifier on `Query.map` is to signify that applications of this method are inlined,
-i.e. replaced with the method body, in which references to enclosing `this`, self, and formal parameters are rewritten accordingly
-(see ["Inline reduction"][InlineExpansion] for details).
-
-The goal of the `meta` keyword is to demarcate code that executes at compile time and to provide
-that code with [scala.meta capabilities][MetaApis].
-The metaprogram written inside the meta scope has access to multiple implicit capabilities
-and can get ahold of representations of certain values and types from lexical scope.
-The compiler runs this metaprogram, interprets its result as an abstract syntax tree
-and replaces the meta expression with that tree (see ["Meta expansion"][MetaExpansion] for details).
-
-When the compiler encounters a call to `Query.map`,
-it simply inlines the body of `map` into the callsite without performing any compile-time function execution.
-For the running example of `users.map(u => u.name)`,
-this inlining produces the result illustrated in the listing below.
-
-```
-{
- val prefix$1: QueryApi = QueryApi(users)
- val fn$1: User => String = u => u.name
- meta {
- import scala.meta._
-
- val q"$_($prefix)" = q"QueryApi(users)"
-
- val node: Tree = q"u => u.name" match {
- case q"($name: $_) => $body" =>
- body match {
- case q"$qual.$_" if qual =:= name =>
- q"Ref[${body.tpe}](${name.toString})"
- }
- }
-
- q"Select($prefix, $node)"
- }
-}
-```
-
-Before inlining a method application, the compiler first hoists the prefix and by-value arguments of the application
-into temporary variables. This is done in order to guarantee that applications of inline methods
-are semantically equivalent to applications of regular methods.
-
-Afterwards, the compiler replaces the application with a block that consists of hoisted values and the transformed method body.
-In the method body, all regular references to `this` and self as well as
-by-value parameters are rewritten to references to the corresponding temporary variables.
-If such references are part of a meta scope, they are replaced with scala.meta-based representations of
-the prefix and the corresponding arguments, without going into temporary variables.
-
-When the compiler comes across a meta expression that isn't part of an inline method,
-it executes the code inside the expression and replaces the expression with the result of execution.
-For our running example, this produces the desired expansion that invokes query constructors corresponding
-to the LINQ notation.
-
-**New metaprogramming API**. Scala.meta noticeably improves on scala.reflect in the convenience of the API
-and no longer requires metaprogrammers to understand compiler internals in order to write macros.
-
-In particular, we don't need to know that construction of the implicit class involves
-expanding the reference to `QueryApi` into a fully-qualified name and inferring the missing type argument.
-The particular implementation of the scala.meta API that runs the meta expression may or may not
-do these desugarings, and scala.meta shields us from this fact.
-We can use the WYSIWYG pattern `q"$_($prefix)"` in order to unwrap the original prefix of the call.
-
-Moreover, we don't have to worry about the compiler internally mangling non-alphanumeric names.
-Again, even if the underlying macro engine internally does name mangling, scala.meta abstracts away such implementation details.
-
-Finally, we are able to improve on scala.reflect thanks to more precise quasiquotes.
-If in the current macro system, we used `q"($name: $_) => ..."` to match the `fn` argument,
-`name` would capture a scala.reflect `Name` that doesn't carry any semantic information.
-In scala.meta, names are full-fledged trees, so we can use `Tree.=:=` to semantically compare the name
-with the qualifier of the field selection.
-
-In order to use semantic APIs, scala.meta metaprograms need the [mirror capability][ScalaMetaSection],
-so it is implicitly provided inside meta scopes. As a result, meta expressions can use the full spectrum
-of APIs available in scala.meta.
-
-**To put it in a nutshell**, the new-style macro system combines two language features:
-[inline definitions][InlineDefs] and [meta expressions][MetaExprs]
-in order to provide a more lightweight syntax for the current def macros. Moreover, this macro system
-does a switchover from scala.reflect to scala.meta, featuring a new API that is more convenient and
-doesn't require compiler knowledge to be utilized effectively.
-
-## Language features
-
-### Inline definitions
-
-We introduce a new reserved word: `inline`, which can be used as a modifier for
-concrete vals, concrete methods and parameters of inline methods, as illustrated in the listing below.
-
-```
-inline val x = 4
-
-inline def square(x: Double) = x * x
-
-inline def pow(b: Double, inline n: Int): Double = {
- if (n == 0) 1
- else b * pow(b, n - 1)
-}
-```
-
-Inline vals are guaranteed to be compile-time constants, superseding the existing approach
-of declaring such constants with `final val`. Inline parameters get the same treatment, adding a previously
-non-existent functionality of guaranteeing that an argument of a method is a compile-time constant.
-
-A value is considered to be a compile-time constant if it is a Scala literal,
-or it is equivalent to one by the means of inline/meta expansion and constant folding.
-Future work may extend this notion to custom classes, but this discussion lies outside the scope of this proposal.
-
-Inline defs are guaranteed to be inlined at compile time, superseding the existing approach of
-annotating methods with the `@inline` annotation. After introducing `inline`, we expect to deprecate and phase out `@inline`.
-
-The problem with `@inline` is that it doesn't provide guarantees.
-As specified in documentation,
-`@inline` tells the compiler to "try especially hard to inline the annotated method".
-However, different backends interpret this request differently.
-The JVM backend ignores this annotation if optimizations are disabled and sometimes skips inlining even when optimizations are enabled.
-Both Scala.js and Scala Native always inline methods that are marked with this annotation.
-In contrast, `inline` achieves guaranteed inlining, regardless of the backend.
-
-Inline defs are very similar to macro defs in the sense that they look like regular defs and that they expand at compile time.
-As a result, the rules in [Appendix A][AppendixInteraction] also apply to inline defs with three exceptions.
-
- 1. Inline defs are effectively final; they cannot be overridden. Inline members also never override other members.
-The idea of allowing macro defs to override regular defs didn't find compelling use cases, so we prohibit this for inline defs.
-
- 1. Inline defs can have default parameters. Not supporting default parameters for macro defs was an oversight
-of the initial design, so now we fix this oversight in the new macro system.
-
- 1. Inline defs have regular bodies, just like regular defs. When an inline def is typechecked, its body
-is typechecked according to the usual rules, which means that inline defs are eligible for return type inference. If an inline def
-doesn't explicitly specify its result type, the result type gets inferred from the type of its body.
-
-### Inline reduction
-
-When the compiler encounters certain patterns of code that involve references to inline vals and applications of inline defs,
-it will perform the rewritings provided below, if and only if these patterns appear outside the bodies of inline vals and defs.
-
- 1. If `prefix.v` refers to an inline value, replace the expression with the body of `v`.
-
- 1. If `prefix.f[Ts](args1)...(argsN)` refers to a fully applied inline method, hoist the prefix and the arguments
-into temporary variables with fresh names and then replace the expression with the method body. In the body, replace parameter references
-with references to temporary variables created for the corresponding arguments. Also, replace enclosing `this`
-and self references with references to the temporary variable created for the prefix.
-
- ```
- {
- val prefix$1 = prefix
- val param1$1 = arg1
- ...
- val paramN$1 = argN
-
- }
- ```
-
- The hoisting is intended to preserve the semantics of method applications under inlining.
- A method call should have the same semantics with respect to side effects independently
- on whether the method was made inline or not.
- If an inline method has by-name parameters, then corresponding arguments are not hoisted.
-
- The rewriting is done in accordance with hygiene. Any references from the method body to its lexical scope
- will be kept in the rewritten code. If the result of the rewriting references private or protected definitions
- in the class that defines the inline method, these references will be changed to use accessors generated automatically by the compiler.
- To ensure that the rewriting works in the separate compilation setting,
- it is critical for the compiler to generate the accessors in advance.
- Most of these accessors can be pregenerated by analyzing the bodies of inline methods,
- except for members that are referred to inside meta scopes.
- Such references are disallowed, because it is impossible to generate them in advance.
-
- 1. If `prefix.f[Ts](args1)...(argsN)` refers to a partially applied inline method, an error is raised.
-Eta expansion of inline methods is prohibited.
-
-The rules of inline reduction are similar to the rules of feature interaction for macro applications ([Appendix A][AppendixInteraction])
-as well as relevant parts of the rules of def macro expansion ([Appendix B][AppendixExpansion]) with four exceptions.
-
- 1. Inline reductions in their current form preclude whitebox expansion.
-Since bodies of inline vals and defs are typechecked when their definitions are typechecked,
-potential meta expansions that may happen afterwards won't be able to change their types.
-Implications of this are discussed in ["Losing whiteboxity"][Whiteboxity].
-
- 1. By-value and by-name arguments behave differently. By-value arguments are hoisted in temporary variables,
-while by-name arguments remain as they were. This doesn't affect meta expansions,
-but it does make a semantic difference for parts of inline definitions that are not inside meta scopes.
-Note that `this` and self references always follow the by-value scheme,
-because there is no syntax in Scala that allows to define them as by-name.
-
- 1. Named and default arguments are fully supported. Again, not including them in the initial release of def macros
-was an oversight, which is now fixed.
-
- 1. The rules of rewriting mandate the "outside in" style, i.e. calls to inline methods are expanded before possible calls
-to inline methods in their prefixes and arguments. This is different from how the "inside out" style of def macros,
-where prefixes and arguments are expanded first. Previously, it was very challenging to
-take a look at unexpanded trees, but now the metaprogrammer can switch between unexpanded and expanded views using scala.meta.
-
-From the discussion above, we can see that inline reduction closely resembles the inlining aspect of the current macro system.
-The only significant difference is lack of support for whitebox expansion, which will be discussed in ["Losing whiteboxity"][Whiteboxity].
-
-### Meta expressions
-
-A meta expression is an expression of the form `meta { ... }`, where `{ ... }` is some block of Scala code, called meta scope.
-(In fact, `meta` may prefix arbitrary expressions, but blocks are expected to be used most commonly).
-
-Meta expressions can appear both
-in the bodies of inline methods (then their expansion is going to be deferred until the enclosing method expands)
-and in normal code (in that case, their expansion will take place immediately at the place where the meta expression is written).
-
-Meta scopes can contain arbitrary code, but they must return values that are either of type `scala.meta.Term` or are convertible
-to it via the `scala.meta.Lift` typeclass. There are standard instances of the typeclass that lift simple values to literals
-as well as ones that support frequently used collections of liftable values. Metaprogrammers may define and use their own instances
-as long as they are available in corresponding meta scopes.
-
-Inside meta scopes, metaprogrammers can use a combination of general-purpose and expansion-specific metaprogramming facilities.
-Refer to ["Meta APIs"][MetaApis] for more information.
-
-Since meta scopes must return scala.meta trees, and scala.meta trees are by design statically untyped,
-the type of meta expressions can't be computed from the inside
-and has to come from the outside. Therefore, meta expressions can only be used in contexts that specify an expected type.
-
-```
-// allowed, expected type provided by the return type
-inline def map[U](fn: T => U): Query[U] = meta { ... }
-
-// not allowed, no explicit return type
-val x = meta { ... }
-
-// allowed, expected type of a condition is Boolean
-if (meta(T.isPrimitive)) { ... }
-```
-
-Meta scopes can reference names in their lexical scope outside the enclosing meta expression.
-While crossing the `meta` boundary, references change their meaning.
-Concretely, here's how the transformation works for different references:
-
-**Inline vals and inline parameters**. These are guaranteed to be compile-time constants,
-so an inline value of type `T` is available inside a meta scope as a regular value of type `T`.
-
-**Inline defs**. When viewed from within a meta scope, inline defs become tree transformers.
-Types of their inline parameters are unchanged, their non-inline parameters and return type become typed as `scala.meta.Term`.
-For example, `inline def pow(b: Double, inline n: Int): Double` transforms into
-`def pow(b: scala.meta.Term, n: Int): scala.meta.Term`.
-
-**Term parameters of an inline method**. References to statically known term parameters,
-enclosing `this` or self become values of type `scala.meta.Term`. This is similar to `c.Expr`/`c.Tree`
-parameters of macro impls, but more lightweight, because there's no need
-to declare these parameters explicitly.
-
-**Type parameters of an inline method**. References to statically known type parameters become values
-of type `scala.meta.Type`. This is similar to `c.WeakTypeTag` parameters of macro impls,
-but more lightweight, because metaprogrammers don't need to explicitly manifest their interest in given type parameters
-in order to get access to their representations.
-
-This rule can create clashes between term and type namespaces.
-If such a clash happens, i.e. if a reference to a type parameter is ambiguous with an eponymous term,
-the compiler emits an error. This is regrettable, but Scala naming conventions make this situation unlikely,
-and there is always a workaround of renaming the type parameter.
-
-**Global definitions**. Statically available types and terms, e.g. `List` or `Int`,
-are usable inside meta scopes as themselves. This means that meta expressions, just like macro impls,
-can use the standard library and arbitrary third-party libraries.
-
-**Other definitions**. Macro scopes cannot reference definitions that don't fall into one of the categories mentioned above.
-This outlaws usages of local definitions - both terms and types. Such definitions may refer to state that only
-exists at runtime, so we prohibit them altogether. This has no analogues in the current macro system, because macro impls
-must be defined in static methods, which means that by definition their scope cannot contain local definitions.
-
-In other words, definitions that are statically available outside meta scopes remain available in meta scopes,
-term and type arguments of inline methods become available as their representations,
-while signatures of inline methods are recursively transformed according to the rules above.
-
-From the discussion above, we can see that meta expressions provide an analogue of the compile-time execution part
-of the current macro system. In addition to achieving feature parity, meta expressions also improve on the corresponding part of def macros
-by allowing metaprograms to easily obtain representations of their term and type parameters and
-making it possible to run anonymous snippets of metaprogramming code without wrapping them in a dedicated macro.
-
-### Meta expansion
-
-When the compiler encounters a meta expression that appears outside the bodies of inline vals and defs,
-it expands that expression as described below.
-
-A meta expression is expanded by evaluating its body and replacing the original meta expression with an expression
-that represents the result of the evaluation. The compiler is responsible for providing [the capabilities][MetaApis]
-necessary for meta scopes to evaluate and for converting between its internal representation for language model elements
-and representations defined in scala.meta, such as `scala.meta.Term` and `scala.meta.Type`.
-
-Meta expansion works very similarly to the relevant part of the def macro expansion pipeline ([Appendix B][AppendixExpansion]).
-Code in the meta scope is precompiled and then reflectively invoked by the compiler, sharing the class loader with other
-metaprograms run inside the compiler. Expansion can return normally or can be interrupted with an exception. Expansion results
-are typechecked against the expected type of the meta expression. Typecheck results are upcast to the expected type in blackbox style,
-as discussed in ["Losing whiteboxity"][Whiteboxity].
-
-Another practicality of meta expansion is the protocol of communication between `inline` and `meta`.
-On the one hand, a reasonable default for inlining that doesn't involve meta expressions is to hoist prefixes and by-value arguments
-as described in ["Inline reduction"][InlineExpansion]. On the other hand, macro writers default to having unfettered access to
-abstract syntax trees without needing to write additional boilerplate.
-These two design preferences are at odds with each other.
-
-Therefore, in our design `inline` both hoists eligible components of inline applications and passes their original
-representations into meta expressions. This way, both defaults are satisfied and, additionally, if meta expressions need
-to hoist something, they can use the new `hoist` API.
-
-In the case when an inline method consists in a single meta expression, the new macro engine removes temporary variables
-that are produced by hoisting and aren't claimed by `hoist`. In the case when an inline method doesn't contain
-meta expressions, all temporary variables are retained, because they are necessary to express method application semantics.
-Finally, in the case of a hybrid inline method, meta expressions can look into representations of hoisted expressions,
-but they cannot use them in their expansions without calling `hoist` first in order to avoid reordering or duplicating side effects.
-
-In a nutshell, meta expansion closely resembles the compile-time execution aspect of the current macro system.
-The only nuance is the interaction with hoisting performed by the mechanism of inline reduction.
-
-### Meta APIs
-
-In scala.meta, all APIs are available out of the box after doing `import scala.meta._`.
-However, in order to use most of them, metaprogrammers must have access to certain capabilities
-(see ["Scala.meta"][ScalaMetaSection] for details).
-
-Meta scopes provide two different capabilities. First, there are general-purpose metaprogramming facilities,
-enabled by a `Mirror`. Secondly, there are expansion-specific facilities enabled via a newly introduced `Expansion`.
-
-Mirrors are explained in ["Scala.meta"][ScalaMetaSection], and in this section
-we will cover the functionality enabled by expansions. We will also compare this functionality
-with macro APIs from the current macro system.
-
-First, `Context.prefix` is no longer necessary,
-because meta expressions can refer to prefixes of enclosing inline definitions via `this`.
-`Context.macroApplication` is unnecessary as well, because meta expressions may be written outside inline vals and defs,
-which means that they won't have a corresponding application at all. In the rare cases when it is useful to know
-the position that spans the entire inline application, it can be obtained by traversing prefixes or arguments via `Tree.parent`.
-
-Secondly, much like their counterparts in the current macro system, meta APIs support diagnostic messages.
-Since the only prevalent macro APIs in this group is `Context.abort`, with `Context.error`, `Context.warning`
-and others seeing rare use, we only expose `abort` that works similarly to its predecessor.
-
-Thirdly, we no longer expose APIs that tightly integrate with compiler internals. Most of these APIs take care
-of the limitations of the scala.reflect language model, so in the new metaprogramming framework based on scala.meta
-they are simply unnecessary. Others feature advanced functionality that accesses or manipulates internal compiler state,
-and this exactly the kind of thing that we would like to avoid in the macro system. We discuss the implications in
-["Losing compiler internals"][CompilerInternals].
-
-Finally, we also support `hoist`, which takes a `scala.meta.Term`, precomputes it in a temporary variable
-outside the meta expansion and returns a reference to it.
-Apart from `inline`-compatible precomputation of prefixes and arguments,
-this functionality seems relevant to solving the problem of sharing expansions of [implicit materializers][Materialization],
-so we are confident that it's a useful addition to the macro API.
-
-## Design considerations
-
-### Scala.meta
-
-Scala.meta is a clean-room implementation of a metaprogramming toolkit for Scala,
-designed to be simple, robust and portable. We are striving for scala.meta to become a successor of scala.reflect,
-the current de facto standard in the Scala ecosystem.
-
-We have recently released Scala.meta 1.0.0 that features support for syntactic APIs, such as parsing, tokenization,
-quasiquotes and prettyprinting. We are currently working on Scala.meta v2 that will enable semantic APIs, such as
-typechecking, name resolution and others.
-
-In [Appendix C][AppendixMeta], we provide a high-level overview of the architecture of scala.meta
-along with several practical examples that illustrate its functionality.
-
-### Tool support
-
-The key innovation of the new macro system is the fact that it's based on scala.meta, which finally makes it feasible to
-provide third-party implementations of mirrors.
-
-There now exists a prototype implementation of an IntelliJ mirror, and, in further effort of Mikhail Mutcianko from the IntelliJ team,
-this mirror has become the foundation for [an interactive expander of new-style macro annotations][PrototypeIntellij].
-This recent advancement strongly suggests that it was the right choice to bet on scala.meta to fix
-code compehension and error reporting issues with the current macro system.
-
-This takes some pressure off whitebox macros. In the current macro system, there is a preference towards blackbox macros,
-because they are much friendlier to IntelliJ. Once we have a fully-working mirror for IntelliJ, user experience of blackbox
-and whitebox macros should be equivalent. For additional discussion of whiteboxity from a language design and compiler development
-perspective, refer to ["Losing whiteboxity"][Whiteboxity].
-
-Improvements in support for incremental compilation, testing and debugging also hinge on a capability of scala.meta
-to enable custom mirror implementations.
-However, they also require significant new functionality to be developed in the corresponding tools
-([additional dependency tracking mechanisms for the incremental compiler][SbtMacroSupport] and changes to the vanilla debugger in IDEs).
-
-### Losing whiteboxity
-
-It is desirable for the new design to provide reasonable feature parity with the
-current macro system. So far, the biggest digression from this course is giving up whitebox expansion.
-In this section, we discuss what it will cost us to follow this through, identify the aspects of the new design that
-prevent whiteboxity and propose alternatives.
-
-The main motivation for getting rid of whitebox expansion is simplification - both of the macro expansion pipeline
-and the typechecker. Currently, they are inseparably intertwined, complicating both compiler evolution and tool support.
-Therefore, the new design tries to disentangle these systems.
-
-Let's recapitulate the limitations that def macro expansion applies to applications of blackbox macros,
-outlining the most important use cases that blackboxity cannot express. This won't give us the full picture,
-because there are many macros in the wild that we haven't classified, but nonetheless it will provide an understanding
-of the significant chunk of the Scala macros ecosystem.
-
- 1. When an application of a blackbox macro expands into a tree `x`, the expansion is wrapped into a type ascription `(x: T)`,
-where `T` is the declared return type of the blackbox macro def with type arguments and path dependencies applied in consistency
-with the particular macro application being expanded.
-This invalidates blackbox macros as an implementation vehicle for [anonymous type providers][AnonymousTypeProviders].
-
- 1. When an application of a blackbox macro is used as an implicit candidate, no expansion is performed until the macro
-is selected as the result of the implicit search.
-This makes it impossible to dynamically calculate availability of implicit macros,
-precluding some advanced aspects of [materialization][Materialization].
-
- 1. When an application of a blackbox macro still has undetermined type parameters after the Scala type inference algorithm has finished
-working, these type parameters are inferred forcibly, in exactly the same manner as type inference happens for normal methods.
-This makes it impossible for blackbox macros to influence type inference, prohibiting [fundep materialization][Materialization].
-
- 1. When an application of a blackbox macro is used as an extractor in a pattern match,
-it triggers an unconditional compiler error, preventing [customizations of pattern matching implemented with macros][ExtractorMacros].
-This precludes blackbox macros from providing precise types to values extracted from patterns written in external DSLs,
-preventing a library-based implementation of quasiquotes.
-
-As we can see, whitebox expansion plays an important role in several use cases, the most practically significant
-of them being fundep materialization and quasiquote patterns. Fundep materialization is paramount to the design of Shapeless.
-Quasiquote patterns are an integral part of writing any kinds of macros - both blackbox and whitebox - which is the main
-reason to use scala.reflect.
-
-It is now clear that our desire for simplification is at odds with the ways how the Scala community uses macros.
-In order to resolve the apparent conflict, we outline several solutions, whose evaluation we leave for later.
-
-**Give up on simplification**. This is probably the most obvious approach, in which we admit
-that tight coupling with the typechecker is intrinsic to the essence of Scala macros and change the new design
-to enable whitebox expansion.
-
-Concretely, accommodating whiteboxity in the new macro system requires changing the aspects of the new design
-specified in ["Inline reduction"][InlineExpansion] and ["Meta expansion"][MetaExpansion] according to the
-plan provided below.
-
- * Force inline reductions and meta expansions inside the typechecker. Currently, both the rules of inline reduction
-and the rules of meta expansion are intentionally vague about the exact point in the compilation pipeline that does expansions,
-but whiteboxity will leave us no room for that.
- * Delay typechecking of the bodies of inline vals and defs until their expansion. Meta expressions inside inline definitions
-are not expanded, which means that eager typechecking of these definitions precludes whitebox expansion.
- * Allow using meta expressions without expected type. This captures the main idea of whitebox expansion, in which compile-time
-metaprogramming has the final say about the type of transformed snippets of code.
-
-**Assimilate the most popular use cases**. Instead of supporting the general notion of whiteboxity,
-we can introduce dedicated compiler support for the most popular uses cases including the `Generic`
-mechanism in Shapeless and quasiquote patterns in scala.reflect.
-
-This is an attempt at a compromise. On the one hand, this approach allows us to follow through with simplification.
-On the other hand, it significantly minimizes the impact on the existing users of whitebox macros.
-
-The downside of this solution is that it requires an extensive design process (because it involves adding new language features to Scala)
-and assumes that the internalized techniques have reached their final form. If a new version of Shapeless
-or a new version of scala.reflect (read: scala.meta) decide to adapt their designs after these designs have been assimilated,
-they will have a very hard time doing that.
-
-**Dedicated support for type-level computations**. Manifestations of whiteboxity are quite diverse,
-but a lot of them are reducible to type-level computations.
-
-For example, let's take a macro `join` that takes two objects and outputs an object that
-has fields of both. Since Scala doesn't have row polymorphism, it is impossible to write a type signature
-for this macro, so we have to declare it as whitebox.
-
-```
-scala> def join(x: Any, y: Any): Any = macro ...
-defined term macro join: (x: Any, y: Any)Any
-
-scala> join(new { val x = 2 }, new { val y = 3 })
-res0: AnyRef{val x: Int; val y: Int} = $anon$1@64af328d
-```
-
-Here we can see how the whitebox macro encapsulates a type-level computation that takes
-the types of both arguments (`AnyRef{ val x: Int }` and `AnyRef{ val y: Int }`)
-and merges them into the result type. Since this computation doesn't involve the abstract syntax trees
-of the arguments, the whitebox part of the macro can be extracted into a helper, making the macro itself
-blackbox.
-
-```
-scala> :paste
-// Entering paste mode (ctrl-D to finish)
-
-trait Join[T, U, V]
-object Join {
- implicit def materialize[T, U, V]: Join[T, U, V] = macro ...
-}
-
-// Exiting paste mode, now interpreting.
-
-defined trait Join
-defined object Join
-
-scala> def join[T, U, V](x: T, y: U)
- | (implicit ev: Join[T, U, V]): V = macro ...
-defined term macro join: [T, U, V](x: T, y: U)...
-```
-
-This approach can express some macros that refine their return type, all fundep materialization macros,
-and even some macros that dynamically compute availability of implicits (such macros can be modified to take
-an additional implicit parameter whose failure to materialize can be used to control availability of the enclosing implicit) -
-that is, all macros whose whiteboxity depends only on types of their prefix and arguments.
-
-Now, after eligible whitebox macros are rewritten this way, we can replace the whitebox materializers
-that compute types, e.g. `Join.materialize`, with a dedicated language feature that natively expresses them.
-The listing below provides a sketch of an imaginary syntax that assumes inline types and type-generating meta expressions.
-
-```
-inline type Join[T, U] = meta {
- import scala.meta._
- val jointVals = union(T, U)
- t"{ ..$jointVals }"
-}
-
-inline def join[T, U](x: T, y: U): Join[T, U] = meta { ... }
-```
-
-From the discussion above, we can see that whiteboxity is an important feature of the current macro system
-and is used in multiple highly popular open-source libraries. As a result, giving up whiteboxity
-may lead to undesired practical consequences.
-
-More work is needed to reconcile the design of the new macro system
-and existing use cases, and in this section we provided several approaches to addressing this need. In the opinion of the author,
-the approach that involves dedicated support to type-level computations is the most promising, because it both simplifies
-the macro system and provides support for the most important use cases of whiteboxity.
-
-### Losing compiler internals
-
-One of the main goals of this proposal is to stop exposing overcomplicated and brittle compiler internal APIs
-in order to make macros more accessible and more robust.
-
-However, some of the compiler APIs may actually capture useful idioms that we may be able to expose in a principled fashion.
-`c.internal.enclosingOwner` immediately comes to mind here.
-
-More work in collaboration with macro authors is needed to make sure that we don't unnecessarily break existing macros
-in the name of elusive conceptual purity.
-
-### Macro annotations
-
-Much like the current macro system can get extended to support macro annotations,
-the new macro system can get extended to support new-style macro annotations that provide similar functionality.
-
-```
-import scala.annotation.StaticAnnotation
-
-class h2db(url: String) extends StaticAnnotation {
- inline def apply(defns: Any): Any = meta {
- ...
- }
-}
-
-object Test {
- def main(args: Array[String]): Unit = {
- @h2db("coffees") object Db
- val brazilian = Db.Coffees.insert("Brazilian", 99.0)
- Db.Coffees.update(brazilian.copy(price = 100.0))
- println(Db.Coffees.all)
- }
-}
-```
-
-In the current macro system, a macro annotation is a subclass of `StaticAnnotation` that define
-a macro def called `macroTransform`.
-
-Analogously, in the new design, a macro annotation is a subclass of `StaticAnnotation`
-that defines an inline def called `apply`. We decided to change the magic name, because the old one no longer applies.
-We also simplified the signature to take a block wrapping the definitions being expanded and returns a block wrapping expansion results,
-i.e. `Any => Any`, as opposed to having `Any* => Any` in the current system.
-
-Expansion of new-style macro annotations is very similar to expansion of vanilla macro annotations.
-The only difference is that we only provide syntactic APIs, informed about [the limitations][AnnotationsTypecheck]
-brought by exposing semantic APIs in macros that generate top-level definitions.
-Concretely, meta scopes in macro annotations expose a `Dialect` capability instead of a `Mirror`.
-As a result, we can afford to expand on enter without any limitations to the shape of expansion.
-
-### Why inline
-
-The main motivation behind inline is to provide a templating system that can express simple use cases
-of compile-time metaprogramming in an lightweight declarative style that minimizes explicit introspection.
-
-For example, in one of the code snippets that illustrates inline defs and inline parameters, we can use the newly
-introduced mechanism to express partial evaluation. Thanks to constant folding facilities built into the compiler,
-usages of the `pow` method provided below will expand into a sequence of multiplications - all that without
-a single line of macro code.
-
-```
-inline def pow(b: Double, inline n: Int): Double = {
- if (n == 0) 1
- else b * pow(b, n - 1)
-}
-```
-
-### Out of scope
-
-This proposal addresses a lot of pain points of the current macro system, but it doesn't talk about two very common
-problems: lack of hygiene and presence of the separate compilation restriction.
-
-These two problems have a lot in common: we have experimented with both of them, our initial results are promising but insufficient,
-both of them can be developed independently of inline/meta.
-
-Given that both hygiene and joint compilation still require significant research to materialize,
-we decided not to include them in this proposal. We think that even without these features, inline/meta represents a significant
-improvement over the state of the art, so we leave them for future work that may be submitted in follow-up SIPs when it's done.
-
-## Conclusion
-
-Pioneered by def macros and macro annotations,
-the area of language-integrated compile-time metaprogramming in Scala has shown significant practical value.
-
-During the last several years, we have been utilizing and maintaining the current macro system in industrial projects.
-Learning from this experience, we have created a new design based on `inline` and `meta` that provides
-comparable functionality and avoids the most common pitfalls of existing macros.
-
-The user interface of the new system is a conservative evolution of def macros.
-[Inline defs][InlineDefs] work similarly to macro defs, and
-[meta expressions][MetaExprs] play the compile-time execution role of macro impls.
-These new language features are designed to be used together,
-and in this capacity their look and feel can hardly be distinguished from that of def macros.
-
-The metaprogrammer interface of the new system is a drastic redesign. We have merged macro defs and macro impls,
-and, more importantly, we have switched the underlying metaprogramming API from scala.reflect to [scala.meta][ScalaMetaSection].
-This has allowed us to make significant improvements in robustness and tool support.
-
-The main open question of the new design is [whether whiteboxity will stay or will be removed][Whiteboxity] from the new macro system.
-We also need to figure out [which internal compiler APIs we may want to approximate][CompilerInternals] in the new macro system.
-Future work outside the scope of this proposal includes
-hygiene and lifting the separate compilation restriction.
-
-At the time of writing, `inline` and `meta` are partially implemented in [a prototype compiler plugin for Scala 2.11][PrototypeScalac]
-and [an accompanying experimental branch of IntelliJ][PrototypeIntellij].
-We are excited with our initial results and are planning to develop the new design further.
-
-## Credits
-
-This design was created by Eugene Burmako, Denys Shabalin and Martin Odersky
-and was further elaborated together with other members of the inline working group at EPFL:
-Sébastien Doeraene, Vojin Jovanovic and Dmitry Petrashko.
-
-Over time, the ideas behind the design were refined based on experiments carried out by:
-Uladzimir Abramchuk, Igor Bogomolov, Mathieu Demarne, Martin Duhem, Adrien Ghosn, Zhivka Gucevska,
-Mikhail Mutcianko, Dmitry Naydanov, Artem Nikiforov, Vladimir Nikolaev, Jatin Puri and Valentin Rutz.
-
-The prototype of scalac integration was developed by Eugene Burmako with open-source contributions from
-Tamer Mohammed Abdul-Radi, David Dudson, Takeshi D. Itoh, Oleksandr Olgashko and Hiroshi Yamaguchi.
-
-The prototype of IntelliJ integration was developed by Mikhail Mutcianko.
-
-## References
-
- 1. [Prototype of scalac integration][PrototypeScalac]
- 1. [Prototype of IntelliJ integration][PrototypeIntellij]
- 1. [(Appendix A) Def macros: feature interaction][AppendixInteraction]
- 1. [(Appendix B) Def macros: macro expansion][AppendixExpansion]
- 1. [(Appendix C) Scala.meta: high-level overview][AppendixMeta]
-
-[ScalaMetaSection]: #scalameta
-[ScalaMetaWebsite]: https://scalameta.org/
-[MacroUsecases]: https://scalamacros.org/paperstalks/2014-02-04-WhatAreMacrosGoodFor.pdf
-[PrototypeScalac]: https://github.com/scalameta/paradise
-[PrototypeIntellij]: https://www.youtube.com/watch?v=IPnd_SZJ1nM&feature=youtu.be&t=1360
-[Intuition]: #intuition
-[LanguageFeatures]: #language-features
-[InlineDefs]: #inline-definitions
-[InlineExpansion]: #inline-reduction
-[MetaExprs]: #meta-expressions
-[MetaExpansion]: #meta-expansion
-[MetaApis]: #meta-apis
-[Whiteboxity]: #losing-whiteboxity
-[CompilerInternals]: #losing-compiler-internals
-[Hygiene]: #hygiene
-[SeparateCompilation]: #separate-compilation-restriction
-[Linq]: https://dl.acm.org/citation.cfm?id=1142552
-[Materialization]: https://docs.scala-lang.org/overviews/macros/implicits.html
-[SbtMacroSupport]: https://github.com/sbt/sbt/issues/1729
-[AnonymousTypeProviders]: https://docs.scala-lang.org/overviews/macros/typeproviders.html#anonymous-type-providers
-[ExtractorMacros]: https://docs.scala-lang.org/overviews/macros/extractors.html
-[AnnotationsTypecheck]: https://github.com/scalamacros/paradise/issues/75
-[AppendixInteraction]: https://gist.github.com/xeno-by/e26a904051a171e4bc8b9096630220a7
-[AppendixExpansion]: https://gist.github.com/xeno-by/5dde62aedcc23afc85ecf4d795ac67c2
-[AppendixMeta]: https://gist.github.com/xeno-by/9741ce7532cb30368b3753521bbfce4e
diff --git a/_sips/sips/2017-01-11-refer-other-arguments-in-args.md b/_sips/sips/2017-01-11-refer-other-arguments-in-args.md
deleted file mode 100644
index 6d5097038a..0000000000
--- a/_sips/sips/2017-01-11-refer-other-arguments-in-args.md
+++ /dev/null
@@ -1,107 +0,0 @@
----
-layout: sip
-title: SIP-32 - Allow referring to other arguments in default parameters
-vote-status: pending
-permalink: /sips/:title.html
-redirect_from: /sips/pending/refer-other-arguments-in-args.html
----
-
-**By: Pathikrit Bhowmick**
-
-## History
-
-| Date | Version |
-|---------------|------------------|
-| Jan 11th 2017 | Initial Draft |
-| Jan 12th 2017 | Initial Feedback |
-| Jan 16th 2017 | Minor Changes |
-
-## Introduction
-Currently there is no way to refer to other arguments in the default parameters list:
-
-Does not compile:
-```scala
-def substring(s: String, start: Int = 0, end: Int = s.length): String
-```
-
-The workaround to achieve this is by using a curried-function:
-```scala
-def substring(s: String, start: Int = 0)(end: Int = s.length): String
-```
-
-However, the above workaround is not always suitable in all situations since you may not want a curried function.
-
-The other more verbose alternative is by overloading:
-```scala
-def substring(s: String, start: Int): String
- = substring(s, start = 0, end = s.length)
-def substring(s: String, start: Int = 0, end: Int): String
-```
-
-The above is quite verbose as it required 1 extra function definition per argument that refers other args.
-
-### Proposal
-Allow to refer to ***any*** parameters in the same (or left) curried parameter list:
-```scala
-def substring(s: String, start: Int = 0, end: Int = s.length) // Legal
-def substring(start: Int = 0, end: Int = s.length, s: String) // Legal !!!
-def substring(s: String, start: Int = 0)(end: Int = s.length) // Legal (works currently)
-def substring(start: Int = 0, end: Int = s.length)(s: String) // Illegal
-```
-
-The same applies for class arguments:
-```scala
-class Substring(s: String, start: Int = 0, end: Int = s.length) // Legal
-class Substring(start: Int = 0, end: Int = s.length, s: String) // Legal
-class Substring(s: String, start: Int = 0)(end: Int = s.length) // Legal
-class Substring(start: Int = 0, end: Int = s.length)(s: String) // Illegal
-```
-
-We should also be able to refer to ***multiple*** parameters:
-```scala
-def binarySearch(start: Int, end: Int, middle: Int = (start + end)/2) // Legal
-```
-
-# Motivating examples:
-
-TBD
-
-## Interactions with other syntax
-
-#### Partially Applied Functions:
-Works as expected:
-```scala
-def substring(s: String, start: Int = 0, end: Int = s.length)
-
-substring(_, start = 0, end = 5) // Legal
-substring(_, end = 5) // Legal (start = 0)
-substring(_, start = 5) // Legal (same as s => substring(s, start = 5, end = s.length)
-```
-
-#### Multiple Implicit Parameters
-[Multiple implicit parameters](https://github.com/scala/docs.scala-lang/pull/520) should also be allowed to refer to one another (left to right):
-```scala
-def codec[A](data: A)(implicit encoder: Encoder[A])(implicit decoder: Decoder[A] = encoder.reverse) // Legal
-```
-
-#### Referring to type members:
-The default parameters should be able to refer to type members of other arguments e.g.:
-```scala
-trait Codec {
- type Input
- type Output
-}
-
-def codec(codec: Codec, in: codec.Input, out: codec.Output) // Legal !!!
-```
-
-### Other languages
-The following languages allow referring to previously declared arguments in the function signature:
-* [CoffeeScript](https://coffeescript.org/)
-* [Kotlin](https://kotlinlang.org)
-* [TypeScript](https://www.typescriptlang.org/)
-
-AFAIK, there are no major languages where referring to parameters declared to the ***right*** is allowed.
-
-### Discussions
-[Scala Lang Forum](https://contributors.scala-lang.org/t/refer-to-previous-argument-in-default-argument-list/215/6)
diff --git a/_sips/sips/2017-01-13-binary-compatibility.md b/_sips/sips/2017-01-13-binary-compatibility.md
deleted file mode 100644
index 96be472776..0000000000
--- a/_sips/sips/2017-01-13-binary-compatibility.md
+++ /dev/null
@@ -1,299 +0,0 @@
----
-layout: sip
-title: SIP-34 - Improving binary compatibility with @stableABI
-vote-status: dormant
-vote-text: When the author of this proposal figures out which features should be binary compatible and has more information on the future implementation, the SIP Committee will start the review period.
-permalink: /sips/:title.html
-redirect_from: /sips/pending/binary-compatibility.html
----
-
-__Dmitry Petrashko__
-
-__first submitted 13 January 2017__
-
-## Introduction
-
-Scala is a language which evolves fast and thus made a decision to only promise binary compatibility across minor releases\[[3]\].
-At the same time, there is a demand to develop APIs that live longer than a major release cycle of Scala.
-This SIP introduces an annotation `@stableABI` that checks that `what you write is what you get`.
-
-`@stableABI` is a linter, that does not change binary output, but will fail compilation if Public API of a class uses features
-of Scala that are desugared by compiler and may be binary incompatible across major releases.
-
-As long as declarations in source have not changed, `@stableABI` annotated classes will be compatible across major versions of Scala.
-It complements MiMa\[[2]\] in indicating if a class will remain binary compatible across major Scala releases.
-
-## Term definitions
-
-* ##### Binary descriptors
-
-As defined by the JVM spec\[[4]\]:
-
- > A descriptor is a string representing the type of a field or method. Descriptors are represented in the class file format using modified UTF-8 strings (§4.4.7)
- > and thus may be drawn, where not further constrained, from the entire Unicode codespace.
- >
- > A method descriptor contains zero or more parameter descriptors, representing the types of parameters that the method takes, and a return descriptor, representing the type of the value (if any) that the method returns.
-
- Binary descriptors are used in the bytecode to indicate what fields and methods are accessed or invoked.
- If a method or field has its descriptor changed, previously compiled classes that used different descriptor will fail in
- runtime as they no longer link to the changed field.
-
- In this document we use the term `binary descriptor` to refer to both method and field descriptors used by the JVM.
-
-* ##### Public API
-
- Methods and fields marked with `ACC_PUBLIC`\[[5]\] may be accessed from any class and package.
- This loosely corresponds to absence of AccessModifier\[[6]\] in Scala source.
- Changing a binary descriptor of a method or a field marked with `ACC_PUBLIC` is a binary incompatible change
- which may affect all classes in all packages leading to a runtime linkage failure.
-
- Methods and fields marked with `ACC_PROTECTED`\[[5]\] may be accessed within subclasses.
- This loosely corresponds to presence of `protected` AccessModifier\[[6]\] in Scala source.
- Changing a binary descriptor of a method or a field marked with `ACC_PROTECTED` is a binary incompatible change
- which may affect all subclasses of this class leading to a runtime linkage failure.
-
- In this document we use the term `Public API` to refer both to methods and fields defined as `ACC_PUBLIC` and `ACC_PROTECTED`.
- Changes do binary descriptors of Public API may lead to runtime linkage failures.
-
-* ##### Binary compatibility
-
- Two versions of the same class are called binary compatible if there are no changes to the Public API of this class,
- meaning that those two classes can be substituted in runtime without linkage errors.
-
-## Use cases
-
-1. Publishing a library that would work across major Scala versions, such as 2.12 & 2.13 and Dotty.
-2. Defining a class which is supposed to be used from other JVM languages such as Java\Kotlin.
-`@stableABI` will ensure both binary compatibility and that there are no unexpected methods
- that would show up in members of a class or an interface.
-3. Library authors can take advantage of language features introduced in new major versions of Scala
- while still serving users on older language versions by defining their Public API as `@stableABI`.
-
-The important use-case envisioned here by the authors is migration to Dotty.
-We envision that there might be code-bases that for some reason don't compile either with Dotty or with Scalac.
-This can be either because they rely on union types, only present in Dotty,
-or because they need early initializers, which are only supported by Scalac.
-
-At the same time, by marking either those classes themselves or their parents as `@stableABI`,
-the compiled artifacts could be used in both Dotty-compiled and Scalac-compiled projects.
-
-
-## Current Status
-In case there's a need to develop an API that will be used by clients compiled using different major versions of Scala,
-the current approach is to either develop them in Java or to use best guess to restrict what Scala features should be used.
-
-There's also a different approach which is used by sbt: instead of publishing a binary `compiler-interface`, sources are published instead that would be locally compiled.
-
-Examples:
-
- 1. Zinc\[[8]\] is writing their interfaces in Java because the interface has to be Scala version agnostic, as it is shipped in every sbt release, independently of Scala version that was used to compile zinc or will be used in to compile the project.
-sbt additionally compiles on demand the compiler bridge, which implements this Java interface.
-
- 2. Dotty\[[7]\] currently uses java defined interfaces as public API for IntelliJ in order to ensure binary compatibility.
-These interfaces can be replaced by `@stableABI` annotated traits to reach the same goal.
-
-## Design Guidelines
-`@stableABI` is a feature which is supposed to be used by a small subset of the ecosystem to be binary compatible across major versions of Scala.
-Thus this is designed as an advanced feature that is used rarely and thus is intentionally verbose.
-It's designed to provide strong guarantees, in some cases sacrificing ease of use and to be used in combination with MiMa\[[2]\]
-
-The limitations enforced by `@stableABI` are designed to be an overapproximation:
-instead of permitting a list of features known to be compatible, `@stableABI` enforces a stronger
-check which is sufficient to promise binary compatibility.
-
-This SIP intentionally follows a very conservative approach.
-This is because we will be able to allow more features later, but we won't have an opportunity to remove them.
-
-## Overview ##
-In order for a class, trait or an object to succeed compilation with the `@stableABI` annotation it has to be:
-
- - defined on the top level;
- - if a class or an object has a companion annotated with `@stableABI`, than annotation applies to both of them;
- - use a subset of Scala that during compilation does not require changes to public API of the class, including
- - synthesizing new members, either concrete or abstract;
- - changing binary descriptors of existing members, either concrete or abstract;
-
-`@stableABI` does not change the compilation scheme of a class:
- compiling a class previously annotated with the `@stableABI`, will produce the same bytecode with or without `@stableABI` annotation.
-
-Below are several examples of classes and traits that succeed compilation with `@stableABI`
-
-{% highlight scala %}
-@stableABI
-trait AbstractFile {
- def name(): String
-
- def path(): String
-
- def jfile(): Optional[File]
-}
-
-@stableABI
-trait SourceFile extends AbstractFile {
- def content(): Array[Char]
-}
-
-@stableABI
-trait Diagnostic {
- def message(): String
-
- def level(): Int
-
- def position(): Optional[SourcePosition]
-}
-
-@stableABI
-object Diagnostic {
- @static final val ERROR: Int = 2
- @static final val WARNING: Int = 1
- @static final val INFO: Int = 0
-}
-
-@stableABI
-class FeaturesInBodies {
- def apiMethod: Int = {
- // as body of the method isn't part of the public interface, one can use all features of Scala here.
- lazy val result = 0 // while lazy vals are prohibited in the class, they are allowed in the bodies of methods
- result
- }
-}
-{% endhighlight %}
-
-## Features that will fail compilation with `@stableABI`
-The features listed below have complex encodings that may change in future versions. We prefer not to compromise on them.
-Most of those features can be simulated in a binary compatible way by writing a verbose re-implementation
-which won't rely on desugaring performed inside compiler.
-Note that while those features are prohibited in the public API, they can be safely used inside bodies of the methods.
-
- - public fields. Can be simulated by explicitly defining public getters and setters that access a private field;
- - lazy vals. Can be simulated by explicitly writing an implementation in source;
- - case classes. Can be simulated by explicitly defining getters and other members synthesized for a case class(`copy`, `productArity`, `apply`, `unapply`, etc).
-
-The features listed below cannot be easily re-implemented in a class or trait annotated with `@stableABI`.
-
- - default arguments;
- - default methods. See Addendum;
- - constant types(both explicit and inferred);
- - inline.
-
-## Binary compatibility and transitivity ##
-Consider a class, that is binary compatible but takes a non-binary compatible argument:
-
-{% highlight scala %}
-@stableABI
-class Example {
- def foo[T](a: MyOption[T]): T = a.get
-}
-
-trait MyOption[T]{
- lazy val get: T = ???
-}
-{% endhighlight %}
-
-
-Consider a situation when we re-compile `MyOption` using a different major compiler version than the one used to compile `Example`.
-Let's assume the new major version of compile has changing binary descriptor of method `get`.
-
-While the code in runtime would still successfully invoke the method `Example.foo`, this method will fail in execution,
-as it will itself call a `MyOption.get` using an outdated descriptor.
-
-While in perfect world it would be nice to require all `@stableABI` classes and traits to only take `@stableABI` arguments
-and only return `@stableABI` values, we believe that all-or-nothing system will be a lot harder to adopt and migrate to.
-
-Because of this we propose to emmit warnings in those cases:
-
- - non-`@stableABI` value is returned from a method or field defined inside a `@stableABI` class or trait;
- - an invocation to a method not-defined inside a `@stableABI` class is used in
- implementation of a method or a field initializer inside a `@stableABI` class or trait.
-
-Those warnings can be suppressed using an `@unchecked` annotations or made fatal using `+Xfatal-warnings`.
-
-## The case of the standard library ##
-The Standard library defines types commonly used as arguments or return types such as `Option` and `List`,
-as well as methods and implicit conversions imported from `scala` and `Predef`.
-
-As such Standard library is expected to be the biggest source of warnings defined in previous section.
-
-We propose to consider either making some classes in standard library use `@stableABI` or define new `@stableABI`
-super-interfaces for them that should be used in `@stableABI` classes.
-This would also allow to consume Scala classes from other JVM languages such as Kotlin and Java.
-## `@stableABI` and Scala.js
-
-Allowing to write API-defining classes in Scala instead of Java will allow them to compile with Scala.js,
-which would have benefit of sharing the same source for two ecosystems.
-
-Scala.js currently is binary compatible as long as original bytecode compiled by Scala JVM is binary compatible.
-Providing stronger binary compatibility guarantees for JVM will automatically provide stronger guarantees for Scala.js.
-
-
-## Comparison with MiMa ##
-The Migration Manager for Scala (MiMa in short) is a tool for diagnosing binary incompatibilities for Scala libraries.
-MiMa allows to compare binary APIs of two already compiled classfiles and reports errors if APIs do not match perfectly.
-
-MiMa and `@stableABI` complement each other, as `@stableABI` helps to develop APIs that stay compatible
-across major versions, while MiMa checks that previously published artifacts indeed have the same API.
-
-`@stableABI` does not compare the currently compiled class or trait against previous version,
-so introduction of new members won't be prohibited. This is a use-case for MiMa.
-
-MiMa does not indicate how hard, if possible, would it be to maintain compatibility of a class across future versions of Scala.
-Multiple features of Scala, most notably lazy vals and traits, have been compiled differently by different Scala versions
-making porting existing compiled bytecode across versions very hard.
-MiMa will complain retroactively that the new version is incompatible with the old one.
-`@stableABI` will instead indicate at compile time that the old version used features whose encoding is prone to change.
-This provides early guidance and warning when designing long-living APIs before they are publicly released.
-
-## Compilation scheme ##
-No modification of typer or any existing phase is planned. The current proposed scheme introduces a late phase that runs before the very bytecode emission that checks that:
-
- - classes, traits and objects annotated as `@stableABI` are on the top level;
- - compiler did not introduce new Public API methods or fields inside `@stableABI` classes, traits and objects;
- - compiler did not change descriptors of existing Public API methods or fields inside `@stableABI` classes, traits and objects.
-
-This phase additionally warns if Public API method or field takes an argument or returns a value that isn't marked as `@stableABI`.
-This warning can be suppressed by annotating with `@unchecked`.
-
-The current prototype is implemented for Dotty and supports everything described in this SIP, except warnings.
-The implementation is simple with less than 50 lines of non-boilerplate code.
-The current implementation has a scope for improvement of error messages that will report domain specific details for disallowed features,
-but it already prohibits them.
-
-## Addendum: Default methods ##
-By `default methods` we mean non-abstract methods defined and implemented by a trait.
-
-The way how those methods are implemented by compiler has changed substantially over years.
-At the same time, `invokeinterface` has always been a reliable way to invoke such a method,
-independently from how it was implemented under the hood.
-
-One might reason that, as there has been a reliable way to call methods on the binary level,
-it should be allowed to use them in binary compatible APIs.
-
-At the same time, the mixin composition protocol that is followed when a class inherits those traits has also
-changed substantially.
-The classes which have been correctly inheriting those traits compiled by previous versions of Scala
-may need recompilation if trait has been recompiled with a new major version of Scala.
-
-Thus, the authors of this SIP has decided not to allow default methods in the
-`@stableABI` traits.
-
-## See Also ##
-
- 1. [dotty#1900][1]
- 2. [MiMa][2]
- 3. [releases-compatibility][3]
- 4. [Descriptor definition in JVM Specification][4]
- 5. [JVM access flags][5]
- 6. [Scala AccessModifiers][6]
- 7. [Dotty interfaces][7]
- 8. [Zinc interfaces][8]
-
-
-[1]: https://github.com/lampepfl/dotty/pull/1900 "an implementation for Dotty"
-[2]: https://github.com/typesafehub/migration-manager "MiMa"
-[3]: https://docs.scala-lang.org/overviews/core/binary-compatibility-of-scala-releases.html "Binary compatibility of Scala releases"
-[4]: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3 "Descriptor definition in JVM Specification"
-[5]: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6-200-A.1 "JVM access flags"
-[6]: https://www.scala-lang.org/files/archive/spec/2.11/05-classes-and-objects.html#modifiers "Scala AccessModifiers"
-[7]: https://github.com/lampepfl/dotty/tree/master/interfaces/src/dotty/tools/dotc/interfaces "Dotty interfaces"
-[8]: https://github.com/sbt/zinc/tree/v1.0.0/internal/compiler-interface/src/main/java/xsbti "zinc interfaces"
-
diff --git a/_sips/sips/2017-02-22-comonadic-comprehensions.md b/_sips/sips/2017-02-22-comonadic-comprehensions.md
deleted file mode 100644
index 92db697c41..0000000000
--- a/_sips/sips/2017-02-22-comonadic-comprehensions.md
+++ /dev/null
@@ -1,223 +0,0 @@
----
-layout: sip
-title: SIP-NN - comonadic-comprehensions
-vote-status: rejected
-permalink: /sips/:title.html
-redirect_from: /sips/pending/comonadic-comprehensions.html
----
-
-**By: Shimi Bandiel**
-
-## History
-
-| Date | Version |
-|---------------|---------------|
-| Feb 22nd 2017 | Initial Draft |
-
-## Motivation
-
-Scala provides a concise syntax for working with Monads(map & flatMap):
-the for comprehension.
-
-Following is a proposal for a concise syntax for working with Comonads(map, extract & coflatMap):
-the cofor comprehension.
-
-The proposal has an existing implementation in PR 5725
-
-## Motivating Examples
-
-### Examples
-
-Consider the following class:
-
-{% highlight scala %}
-
-case class StreamZipper[A](left: Stream[A], focus: A, right: Stream[A]) {
- def map[B](f: A => B): StreamZipper[B] =
- StreamZipper(left.map(f), f(focus), right.map(f))
- def extract: A =
- focus
- def coflatMap(f: StreamZipper[A] => B): StreamZipper[B] =
- ???
-}
-
-{% endhighlight %}
-
-StreamZipper[A] represents a non-empty Stream of As with a cursor (focus).
-
-
-
The map method invokes f on every element and produces a StreamZipper of
-the results.
-
The extract method returns the value at the cursor
-
The coflatMap method invokes f on every cursor (all possible zippers) providing a contextual global operation.
-The result is a StreamZipper[B] of the results with a cursor pointing at the same location as this.
-
-
-
-The above implementation for `coflatMap` was left out for brevity. See [3].
-
-Now, consider the following methods:
-{% highlight scala %}
-
- // returns whether the current cursor in a zipper of ints is between the previous
- // and the next numbers.
- def isInTheMiddle(z : StreamZipper[Int]): Boolean =
- z match {
- case StreamZipper(pi +: _, i, ni +: _) if (pi < i && i < ni) => true
- case _ => false
- }
-
- // counts how many consecutive values of true starting from the cursor
- def numberOfTrues(z: StreamZipper[Boolean]) : Int =
- if (z.focus) 1 + z.right.takeWhile(true ==).size else 0
-
-{% endhighlight %}
-
-And, let's say we have a StreamZipper[Person]:
-{% highlight scala %}
- case class Person(name: String, age: Int)
-
- // a given stream with cursor at some position
- val people: StreamZipper[Person] = ???
-{% endhighlight %}
-
-We would like to get the following:
-{% highlight scala %}
-
- /*
- * A StreamZipper of triplets containing:
- * _1 -- the original Person value.
- * _2 -- whether this Person's age is higher than the previous and lower than the next.
- * We'll call this boolean TAG.
- * _3 -- how many consecutive TAGs with value "true" starting from current cursor.
- */
- val goal: StreamZipper[(Person, Boolean, Int)] = ???
-
-{% endhighlight %}
-
-It seems we can re-use the isInTheMiddle and numberOfTrues methods.
-However, without the proposed cofor syntax we'll probably end with:
-{% highlight scala %}
- val goal = people.map(p => (p, p.age)).coflatMap { zipperOfTuple =>
- val ages = zipperOfTuple.map(_._2)
- (zipperOfTuple.extract._1, isInTheMiddle(ages))
- }.coflatMap { zipperOfTuple =>
- val tags = zipperOfTuple.map(_._2)
- val persons = zipperOfTuple.map(_._1)
- val trues = numberOfTrues(tags)
- persons.extract, tags.extract, trues)
- }
-{% endhighlight %}
-From the code above, you can see that it is quite cumbersome to handle the passing of
-the context between the invocations of coflatMap.
-
-The proposed syntax allows for the following usage:
-{% highlight scala %}
- val flow : StreamZipper[Person] => (Person, Boolean, Int) =
- cofor (p @ Person(_, age)) {
- tag <- isInTheMiddle(age)
- count <- numberOfTrues(tag)
- } yield (p.extract, tag.extract, count.extract)
-
- val goal = people.coflatMap(flow)
-{% endhighlight %}
-
-
-## Syntax
-
-The proposed syntax is based on the paper by Dominic Orchard and Alan Mycroft [1].
-
-The syntax for `cofor` is defined as:
-{% highlight scala %}
- cofor (pattern0) {
- pattern1 <- generator1
- pattern2 <- generator2
- ...
- } yield body
-
- patternN = regular case patterns
- generatorN = expr
- body = expr
-
-{% endhighlight %}
-
-The result type of a `cofor` expression is a function from the comonad type to
-a result (`T[A] => B`).
-This means that the return type must be available at call-site!
-Note that unlike `for`, guards and assignments are not supported.
-
-## Desugaring
-
-A `cofor` desugaring is much more complex than the respective `for`.
-
-Desugaring example:
-
-{% highlight scala %}
- val flow : StreamZipper[Person] => (Person, Boolean, Int) =
- cofor (p @ Person(_, age)) {
- tag <- isInTheMiddle(age)
- count <- numberOfTrues(tag)
- } yield (p.extract, tag.extract, count.extract)
-
- val goal = people.coflatMap(flow)
-{% endhighlight %}
-
-The above `cofor` expression will be desugared into the following function:
-{% highlight scala %}
- input => {
- // desugaring the generators
- val enums =
- // assign values to input variables
- // actual assignment is done through pattern matching
- input.map(p => (
- p match {
- case p @ Person(_, age) => p
- }
- , (p match {
- case p @ Person(_, age) => age
- }, ()))).
- coflatMap(env => {
- // extracting collected values from the context
- val p = env.map(env => env._1)
- val age = env.map(env => env._2._1)
- // now we pass the current context and the generator result
- (isInTheMiddle(age), env.extract)
- }).coflatMap(env => {
- // extracting collected values from the context
- val tag = env.map(env => env._1)
- val p = env.map(env => env._2._1)
- val age = env.map(env => env._2._2._1)
- // now we pass the current context and the generator result
- (numberOfTrues(tag), env.extract)
- })
- // the body phase (yield)
- {
- // deconstructing the collected context
- val count = enums.map(env => env._1)
- val tag = enums.map(env => env._2._1)
- val p = enums.map(env => env._2._2._1)
- val age = enums.map(env => env._2._2._2._1)
- (p.extract, tag.extract, count.extract)
- }
- }
-{% endhighlight %}
-
-## Drawbacks
-
-
-
Adding a new keyword to the language makes it more complex
-
Understanding the desugaring and concept behind cofor is not
-trivial and it's much more complex than for (which many developers still
-don't feel at ease with).
-
-
-
-## References
-
-1. [A Notation for Comonads][1]
-2. [Implementation Pull-Request][2]
-3. [StreamZipper Example][3]
-
-[1]: https://www.cl.cam.ac.uk/~dao29/publ/codo-notation-orchard-ifl12.pdf "codo-notation"
-[2]: https://github.com/scala/scala/pull/5725
-[3]: https://github.com/shimib/scala/blob/5e257cd4b371769deafba2be1ae3932d772ca67d/test/files/neg/cofor.scala
diff --git a/_sips/sips/2017-10-25-adding-prefix-types.md b/_sips/sips/2017-10-25-adding-prefix-types.md
deleted file mode 100644
index 9ef94f2427..0000000000
--- a/_sips/sips/2017-10-25-adding-prefix-types.md
+++ /dev/null
@@ -1,194 +0,0 @@
----
-layout: sip
-title: SIP-36 - Adding prefix types
-vote-status: pending
-permalink: /sips/:title.html
-redirect_from: /sips/pending/adding-prefix-types.html
----
-
-**By: Oron Port**
-
-## History
-
-| Date | Version |
-| ------------- | ---------------------------------------- |
-| Oct 25th 2017 | Split prefix types from [SIP33](https://docs.scala-lang.org/sips/priority-based-infix-type-precedence.html), and emphasize motivation |
-| Nov 29th 2017 | Updated SIP according to feedback in the PR, and recent update to SIP23 |
-| Dec 1st 2017 | Added another use-case for prefix type `~` |
-
-Your feedback is welcome! If you're interested in discussing this proposal, head over to [this](https://contributors.scala-lang.org/t/sip-nn-make-infix-type-alias-precedence-like-expression-operator-precedence/471) Scala Contributors thread and let me know what you think.
-
----
-
-## Introduction
-Currently scala supports unary prefix operators (`-`, `+`, `~`, `!`) for expressions (e.g., `def unary_-`) and does not support prefix types. See the Scala specification [Prefix Operations](https://scala-lang.org/files/archive/spec/2.12/06-expressions.html#prefix-operations) section.
-
-**Prefix expression vs. prefix type example**:
-
-```scala
-object PrefixExpression {
- case class Nummy(expand : String) {
- def unary_- : Nummy = Nummy(s"-$this")
- def unary_~ : Nummy = Nummy(s"~$this")
- def unary_! : Nummy = Nummy(s"!$this")
- def unary_+ : Nummy = Nummy(s"+$this")
- }
- object N extends Nummy("N")
- val n1 = -N
- val n2 = ~N
- val n3 = !N
- val n4 = +N
-}
-object NonExistingPrefixTypes {
- trait unary_-[A]
- trait unary_~[A]
- trait unary_![A]
- trait unary_+[A]
- trait N
- type N1 = -N //Not working
- type N2 = ~N //Not working
- type N3 = !N //Not working
- type N4 = +N //Not working
-}
-```
-
----
-
-## Motivation
-It is easier to reason about the language when mathematical and logical operations for both terms and types are expressed the same. The proposal is relevant solely for projects which utilize numeric literal type operations (supported by SIP23, which was not yet accepted into Lightbend Scala). However, the SIP's implementation is very small and should have minor effect on compiler performance.
-
-### Motivating examples
-
-#### Splice prefix types for meta-programming
-A requirement for `unary_~` is described by Martin Odersky at [this proposal](https://gist.github.com/odersky/f91362f6d9c58cc1db53f3f443311140).
-
-#### Singleton-ops library example
-
-The [singleton-ops library](https://github.com/fthomas/singleton-ops) with [Typelevel Scala](https://github.com/typelevel/scala) (which implemented [SIP-23](https://docs.scala-lang.org/sips/pending/42.type.html)) enable developers to express literal type operations more intuitively.
-
-Consider the following example, where `foo` has two equivalent implementations, one using types, while the other uses terms:
-
-```scala
-import singleton.ops._
-
-object PrefixExample {
- /*
- We would much rather write the following to acheive more clarity and shorter code:
- type Foo[Cond1, Cond2, Num] = ITE[Cond1 && !Cond2, -Num, Num]
- */
- type Foo[Cond1, Cond2, Num] = ITE[Cond1 && ![Cond2], Negate[Num], Num]
- //foo executes typelevel operations by using singleton-ops
- def foo[Cond1, Cond2, Num](implicit f : Foo[Cond1, Cond2, Num]) : f.Out = f.value
- //foo executes term operations
- def foo(cond1 : Boolean, cond2 : Boolean, num : Int) : Int =
- if (cond1 && !cond2) -num else num
-}
-
-import PrefixExample._
-
-foo[true, false, 3] //returns -3
-foo(true, false, 3) //returns -3
-```
-
-Note: `type ![A]` is possible to define, but `type -[A]` is not due to collision with infix type parsing.
-
-#### DFiant library example
-
-DFiant is a domain specific language for hardware description I (Oron) am developing. Hardware interfaces have a direction annotation (e.g., `vec : DFBits[8] <> IN`). Sometime interfaces have multiple ports, in different directions. E.g.:
-
-```scala
-trait MyInterface {
- val data : DFBits[32] <> IN
- val address : DFBits[32] <> OUT
-}
-```
-
-To be able to use the same interface in reverse, we need the ability to easily express it as:
-
-```scala
-trait MyReversableInterface[D <: Direction] {
- val data : DFBits[32] <> D
- val address : DFBits[32] <> ~D
-}
-```
-
-An implicit conversion can then assure that `~IN` is translated to `OUT` and vice-versa.
-
-Interfaces may possess dozens of ports, thus without prefix types can be quite cumbersome.
-
----
-
-## Proposal
-
-Add support for prefix types, which is equivalent to the prefix operations for expressions.
-
-```
-PrefixType ::= [`-' | `+' | `~' | `!'] SimpleType
-CompoundType ::= PrefixType
- | AnnotType {with AnnotType} [Refinement]
- | Refinement
-```
-
-------
-
-## Implementation
-
-A PR for this SIP is available at: [https://github.com/scala/scala/pull/6148](https://github.com/scala/scala/pull/6148)
-
-------
-
-### Interactions with other language features
-
-#### Variance Annotation
-Variance annotation uses the `-` and `+` symbols to annotate contravariant and covariant subtyping, respectively. Introducing unary prefix types may lead to some developer confusion. However, such interaction is very unlikely to occur. E.g.:
-
-```scala
-trait Negate[A]
-trait Positive[A]
-type unary_-[A] = Negate[A]
-type unary_+[A] = Positive[A]
-trait Contravariant[B, -A <: +B] //contravariant A subtype upper-bounded by Positive[B]
-trait Covariant[B, +A <: -B] //covariant A subtype upper-bounded by Negative[B]
-```
-
-#### Negative Literal Types
-Negative literal types are annotated using the `-` symbol. This can lead to the following confusion:
-
-```scala
-trait Negate[A]
-type unary_-[A] = Negate[A]
-trait MyTrait[B]
-
-type MinusFortyTwo = MyTrait[-42]
-type NegateFortyTwo = MyTrait[Negate[42]]
-```
-
-The above example demonstrates a case of two types `MinusFortyTwo` and `NegateFortyTwo` which are different. They may be equivalent in view (implicit conversion between the two type instances), but they are not equal.
-
-Note: It is not possible to annotate a positive literal type in Scala (checked both in TLS and Dotty):
-
-```scala
-val a : 42 = +42 //works
-val b : -42 = -42 //works
-val c : +42 = 42 //error: ';' expected but integer literal found
-```
-
-This means that if unary prefix types are added, then `+42` will be a type expansion of `unary_+[42]`.
-
-**Related Issues**
-* [Dotty Issue #2783](https://github.com/lampepfl/dotty/issues/2783)
-* [Typelevel Scala Issue #157](https://github.com/typelevel/scala/issues/157) (Resolved in recent update to SIP23)
-
-Dotty's implementation of literal types currently fail compilation when infix types interact with a negative literal type.
-```scala
-type ~~[A, B]
-type good = 2 ~~ 2
-type bad = 2 ~~ -2 //Error:(9, 20) ';' expected but integer literal found.
-type work_around = 2 ~~ (-2) //Error in Dotty
-```
-----
-
-### Bibliography
-[Scala Contributors](https://contributors.scala-lang.org/t/sip-nn-make-infix-type-alias-precedence-like-expression-operator-precedence/471)
-
-[scala-sips](https://groups.google.com/forum/#!topic/scala-sips/ARVf1RLDw9U)
diff --git a/_sips/sips/2018-05-26-case-if.md b/_sips/sips/2018-05-26-case-if.md
deleted file mode 100644
index 7e4952f262..0000000000
--- a/_sips/sips/2018-05-26-case-if.md
+++ /dev/null
@@ -1,115 +0,0 @@
----
-layout: sip
-title: SIP-NN - Uncluttering Abuse of Match
-vote-status: pending
-permalink: /sips/:title.html
-redirect_from: /sips/pending/case-if.html
----
-
-**By: Som Snytt and A. P. Marki**
-
-## History
-
-| Date | Version |
-|---------------|----------------|
-| May 26th 2018 | Initial Draft |
-| May 28th 2018 | Underscoreless |
-
-## Motivation
-
-Since the demise of SIP-12, we have relied on Marie Kondo to declutter
-what remains of our lives. But we can do better.
-
-Currently, `case` syntax requires an underscore to represent a pattern,
-even if the code of interest is the guard that follows.
-
-Anxiety over this underscore is expressed in [a StackOverflow question][1]
-in which a programmer mulls the question of "Abuse of Match" and whether
-it actually makes you go blind.
-
-We propose to go underscoreless, pace the famous consultancy.
-
-If we can't have SIP-12 then we can have tidy syntax for `if-then` in `case` blocks.
-
-Since `Scala <3` abhors two ways of doing a thing, we eliminate underscore
-as a pattern. Underscore as a subpattern, that is, as a `pattern2`, is patterned
-after placeholder syntax in expressions, just as constructor patterns are patterned
-after constructor invocations. We read `C(_)` and `case C(_) =>` to mean construction
-of `C` with an argument unspecified. Similarly, just as placeholder syntax is
-restricted, so that an underscore is never an `Expr`, pattern syntax must disallow
-underscore as a `Pattern` production.
-
-In fact, underscore never quite functioned that way, since the definition
-
- val _ = 42
-
-has always incorrectly introduced a variable named `_`.
-
-Suggestions have surfaced that this syntax should mean something entirely different,
-namely, the introduction of a freshly named variable which cannot be named in
-source code, but induces the evaluation of the RHS of the definition, and which
-can be accessed implicitly if defined as an implicit value.
-
-However that may be, underscore must first be disallowed as a `Pattern`.
-
-The only way to coherently define a `case` for which no pattern is applied is to omit
-the pattern. And in the absence of alternative semantics, `val _` is not meaningful.
-Underscore on the RHS of `var` definitions has already been deprecated, and it is
-expected that that syntax will also be removed.
-
-## Syntax
-
-In lieu of
-
- 42 match {
- case _ if now isAfter midnight => nothingGoodHappens()
- case _ => ()
- }
-
-we write
-
- 42 match {
- case if now isAfter midnight => nothingGoodHappens()
- case => ()
- }
-
-The syntax accepts either a pattern with optional guard, or a guard with no pattern:
-
- CaseClause ::= ‘case’ (Pattern [Guard] | Guard) ‘=>’ Block
- Guard ::= ‘if’ PostfixExpr
-
-## Further Justifications
-
-In a respected online [forum][2] which brooks no fools, [Mulliganaceous][3] has posted
-an "accepted" answer using the idiom, "in case if". This supports `case if` as
-a natural locution.
-
-In a response to one judgment about abuse of match, [one Scala user][4] whose handle I can
-never spell quite right let alone pronounce finds the match version
-"clearer and visually more pleasant" than the cluttered `if` expression.
-
-From the beginning, Scala has made great strides in reducing vertical space in source code.
-However, we are still constrained horizontally, despite curved OLED screens.
-Recently, [a suggested edit][5] was declined because of maximum line length restrictions.
-Every wasted character brings us closer to an unfortunate line break.
-
-## Implementation
-
-An implementation is [available][6]. It's pretty slick.
-
-## References
-
-1. [Abuse of Match?][1]
-2. [Reputation requirements for creating tags and tag synonyms][2]
-3. [Mulliganaceous user profile][3]
-4. [huynhjl user profile][4]
-5. [Sample line length limitation in a Scala project][5]
-6. [Implementation][6]
-
-[1]: https://stackoverflow.com/questions/12556236/abuse-of-match "Abuse of Match?"
-[2]: https://meta.stackoverflow.com/a/368537/1296806 "Reputation requirements for creating tags and tag synonyms"
-[3]: https://meta.stackoverflow.com/users/8242447/mulliganaceous "Mulliganaceous"
-[4]: https://stackoverflow.com/users/257449/huynhjl "huynhjl"
-[5]: https://github.com/apache/spark/pull/21369/files#r189794046 "scala-style enforces a max of 100 chars per line"
-[6]: https://github.com/scala/scala/pull/6241 "Implementation PR 6241"
-
diff --git a/_sips/sips/2019-08-11-curried-varargs.md b/_sips/sips/2019-08-11-curried-varargs.md
deleted file mode 100644
index 8fbe8f094d..0000000000
--- a/_sips/sips/2019-08-11-curried-varargs.md
+++ /dev/null
@@ -1,271 +0,0 @@
----
-layout: sip
-title: SIP-NN - Curried varargs
-vote-status: pending
-permalink: /sips/:title.html
-redirect_from: /sips/pending/curried-varargs.html
----
-
-**By: Yang, Bo**
-
-## History
-
-| Date | Version |
-|---------------|---------------|
-| Aug 11th 2019 | Initial Draft |
-| Aug 12th 2019 | Translating sequence arguments to `applyNextSeq` calls |
-
-## Introduction
-
-The [repeated parameters](https://scala-lang.org/files/archive/spec/2.13/04-basic-declarations-and-definitions.html#repeated-parameters) syntax is widely used in Scala libraries to create collection initializers, string interpolations, and DSLs. Unfortunately, repeated parameters are type unsafe as it erase all arguments to their common supertype, inefficient as it creates a temporary `Seq` that is difficult to be eliminated by optimizer. In practice, all sophisticated string interpolation libraries, including [string formatting](https://github.com/scala/scala/blob/43e040ff7e4ba92ccf223e77540580b32c1473c0/src/library/scala/StringContext.scala#L94) and [quasiquotes](https://github.com/scala/scala/blob/43e040ff7e4ba92ccf223e77540580b32c1473c0/src/reflect/scala/reflect/api/Quasiquotes.scala#L28) in standard library, [scalameta](https://scalameta.org/docs/trees/quasiquotes.html) and my [fastring](https://github.com/Atry/fastring/blob/67ae4eccdb9b7f58416ed90eae85ddb035b1ffb1/shared/src/main/scala/com/dongxiguo/fastring/Fastring.scala#L242) library, are written in macros in order to avoid runtime overhead of repeated parameters.
-
-We propose **curried varargs** to improve both the type safety and the performance. Given a function call `f(a, b, c)`, when `f` is a subtype of `Curried`, the function call should be rewritten to `f.applyBegin.applyNext(a).applyNext(b).applyNext(c).applyEnd`.
-
-## Motivating Examples
-
-### Examples
-
-Recently I was working on the implementation of [Pre SIP: name based XML literals](https://contributors.scala-lang.org/t/pre-sip-name-based-xml-literals/2175). During implementing that proposal, I found that the proposal is inefficiency due to repeated parameters, and it could be improved dramatically with the help of curried functions.
-
-For example, according to the proposal the XML literal `
line1 line2
` will result the following code:
-
-``` scala
-xml.tags.div(
- xml.attributes.title(xml.text("my-title")),
- xml.text("line1"),
- xml.tags.br(),
- xml.text("line2")
-)
-```
-
-With the help of this curried varargs proposal and `@inline`, we are able to implement an API to build a DOM tree with no additional overhead over manually written Scala code.
-
-``` scala
-import org.scalajs.dom.document
-import org.scalajs.dom.raw._
-
-object xml {
- type Attribute[-A <: Element] = A => Unit
- @inline def text(data: String) = data
- object attributes {
- @inline def title(value: String): Attribute[Element] = _.setAttribute("title", value)
- }
- object tags {
- class Builder[+E <: Element](private val element: E) extends AnyVal with Curried {
- @inline def applyBegin = this
- @inline def applyNext(text: String) = {
- element.appendChild(document.createTextNode(text))
- this
- }
- @inline def applyNext(node: Node) = {
- element.appendChild(node)
- this
- }
- @inline def applyNext[A <: Attribute[E]](attribute: A) = {
- attribute(element)
- this
- }
- @inline def applyEnd = element
- }
- @inline def div = new Builder(document.createElement("div"))
- @inline def br = new Builder(document.createElement("br"))
- }
-}
-```
-
-Since `xml.tags.div` returns a `Builder`, which is a subtype of `Curried`, calls on `xml.tags.div` will be translated to the curried form, as shown below:
-``` scala
-xml.tags.div
- .applyBegin
- .applyNext(xml.attributes.title(xml.text("my-title")))
- .applyNext(xml.text("line1"))
- .applyNext(xml.tags.br.applyBegin.applyEnd)
- .applyNext(xml.text("line2"))
- .applyEnd
-```
-
-When the above code is compiled in Scala.js, the builders should be eliminated entirely as a zero cost abstraction layer, and the output JavaScript is tiny as shown below:
-
-``` javascript
-var $$this = $m_Lorg_scalajs_dom_package$().document__Lorg_scalajs_dom_raw_HTMLDocument().createElement("div");
-$$this.setAttribute("title", "my-title");
-$$this.appendChild($m_Lorg_scalajs_dom_package$().document__Lorg_scalajs_dom_raw_HTMLDocument().createTextNode("line1"));
-var $$this$1 = $m_Lorg_scalajs_dom_package$().document__Lorg_scalajs_dom_raw_HTMLDocument().createElement("br");
-$$this.appendChild($$this$1);
-$$this.appendChild($m_Lorg_scalajs_dom_package$().document__Lorg_scalajs_dom_raw_HTMLDocument().createTextNode("line2"));
-```
-
-### Comparison Examples
-
-The `Builder` API can be also implemented in repeated parameters:
-
-``` scala
-import org.scalajs.dom.document
-import org.scalajs.dom.raw._
-
-object xml {
- type Attribute[-A <: Element] = A => Unit
- @inline def text(data: String) = data
- object attributes {
- @inline def title(value: String): Attribute[Element] = _.setAttribute("title", value)
- }
- object tags {
- class Builder[+E <: Element](private val element: E) extends AnyVal {
- @inline def apply(attributesAndChildren: Any*) = {
- attributesAndChildren.foreach {
- case text: String =>
- element.appendChild(document.createTextNode(text))
- case node: Node =>
- element.appendChild(node)
- case attribute: Attribute[E] =>
- attribute(element)
- }
- element
- }
- }
- @inline def div = new Builder(document.createElement("div"))
- @inline def br = new Builder(document.createElement("br"))
- }
-}
-```
-
-However, the Scala compiler is unable to optimize repeated parameters, as a result, the output JavaScript from Scala.js would look like the below code.
-
-``` javascript
-var $$this$1 = $m_Lorg_scalajs_dom_package$().document__Lorg_scalajs_dom_raw_HTMLDocument().createElement("div");
-var this$3 = $m_LScalaFiddle$xml$attributes$();
-var jsx$1 = new $c_sjsr_AnonFunction1().init___sjs_js_Function1((function($this, value) {
- return (function(x$1$2) {
- x$1$2.setAttribute("title", value)
- })
-})(this$3, "my-title"));
-var $$this = $m_Lorg_scalajs_dom_package$().document__Lorg_scalajs_dom_raw_HTMLDocument().createElement("br");
-var array = [jsx$1, "line1", $$this, "line2"];
-var i = 0;
-var len = $uI(array.length);
-while ((i < len)) {
- var index = i;
- var arg1 = array[index];
- if ($is_T(arg1)) {
- var x2 = $as_T(arg1);
- $$this$1.appendChild($m_Lorg_scalajs_dom_package$().document__Lorg_scalajs_dom_raw_HTMLDocument().createTextNode(x2))
- } else if ($uZ((arg1 instanceof $g.Node))) {
- $$this$1.appendChild(arg1)
- } else if ($is_F1(arg1)) {
- var x4 = $as_F1(arg1);
- x4.apply__O__O($$this$1)
- } else {
- throw new $c_s_MatchError().init___O(arg1)
- };
- i = ((1 + i) | 0)
-};
-```
-
-Despite of the type safety issue due to the usage of `Any`, the above code are inefficient:
-
-1. Unnecessary temporary object for the `xml.attributes.title(xml.text("my-title"))`.
-2. Unnecessary temporary `Seq` to hold repeated parameters.
-3. Unnecessary runtime type check for each argument.
-
-The similar issues can be found in many other usage of repeated parameters. For example, Scala string interpolation is inefficient due to its internal vararg function call, unless implementing it in a macro; Scala collection initializers (e.g. `List(1, 2, 3)`) create unnecessary temporary `Seq` before creating the desired collection.
-
-## Design
-
-This proposal introduces a new type `Curried` defined as following:
-
-``` scala
-trait Curried extends Any
-```
-
-When a function call `f(p1, p2, p3, ... pn)` is being type checked, the compiler will firstly look for `apply` method on `f`. If an applicable `apply` method is not found and `f` is a subtype of `Curried`, the compiler will convert the function call to curried form `f.applyBegin.applyNext(p1).applyNext(p2).applyNext(p3) ... .applyNext(pn).applyEnd`, and continue type checking the translated call.
-
-### Expanding sequence argument
-
-Optionally, some arguments to a `Curried` call may be a sequence argument marked as `_*`. Those are arguments should be translated to `applyNextSeq` calls instead of `applyNext`. For example, `f(p1, s1: _*, p2)` will be translated to the following code.
-
-``` scala
-f.applyBegin
- .applyNext(p1)
- .applyNextSeq(s1)
- .applyNext(p2)
-.applyEnd
-```
-
-Unlike traditional repeated parameters, which restrict the sequence argument at the last position, sequence arguments in a curried call are allowed at any position.
-
-### Builder type shifting
-
-The type of partially applied function might be changed during applying each argument. Given the following type signature:
-
-``` scala
-class ListBuilder[A] {
- def applyNext[B >: A](b: B): ListBuilder[B] = ???
- def applyNextSeq[B >: A](seqB: Seq[B]): ListBuilder[B] = ???
- def applyEnd: List[A] = ???
-}
-object List extends Curried {
- def applyBegin[A]: ListBuilder[A] = ???
-}
-```
-
-`List(42, "a")` should be translated to `List.applyBegin.applyNext(42).applyNext("a").applyEnd`. Then, the typer will infer type parameters as `List.applyBegin[Nothing].applyNext[Int](42).applyNext[Any]("a").applyEnd`, therefore the final return type of `applyEnd` will be `List[Any]`.
-
-### Explicit type parameters
-
-When a `Curried` is invoked with some type arguments, those type arguments will be moved to the `applyBegin` method. Therefore, `List[Int](1 to 3: _*)` should be translated to `List.applyBegin[Int].applyNextSeq(1 to 3).applyEnd`.
-
-### Implicit parameters
-
-A more common form of curried function call would be like `f(a)(b)(c)`. We prefer the explicit named method calls to `applyNext` instead of the common form, in order to support implicit parameters in `applyNext`. Therefore, each explicit parameter might come with an implicit parameter list, resolving the infamous [multiple type parameter lists](https://github.com/scala/bug/issues/4719) issue.
-
-### Multiple curried vararg parameter lists
-
-When a `Curried` is invoked with multiple parameter lists, for example:
-``` scala
-f(a, b, c)(d, e)
-```
-
-Then the first parameter list should be translated to a curried call:
-
-``` scala
-f.applyBegin
- .applyNext(a)
- .applyNext(b)
- .applyNext(c)
-.applyEnd(d, e)
-```
-
-`(d, e)` is translated to the curried form only if `applyEnd` returns a `Curried`.
-
-### Overloaded curried calls
-
-Curried varargs enables overloaded functions for each parameter. Parameters will not be erased to their common supertype.
-
-## Implementation
-
-This proposal can be implemented either in the Scala compiler or in a whitebox macro. [Curried.scala](https://github.com/Atry/Curried.scala) is an implementation of the proposal in a whitebox macro.
-
-## Alternatives
-
-### Repeated parameters
-
-Repeated parameters are packed into a `Seq`, which is then passed to the callee.
-
-#### Pros
-
-* Interoperable with Java
-
-#### Cons
-
-* Always boxing value class parameters
-* Unable to inline function parameters
-* Unable to inline call-by-name parameters
-* Unable to perform implicit conversion for each parameter
-* Unable to infer context bound for each parameter
-* Erasing all parameters to their common super type
-
-## Reference
-* [Existing Implementation (Curried.scala)](https://github.com/Atry/Curried.scala)
-* [Discussion on Scala Contributors forum](https://contributors.scala-lang.org/t/pre-sip-curried-varargs/3608)
-* [Pre SIP: name based XML literals](https://contributors.scala-lang.org/t/pre-sip-name-based-xml-literals/2175)
-* [Scala Language Specification - Repeated Parameters](https://scala-lang.org/files/archive/spec/2.13/04-basic-declarations-and-definitions.html#repeated-parameters)
diff --git a/_sips/sips/2019-10-24-name-based-xml.md b/_sips/sips/2019-10-24-name-based-xml.md
deleted file mode 100644
index 6389003fa9..0000000000
--- a/_sips/sips/2019-10-24-name-based-xml.md
+++ /dev/null
@@ -1,421 +0,0 @@
----
-layout: sip
-title: SIP-NN - Name Based XML Literals
-vote-status: pending
-permalink: /sips/:title.html
-redirect_from: /sips/pending/name-based-xml.html
----
-
-**By: Yang, Bo**
-
-## History
-
-| Date | Version |
-|---------------|---------------|
-| Oct 24th 2019 | Initial Draft |
-
-## Introduction
-
-Name-based `for` comprehension has been proven success in Scala language design. A `for` / `yield` expression will be converted to higher-order function calls to `flatMap` , `map` and `withFilter` methods, no matter which type signatures they are. The `for` comprehension can be used for either `Option` or `List` , even when `List` has an additional implicit `CanBuildFrom` parameter. Third-party libraries like Scalaz and Cats also provides `Ops` to allow monadic data types in `for` comprehension.
-
-[Name-based pattern matching](https://dotty.epfl.ch/docs/reference/changed-features/pattern-matching.html) is introduced by Dotty. It is greatly simplified the implementation compared to Scala 2. In addition, specific symbols in Scala library ( `Option` , `Seq` ) are decoupled from the Scala compiler.
-
-Considering the success of the above name-based syntactic sugars, in order to decouple `scala-xml` library from Scala compiler, name-based XML literal is an obvious approach.
-
-## Motivating Examples
-
-### Examples
-
-Given an XML literal `
line1 line2
`, at the parser phase, the compiler should internally convert it to an AST equivalent to the following code:
-
-``` scala
-xml.literal(
- xml.elements.div(
- xml.attributes.title(xml.values.`my-title`),
- xml.texts.line1,
- xml.elements.br(),
- xml.texts.line2
- )
-)
-```
-
-By creating or importing different implementation of `xml`, various representation of objects for the XML literal will be created. For example, to create HTML DOM in Scala.js, you can define `xml` object as following:
-
-``` scala
-import org.scalajs.dom.document
-import org.scalajs.dom.raw._
-
-object xml {
- type Attribute[-A <: Element] = A => Unit
- object values extends Dynamic {
- def selectDynamic(data: String) = data
- }
- object texts extends Dynamic {
- def selectDynamic(data: String) = data
- }
- object attributes {
- def title(value: String): Attribute[Element] = _.setAttribute("title", value)
- }
- object elements {
- class Builder[+E <: Element](val element: E) extends AnyVal {
- def apply(attributesAndChildren: Any*) = {
- attributesAndChildren.foreach {
- case text: String =>
- element.appendChild(document.createTextNode(text))
- case builder: Builder[_] =>
- element.appendChild(builder.element)
- case node: Node =>
- element.appendChild(node)
- case attribute: Attribute[E] =>
- attribute(element)
- }
- element
- }
- }
- def div = new Builder(document.createElement("div"))
- def br = new Builder(document.createElement("br"))
- def literal[+E <: Element](builder: Builder[E]) = builder.element
- }
-}
-```
-
-The ability of custom implementation for XML literals enables a lot of possibilities, including React-like virtual DOM frameworks, static type checked XML schema, and reactive XHTML/FXML templating.
-
-### Comparison Examples
-
-XML literals in Scala 2.13 are symbol based, which means the type of an XML literal is always `scala.xml.Elem`. The code `
line1 line2
` will be parsed to an AST equivalent to the following code:
-
-``` scala
-{
- var $md: MetaData = Null;
- $md = new UnprefixedAttribute("title", new Text("my-title"), $md);
- new Elem(null, "div", $md, TopScope, false, ({
- val $buf = new NodeBuffer();
- $buf.$amp$plus(new Text("line1"));
- $buf.$amp$plus({
- {
- new Elem(null, "br", Null, TopScope, true)
- }
- });
- $buf.$amp$plus(new Text("line2"));
- $buf
- }: _*))
-}
-```
-
-Note that `MetaData`, `UnprefixedAttribute`, `Text`, `Elem` and `TopScope` are types defined in `scala.xml`. Library authors cannot create their custom representation of XML literals.
-
-### Counter-Examples
-
-With the help of this proposal, a library author can create custom XML based DSL.
-
-``` scala
-
-```
-
-It will be translated to:
-
-``` scala
-xml.literal(
- xml.elements.div(
- xml.elements.label(
- xml.attributes.`v-if`(xml.interpolation(math.random() < 0.5)),
- xml.texts.`You might see me`
- )
- )
-)
-```
-
-The translated `v-if` method can be supported by creating an `implicit class` for `xml.attributes` easily. However, this proposal is not intended to be used for creating a DSL as an alternative to regular Scala code. Instead, you should just use ordinary `if` expression.
-
-``` scala
-
Визначення функції. Прихована помилка: без = це процедура, що повертає Unit та може ввести в оману. Не підтримується зі Scala 2.13.
+
+
+
Вірно
def f(x: Any) = println(x)
Невірно
def f(x) = println(x)
+
Визначення функції. Синтаксична помилка: для кожного аргументу має бути вказано тип.
+
+
+
type R = Double
+
Псевдонім (синонім) типу.
+
+
+
def f(x: R)
vs.
def f(x: => R)
+
Виклик-за-значенням.
Виклик-за-іменем (аргумент обчислюється кожен раз як до нього звертаються).
+
+
+
(x: R) => x * x
+
Анонімна функція.
+
+
+
(1 to 5).map(_ * 2)
vs.
(1 to 5).reduceLeft(_ + _)
+
Анонімна функція: підкреслення це позиційний аргумент, тобто місце, куди буде підставлено аргумент функції.
+
+
+
(1 to 5).map(x => x * x)
+
Анонімна функція: щоб використати аргумент двічі, треба його назвати. Зліва від => задається ім'я змінної, якій буде присвоєно аргумент та яку можна використати справа.
+
+
+
(1 to 5).map { x =>
+ val y = x * 2
+ println(y)
+ y
+}
+
Анонімна функція: блоковий стиль (фігурні дужки означають блок) повертає останній вираз.
Для зіставлення зі зразком необхідно використати case перед аргументами анонімної функції.
+
+
+
Невірно
+
val v42 = 42
+24 match {
+ case v42 => println("42")
+ case _ => println("Not 42")
+}
+
v42 буде інтерпретовано як ім'я змінної у зразку, яка буде вірно зіставлена з будь-яким Int значенням, і буде виведено “42”.
+
+
+
Вірно
+
val v42 = 42
+24 match {
+ case `v42` => println("42")
+ case _ => println("Not 42")
+}
+
`v42` у зворотних галочках буде інтерпретовано як значення наявної змінної v42, і буде виведено “Not 42”.
+
+
+
Вірно
+
val UppercaseVal = 42
+24 match {
+ case UppercaseVal => println("42")
+ case _ => println("Not 42")
+}
+
UppercaseVal буде інтерпретовано так само як наявна змінна, а не нова змінна в патерні. Тому значення, що міститься в UppercaseVal буде порівняно з 24, і буде виведено “Not 42”.
+
+
+
об'єктна орієнтація
+
+
+
+
class C(x: R)
+
Параметри конструктора - тільки x доступний в тілі класу.
+
+
+
class C(val x: R)
var c = new C(4)
c.x
+
Параметри конструктора - автоматичне створення публічного об'єкта.
+
+
+
class C(var x: R) {
+ assert(x > 0, "positive please")
+ var y = x
+ val readonly = 5
+ private var secret = 1
+ def this = this(42)
+}
+
Тіло класу є конструктором. Оголосити відкритий (public) атрибут. Оголосити атрибут, доступний тільки на читання. Оголосити закритий (private) атрибут. Альтернативний конструктор.
+
+
+
new {
+ ...
+}
+
Анонімний клас.
+
+
+
abstract class D { ... }
+
Визначити абстрактний клас (без можливості створення об'єкту).
+
+
+
class C extends D { ... }
+
Визначити клас, що наслідує інший.
+
+
+
class D(var x: R)
class C(x: R) extends D(x)
+
Наслідування та параметри конструктора (за замовчуванням відбувається передача аргументів).
+
+
+
object O extends D { ... }
+
Визначити єдиний екземпляр (singleton).
+
+
+
trait T { ... }
class C extends T { ... }
class C extends D with T { ... }
+
Риси - трейти (traits). Інтерфейси-з-імплементацією. У трейту немає параметрів конструктора. композиція з домішками (mixin).
+
+
+
trait T1; trait T2
class C extends T1 with T2
class C extends D with T1 with T2
+
Множинні трейти.
+
+
+
class C extends D { override def f = ...}
+
При реалізації вже наявного методу необхідно вказати overrides.
+
+
+
new java.io.File("f")
+
Створення об'єкту.
+
+
+
Невірно
new List[Int]
Вірно
List(1, 2, 3)
+
Помилка типу: абстрактний тип. Натомість, існує конвенція у таких випадках використовувати фабричний метод обʼєкту компаньйону, що приховує конкретний тип.
+
+
+
classOf[String]
+
Літерал класу (Class[String] = class java.lang.String).
+
+
+
x.isInstanceOf[String]
+
Перевірка типу під час виконання (runtime).
+
+
+
x.asInstanceOf[String]
+
Приведення типу під час виконання (runtime).
+
+
+
x: String
+
Приписування типу під час компіляції (compile time).
+
+
+
+
опції (options)
+
+
+
+
Some(42)
+
Конструктор для непустого опціонального значення (тип Some[T]).
+
+
+
None
+
Одинак (Singleton) пустого опціонального значення (тип None).
+
+
+
Option(null) == None
+Option(24) == Some(24)
+
obj.unsafeMethod // number or null
+Option(obj.unsafeMethod) // Some or None
+ проте
+
Some(null) != None
+
Null-safe фабрика опціональних значень.
+
+
+
val optStr: Option[String] = None
+ так само, як і
+
val optStr = Option.empty[String]
+
Явна типізація опціонального значення. Фабричний метод для створення пустих опціональних значень.
val upper = for {
+ name <- request.getParameter("name")
+ trimmed <- Some(name.trim)
+ if trimmed.length != 0
+ upper <- Some(trimmed.toUpperCase)
+} yield upper
+println(upper.getOrElse(""))
+
Синтаксис for-виразу.
+
+
+
option.map(f(_))
+ так само, як і
+
option match {
+ case Some(x) => Some(f(x))
+ case None => None
+}
+
Застосування функції до опціонального значення.
+
+
+
option.flatMap(f(_))
+ так само, як і
+
option match {
+ case Some(x) => f(x)
+ case None => None
+}
+
Так само, як і mapб але функція має повернути опціональне значення.
+
+
+
optionOfOption.flatten
+ так само, як і
+
optionOfOption match {
+ case Some(Some(x)) => Some(x)
+ case _ => None
+}
+
Вилучення вкладених опціональних значень.
+
+
+
option.foreach(f(_))
+ так само, як і
+
option match {
+ case Some(x) => f(x)
+ case None => ()
+}
+
Застосувати процедуру на опціональному значенні.
+
+
+
option.fold(y)(f(_))
+ так само, як і
+
option match {
+ case Some(x) => f(x)
+ case None => y
+}
+
Застосувати функцію на опціональному значенні та повернути значення, якщо воно порожнє.
+
+
+
option.collect {
+ case x => ...
+}
+ так само, як і
+
option match {
+ case Some(x) if f.isDefinedAt(x) => ...
+ case Some(_) => None
+ case None => None
+}
+
Виконати часткове зіставлення зі зразком опціонального значення.
+
+
+
option.isDefined
+ так само, як і
+
option match {
+ case Some(_) => true
+ case None => false
+}
+
true якщо не порожнє.
+
+
+
option.isEmpty
+ так само, як і
+
option match {
+ case Some(_) => false
+ case None => true
+}
+
true якщо порожнє.
+
+
+
option.nonEmpty
+ так само, як і
+
option match {
+ case Some(_) => true
+ case None => false
+}
+
true якщо не порожнє.
+
+
+
option.size
+ так само, як і
+
option match {
+ case Some(_) => 1
+ case None => 0
+}
+
0 якщо порожнє, інакше 1.
+
+
+
option.orElse(Some(y))
+ так само, як і
+
option match {
+ case Some(x) => Some(x)
+ case None => Some(y)
+}
+
Обчислити та повернути альтернативне опціональне значення, якщо порожнє.
+
+
+
option.getOrElse(y)
+ так само, як і
+
option match {
+ case Some(x) => x
+ case None => y
+}
+
Обчислити та повернути значення за замовчуванням, якщо порожнє.
+
+
+
option.get
+ так само, як і
+
option match {
+ case Some(x) => x
+ case None => throw new Exception
+}
+
Повернути значення, або згенерувати виключення, якщо порожнє.
+
+
+
option.orNull
+ так само, як і
+
option match {
+ case Some(x) => x
+ case None => null
+}
+
Повернути значення, null якщо порожнє.
+
+
+
option.filter(f)
+ так само, як і
+
option match {
+ case Some(x) if f(x) => Some(x)
+ case _ => None
+}
+
Фільтрація опціонального значення. Повернути значення, якщо предикат істинний.
+
+
+
option.filterNot(f(_))
+ так само, як і
+
option match {
+ case Some(x) if !f(x) => Some(x)
+ case _ => None
+}
+
Фільтрація опціонального значення. Повернути значення, якщо предикат хибний.
+
+
+
option.exists(f(_))
+ так само, як і
+
option match {
+ case Some(x) if f(x) => true
+ case Some(_) => false
+ case None => false
+}
+
Повернути значення предикату на опціональному значенні або false якщо порожнє.
+
+
+
option.forall(f(_))
+ так само, як і
+
option match {
+ case Some(x) if f(x) => true
+ case Some(_) => false
+ case None => true
+}
+
Повернути значення предикату на опціональному значенні або true якщо порожнє..
+
+
+
option.contains(y)
+ так само, як і
+
option match {
+ case Some(x) => x == y
+ case None => false
+}
+
Перевіряє чи дорівнює опціональне значення параметру, false якщо порожнє.
+
+
+
diff --git a/_uk/getting-started/install-scala.md b/_uk/getting-started/install-scala.md
new file mode 100644
index 0000000000..d8ae3efbd9
--- /dev/null
+++ b/_uk/getting-started/install-scala.md
@@ -0,0 +1,221 @@
+---
+layout: singlepage-overview
+title: Перші кроки
+partof: getting-started
+language: uk
+includeTOC: true
+redirect_from:
+ - /uk/scala3/getting-started.html # we deleted the scala 3 version of this page
+---
+
+Інструкції нижче стосуються як Scala 2 так, і та Scala 3.
+
+## Спробуйте Scala без інсталяції
+
+Щоб швидко почати експериментувати зі Scala, відкрийте “Scastie” у вашому браузері.
+_Scastie_ це онлайн “пісочниця”, де ви можете експериментувати з прикладами на Scala та подивитись як все працює, з доступом до всіх компіляторів Scala та доступних бібліотек.
+
+> Scastie підтримує як Scala 2 так, і Scala 3, але за замовчування
+> використовується Scala 3. Якщо ж ви шукаєте приклади на Scala 2,
+> [натисніть тут](https://scastie.scala-lang.org/MHc7C9iiTbGfeSAvg8CKAA).
+
+## Встановіть Scala на ваш комп'ютер
+
+Інсталяція Scala означає встановлення різних command-line інструментів, таких як компілятор Scala та інструменти для збірки.
+Ми радимо використовувати інсталятор "Coursier", який автоматично встановить всі необхідні залежності, але ви можете встановити окремо кожен інструмент.
+
+### За допомогою інсталятора Scala (рекомендовано)
+
+Інсталятор Scala називається [Coursier](https://get-coursier.io/docs/cli-overview), а його основна команда має назву `cs`.
+Він гарантує, що JVM та стандартні інструменти Scala встановлені на вашій системі.
+Щоб встановити його на вашій системі виконайте наступні інструкції.
+
+
+{% tabs install-cs-setup-tabs class=platform-os-options %}
+
+
+{% tab macOS for=install-cs-setup-tabs %}
+Виконайте наступну команду в терміналі, виконуючи всі спливаючі інструкції:
+{% include code-snippet.html language='bash' codeSnippet=site.data.setup-scala.macOS-brew %}
+{% altDetails cs-setup-macos-nobrew "Якщо ви не використовуєте Homebrew:" %}
+{% include code-snippet.html language='bash' codeSnippet=site.data.setup-scala.macOS-x86-64 %}
+{% endaltDetails %}
+{% endtab %}
+
+
+
+{% tab Linux for=install-cs-setup-tabs %}
+Виконайте наступну команду в терміналі, виконуючи всі спливаючі інструкції:
+{% include code-snippet.html language='bash' codeSnippet=site.data.setup-scala.linux-x86-64 %}
+{% endtab %}
+
+
+
+{% tab Windows for=install-cs-setup-tabs %}
+Завантажте та запустіть [the Scala installer for Windows]({{site.data.setup-scala.windows-link}})
+інсталятор на основі Coursier, виконуючи всі спливаючі інструкції.
+{% endtab %}
+
+
+
+{% tab Other for=install-cs-setup-tabs defaultTab %}
+
+Дотримуйтесь документації від Coursier з того,
+[як встановити і запустити `cs setup`](https://get-coursier.io/docs/cli-installation).
+{% endtab %}
+
+
+{% endtabs %}
+
+
+
+{% altDetails testing-your-setup 'Перевірити налаштування' %}
+Перевірте ваші налаштування виконавши команду `scala -version`, яка має вивести:
+```bash
+$ scala -version
+Scala code runner version: 1.4.3
+Scala version (default): {{site.scala-3-version}}
+```
+Якщо це не спрацювало, необхідно завершити сеанс та зайти в систему знову (або перезавантажити), щоб зміни застосувались на вашій системі.
+{% endaltDetails %}
+
+
+
+Разом з менеджментом JVM-ів, `cs setup` також встановлює корисні command-line інструменти:
+
+| Команда | Опис |
+|---------------|----------------------------------------------------------------------------------------|
+| `scalac` | компілятор Scala |
+| `scala` | інтерактивне середовище Scala та інструмент для запуску скриптів |
+| `scala-cli` | [Scala CLI](https://scala-cli.virtuslab.org), інтерактивні інструменти для Scala |
+| `sbt`, `sbtn` | Інструмент збірки [sbt](https://www.scala-sbt.org/) |
+| `amm` | [Ammonite](https://ammonite.io/) розширене інтерактивне середовище (REPL) |
+| `scalafmt` | [Scalafmt](https://scalameta.org/scalafmt/) призначений для форматування коду на Scala |
+
+Для більш детальної інформації про `cs`, прочитайте
+[документацію coursier-cli](https://get-coursier.io/docs/cli-overview).
+
+> `cs setup` встановлює компілятор Scala 3 та інтерактивне середовище за замовчування (команди `scalac` та
+> `scala` відповідно). Незалежно від того, чи збираєтеся ви використовувати Scala 2 чи 3,
+> тому що більшість проєктів використовує інструменти для збірки,
+> які використовують правильні версії Scala незалежно від того, яка встановлена "глобально".
+> Однак, ви завжди можете запустити певну версію Scala за допомогою
+> ```
+> $ cs launch scala:{{ site.scala-version }}
+> $ cs launch scalac:{{ site.scala-version }}
+> ```
+> Якщо ви надаєте перевагу Scala 2 за замовчуванням, ви можете примусово встановити певну версію:
+> ```
+> $ cs install scala:{{ site.scala-version }} scalac:{{ site.scala-version }}
+> ```
+
+### ...або вручну
+
+Вам необхідно лише два інструменти, для того, щоб скомпілювати, запустити, протестувати й упакувати Scala проєкт: Java 8 або 11, і sbt.
+Щоб встановити їх вручну:
+
+1. Якщо Java 8 або 11 не встановлені, необхідно завантажити
+ Java з [Oracle Java 8](https://www.oracle.com/java/technologies/javase-jdk8-downloads.html), [Oracle Java 11](https://www.oracle.com/java/technologies/javase-jdk11-downloads.html),
+ або [AdoptOpenJDK 8/11](https://adoptopenjdk.net/). Перевірте [сумісність JDK](/overviews/jdk-compatibility/overview.html) для Scala/Java.
+1. Встановіть [sbt](https://www.scala-sbt.org/download.html)
+
+## Створити проєкт "Hello World" з sbt
+
+Після встановлення sbt ви готові до створення проєкту на Scala, який ми розглянемо в подальших розділах.
+
+Щоб створити проєкт, ви можете використати або термінал, або IDE.
+Якщо ви знайомі з командним рядком, ми рекомендуємо такий підхід.
+
+### За допомогою командного рядка
+
+Інструмент sbt призначений для збірки проєкту на Scala. sbt компілює, запускає,
+та тестує ваш код на Scala. (Також він публікує бібліотеки та виконує багато інших задач.)
+
+Щоб створити новий Scala проєкт за допомогою sbt:
+
+1. Перейдіть (`cd`) в пусту директорію.
+1. Виконайте команду `sbt new scala/scala3.g8`, щоб створити проєкт на Scala 3, або `sbt new scala/hello-world.g8`, щоб створити проєкт на Scala 2.
+ Команда завантажує шаблон проєкту з GitHub.
+ Також, створює директорію `target`, яку ви можете проігнорувати.
+1. Коли буде запропоновано, оберіть назву програми `hello-world`. В результаті буде створено проєкт "hello-world".
+1. Подивимося, що щойно було створено:
+
+```
+- hello-world
+ - project (sbt uses this for its own files)
+ - build.properties
+ - build.sbt (sbt's build definition file)
+ - src
+ - main
+ - scala (весь ваш код на Scala буде тут)
+ - Main.scala (Точка входу в програму) <-- це все, що потрібно наразі
+```
+
+Більше документації про sbt можна знайти у [Книзі по Scala](/scala3/book/tools-sbt.html) (див. [тут](/overviews/scala-book/scala-build-tool-sbt.html) версію для Scala 2)
+та в офіційній [документації](https://www.scala-sbt.org/1.x/docs/index.html) sbt
+
+### За допомогою IDE
+
+Ви можете пропустити подальші кроки та перейти до [Створення Scala проєкту з IntelliJ і sbt](/uk/getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.html)
+
+
+## Відкрити проєкт hello-world
+
+Використаймо IDE, щоб відкрити проєкт. Найбільш популярними є IntelliJ та VSCode.
+Обидва з них мають багатий функціонал, але ви також можете використати [багато інших редакторів.](https://scalameta.org/metals/docs/editors/overview.html)
+
+### За допомогою IntelliJ
+
+1. Завантажте та встановіть [IntelliJ Community Edition](https://www.jetbrains.com/idea/download/)
+1. Встановіть плагін Scala дотримуючись [інструкції з встановлення плагінів в IntelliJ](https://www.jetbrains.com/help/idea/managing-plugins.html)
+1. Відкрийте файл `build.sbt` та оберіть *Відкрити як проєкт* (*Open as a project*)
+
+### За допомогою VSCode та metals
+
+1. Завантажте [VSCode](https://code.visualstudio.com/Download)
+1. Встановіть розширення Metals з [the Marketplace](https://marketplace.visualstudio.com/items?itemName=scalameta.metals)
+1. Відкрийте директорію, що містить файл `build.sbt` (це має бути директорія `hello-world` якщо ви виконали попередні інструкції). Коли буде запропоновано, оберіть *Імпортувати збірку* (*Import build*).
+
+>[Metals](https://scalameta.org/metals) це “Сервер мови Scala” який забезпечує можливість написання коду на Scala в VS Code та інших редакторах на кшталт [Atom, Sublime Text, and more](https://scalameta.org/metals/docs/editors/overview.html), використовуючи Language Server Protocol.
+>
+> Під капотом, Metals комунікує з інструментом збірки використовуючи
+> [Build Server Protocol (BSP)](https://build-server-protocol.github.io/). Більш детально про те, як працює Metals, можна подивитись на [“Write Scala in VS Code, Vim, Emacs, Atom and Sublime Text with Metals”](https://www.scala-lang.org/2019/04/16/metals.html).
+
+### Внесення змін в початковий код
+
+Перегляньте ці два файли у вашому IDE:
+
+- _build.sbt_
+- _src/main/scala/Main.scala_
+
+Коли ви будете запускати ваш проєкт у наступному кроці, то будуть використані конфігурації з _build.sbt_ для запуску коду в _src/main/scala/Main.scala_.
+
+## Запустити Hello World
+
+Якщо вам зручно користуватися IDE, ви можете запустити код в _Main.scala_ з вашого IDE.
+
+В іншому випадку ви можете запустити програму через термінал, виконавши такі дії:
+
+1. `cd` в `hello-world`.
+1. Запустіть `sbt`. Це відкриє консоль sbt.
+1. Наберіть `~run`. Символ `~` опціональний і змушує sbt повторно запускатися після кожного збереження файлу,
+ що забезпечує швидкий цикл редагування/запуск/налагодження. sbt також створить директорію `target`, яку ви можете проігнорувати.
+
+Коли ви закінчите експериментувати з вашим проєктом, натисніть `[Enter]` щоб перервати команду `run`.
+Потім наберіть `exit` або затисніть `[Ctrl+D]` щоб вийти з sbt та повернутись до вашого командного рядка.
+
+## Наступні кроки
+
+Після того, як ви закінчите наведені вище посібники, спробуйте пройти:
+
+* [Книга по Scala](/scala3/book/introduction.html) (версія по Scala 2 [тут](/overviews/scala-book/introduction.html)), яка містить коротких ознайомчих уроків з основних можливостей Scala.
+* [Тур по Scala](/tour/tour-of-scala.html) for bite-sized introductions to Scala's features.
+* [Навчальні ресурси](/online-courses.html), що містять інтерактивні онлайн путівники та курси.
+* [Наш список деяких популярних книжок по Scala](/books.html).
+* [Посібник з міграції](/scala3/guides/migration/compatibility-intro.html) допомагає перевести ваш наявний проєкт зі Scala 2 на Scala 3.
+
+## Отримати допомогу
+Існує безліч поштових розсилок та чатів в режимі реального часу, якщо ви захочете зв'язатися з іншими користувачами Scala. Перейдіть на сторінку нашої [спільноти](https://scala-lang.org/community/), щоб побачити перелік можливих способів та попросити про допомогу.
+
diff --git a/_uk/getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.md b/_uk/getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.md
new file mode 100644
index 0000000000..9a9d303f47
--- /dev/null
+++ b/_uk/getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.md
@@ -0,0 +1,100 @@
+---
+title: Створення проєкту на Scala з IntelliJ і sbt
+layout: singlepage-overview
+partof: building-a-scala-project-with-intellij-and-sbt
+language: uk
+disqus: true
+previous-page: /uk/getting-started/intellij-track/getting-started-with-scala-in-intellij
+next-page: /uk/testing-scala-in-intellij-with-scalatest
+---
+
+В цьому посібнику ми побачимо як будувати Scala проєкти використовуючи [sbt](https://www.scala-sbt.org/1.x/docs/index.html).
+sbt — популярний інструмент для компіляції, запуску та тестування проєктів Scala будь-якої складності.
+Використання інструменту збірки, такого як sbt (або Maven/Gradle), стає необхідним, коли ви створюєте проєкти із залежностями або кількома файлами коду.
+Ми припускаємо, що ви завершили [перший посібник](./getting-started-with-scala-in-intellij.html).
+
+## Створення проєкту
+У цьому розділі ми покажемо вам, як створити проєкт в IntelliJ. Однак, якщо вам
+комфортніше працювати у терміналі, ми рекомендуємо подивитись [початок роботи зі Scala і sbt у командному рядку](/uk/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.html)
+і потім повернутися сюди до розділу «Написання коду на Scala».
+
+1. Якщо ви ще не створили проєкт у терміналі, запустіть IntelliJ та оберіть "Створити новий проєкт (Create New Project)"
+ * На панелі зліва оберіть Scala, а на панелі справа оберіть sbt
+ * Натисніть **Next**
+ * Назвіть ваш проєкт "SbtExampleProject"
+1. Якщо ви вже створили проєкт через термінал, запустіть IntelliJ, оберіть *Імпортувати проєкт (Import Project)* та відкрийте файл `build.sbt` вашого проєкту
+1. Впевніться, що **версія JDK** 1.8 або вище, та **версія sbt** 0.13.13 та вище
+1. Натисніть **Use auto-import**, щоб залежності автоматично завантажились
+1. Натисніть **Finish**
+
+## Розуміння структури директорій
+Завдяки sbt створюються директорії, які можуть бути корисні у разі розробки складніших проєктів.
+Поки що ви можете проігнорувати більшість із них, але ось для чого це все:
+
+```
+- .idea (IntelliJ files)
+- project (plugins and additional settings for sbt)
+- src (source files)
+ - main (application code)
+ - java (Java source files)
+ - scala (Scala source files) <-- This is all we need for now
+ - scala-2.12 (Scala 2.12 specific files)
+ - test (unit tests)
+- target (generated files)
+- build.sbt (build definition file for sbt)
+```
+
+
+## Написання коду на Scala
+1. На панелі **Project** зліва розкрийте `SbtExampleProject` => `src` => `main`
+1. Натисніть праву кнопку миші, `scala` та оберіть **New** => **Package**
+1. Назвіть пакет `example` та натисніть **OK** (або просто натисніть клавішу Enter або Return).
+1. Натисніть праву кнопку миші на пакет `example` та оберіть **New** => **Scala class** (якщо ви не бачите цю опцію, натисніть праву кнопку миші на `SbtExampleProject`, натисніть **Add Frameworks Support**, оберіть **Scala** та продовжить)
+1. Назвіть клас `Main` та змініть **Kind** на `Object`.
+1. Змініть код у класі на наступний:
+
+```
+@main def run() =
+ val ages = Seq(42, 75, 29, 64)
+ println(s"The oldest person is ${ages.max}")
+```
+
+Примітка: IntelliJ має власну реалізацію компілятора Scala, тому іноді ваш код є правильним, навіть якщо IntelliJ вказує інше.
+Ви завжди можете перевірити у командному рядку, чи може sbt запустити ваш проєкт.
+
+## Запуск проєкту
+1. З меню **Run** оберіть **Edit configurations**
+1. Натисніть кнопку **+** та оберіть **sbt Task**.
+1. Назвіть його `Run the program`.
+1. В полі **Tasks** наберіть `~run`. Опція `~` змушує sbt перебудовувати та перезапускати проєкт, коли ви зберігаєте зміни у файлі проєкту.
+1. Натисніть **OK**.
+1. В меню **Run** натисніть **Run 'Run the program'**.
+1. В коді змініть `75` на `61` та подивіться оновлений результат в консолі.
+
+## Додавання залежностей
+Давайте ненадовго змістимо фокус на використання опублікованих бібліотек для забезпечення додаткової функціональності ваших програм.
+1. Відкрийте `build.sbt` та додайте наступний рядок:
+
+```
+libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2"
+```
+
+Тут `libraryDependencies` є набором залежностей та використовуючи `+=`,
+ми додаємо залежність [scala-parser-combinators](https://github.com/scala/scala-parser-combinators) до набору залежностей,
+які необхідні для sbt та які завантажаться при його запуску. Тепер в будь-якому Scala файлі ви можете використати
+класи, об'єкти тощо з scala-parser-combinators через звичайний "import".
+
+Більше опублікованих бібліотек можна знайти на
+[Scaladex](https://index.scala-lang.org/) - індекс бібліотек Scala, місце куди ви можете зайти, щоб скопіювати інформацію про бібліотеку
+та додати у ваш `build.sbt` файл.
+
+## Наступні кроки
+
+Перейдіть до наступного навчального матеріалу з серії _початок роботи з IntelliJ_, та дізнайтесь про [тестування Scala в IntelliJ зі ScalaTest](testing-scala-in-intellij-with-scalatest.html).
+
+**або**
+
+* [Книга по Scala](/scala3/book/introduction.html), що є набором коротких вступних уроків з основних особливостей.
+* [Тур по Scala](/tour/tour-of-scala.html) серія коротких оглядових статей про можливості Scala.
+* Продовжить вчити Scala інтерактивно виконуючи
+ [вправи зі Scala](https://www.scala-exercises.org/scala_tutorial).
\ No newline at end of file
diff --git a/_uk/getting-started/intellij-track/getting-started-with-scala-in-intellij.md b/_uk/getting-started/intellij-track/getting-started-with-scala-in-intellij.md
new file mode 100644
index 0000000000..2d44b3ef34
--- /dev/null
+++ b/_uk/getting-started/intellij-track/getting-started-with-scala-in-intellij.md
@@ -0,0 +1,77 @@
+---
+title: Перші кроки зі Scala в IntelliJ
+layout: singlepage-overview
+partof: getting-started-with-scala-in-intellij
+language: uk
+disqus: true
+next-page: /uk/building-a-scala-project-with-intellij-and-sbt
+---
+
+У цьому посібнику буде розглянемо як створити мінімальний проєкт Scala за допомогою IntelliJ IDE з плагіном Scala.
+У цьому посібнику IntelliJ завантажить для вас Scala.
+
+## Встановлення
+1. Впевніться, що ви вже встановили Java 8 JDK (також відому як 1.8)
+ * Запустіть `javac -version` у командному рядку і впевніться, що бачите
+ `javac 1.8.___`
+ * Якщо у вас не встановлена версія 1.8 або вище, [встановіть JDK](https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
+1. Далі, завантажте та встановіть [IntelliJ Community Edition](https://www.jetbrains.com/idea/download/)
+1. Після того, як ви запустили IntelliJ, ви можете завантажити й встановити плагін Scala за інструкцією
+ [як встановлювати плагіни IntelliJ](https://www.jetbrains.com/help/idea/installing-updating-and-uninstalling-repository-plugins.html) (шукайте "Scala" в меню плагінів.)
+
+Під час створення проєкту встановиться остання версія Scala.
+Примітка: якщо ви хочете відкрити наявний проєкт Scala, ви можете натиснути **Open** під час запуску IntelliJ.
+
+## Створення проєкту
+1. Запустіть IntelliJ та натисніть **File** => **New** => **Project**
+1. На панелі зліва оберіть Scala, а на панелі справа - IDEA.
+1. Назвіть проєкт **HelloWorld**
+1. Припускаємо, що ви вперше створюєте проєкт Scala за допомогою IntelliJ,
+ вам потрібно буде встановити Scala SDK. В полі праворуч від Scala SDK натисніть **Create**.
+1. Оберіть останню версію (наприклад, {{ site.scala-version }}) та натисніть **Download**. Це може зайняти декілька хвилин, але наступні проєкти зможуть використати той же SDK.
+1. Після того як створена SDK та ви повернулись до вікна "New Project", натисніть **Finish**.
+
+
+## Написання коду
+
+1. Зліва, на панелі **Project** клацніть кнопкою миші на `src` та оберіть **New** => **Scala class**.
+ Якщо ви не бачите **Scala class**, клацніть правою кнопкою миші на **HelloWorld** та оберіть **Add Framework Support...**, натисніть **Scala** та продовжить.
+ Якщо ви бачите **Error: library is not specified**, ви можете або натиснути на кнопку завантаження або обрати шлях бібліотеки вручну.
+ Якщо ви бачите тільки **Scala Worksheet** спробуйте розкрити директорію `src` та піддиректорію `main` та клацніть правою кнопкою миші на теку `scala`.
+1. Назвіть клас `Hello` та змініть його **Kind** на `object`.
+1. Змініть код класу на наступний:
+
+```
+object Hello extends App {
+ println("Hello, World!")
+}
+```
+
+## Запуск
+* Клацніть правою кнопкою миші `Hello` та оберіть **Run 'Hello'**.
+* Готово!
+
+## Експерименти зі Scala
+Хорошим способом випробувати код є Scala Worksheets
+
+1. Зліва, на панелі проєкту, клацніть правою кнопкою миші на `src` та оберіть **New** => **Scala Worksheet**.
+2. Назвіть робочий лист Scala "Mathematician".
+3. Впишіть наступний код в робочий лист:
+
+```
+def square(x: Int) = x * x
+
+square(2)
+```
+
+Коли ви змінюєте свій код, ви побачите, як він виконується на панелі справа.
+Якщо ви не бачите правої панелі, клацніть правою кнопкою миші на робочому аркуші Scala на панелі проєкту та натисніть Evaluate Worksheet.
+
+
+## Наступні кроки
+
+Тепер ви знаєте, як створити простий проєкт Scala, який можна використовувати,
+щоб почати вивчати мову. У наступному уроці ми познайомимося з важливим інструментом збірки під назвою sbt,
+який можна використовувати як для простих проєктів, так і продакшн програм.
+
+Наступне: [Створення проєкту на Scala з IntelliJ і sbt](building-a-scala-project-with-intellij-and-sbt.html)
diff --git a/_uk/getting-started/intellij-track/testing-scala-in-intellij-with-scalatest.md b/_uk/getting-started/intellij-track/testing-scala-in-intellij-with-scalatest.md
new file mode 100644
index 0000000000..b2e1a9f801
--- /dev/null
+++ b/_uk/getting-started/intellij-track/testing-scala-in-intellij-with-scalatest.md
@@ -0,0 +1,70 @@
+---
+title: Тестування Scala в IntelliJ зі ScalaTest
+layout: singlepage-overview
+partof: testing-scala-in-intellij-with-scalatest
+language: uk
+disqus: true
+previous-page: /uk/building-a-scala-project-with-intellij-and-sbt
+---
+
+Існує кілька бібліотек і методологій тестування для Scala,
+але в цьому посібнику ми продемонструємо один популярний варіант для фреймворку ScalaTest,
+що називається [FunSuite](https://www.scalatest.org/getting_started_with_fun_suite).
+
+Ми припускаємо, що ви знаєте [як створити проєкт з IntelliJ](building-a-scala-project-with-intellij-and-sbt.html).
+
+## Налаштування
+1. Створіть sbt проєкт в IntelliJ.
+1. Додайте залежність ScalaTest:
+ 1. Додайте залежність ScalaTest у файл `build.sbt` вашого проєкту:
+ ```
+ libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.19" % Test
+ ```
+ 1. Ви побачите сповіщення "build.sbt was changed", оберіть **auto-import**.
+ 1. Ці дві дії призведуть до того, що `sbt` завантажить бібліотеку ScalaTest.
+ 1. Зачекайте завершення синхронізації `sbt`; інакше `AnyFunSuite` та `test()` не розпізнаються.
+1. На панелі проєкту розкрийте `src` => `main`.
+1. Клацніть правою кнопкою миші на `scala` та оберіть **New** => **Scala class**.
+1. Назвіть його `CubeCalculator` та змініть **Kind** на `object` та натисніть Enter або двічі клацніть на `object`.
+1. Замініть код на наступний:
+ ```
+ object CubeCalculator:
+ def cube(x: Int) =
+ x * x * x
+ ```
+
+## Створення тесту
+1. Зліва на панелі проєкту розкрийте `src` => `test`.
+1. Клацніть правою кнопкою миші на `scala` та оберіть **New** => **Scala class**.
+1. Назвіть клас `CubeCalculatorTest` та натисніть Enter або двічі клацніть на `class`.
+1. Замініть код на наступний:
+ ```
+ import org.scalatest.funsuite.AnyFunSuite
+
+ class CubeCalculatorTest extends AnyFunSuite:
+ test("CubeCalculator.cube") {
+ assert(CubeCalculator.cube(3) === 27)
+ }
+ ```
+1. У початковому коді клацніть правою кнопкою миші на `CubeCalculatorTest` та оберіть **Run 'CubeCalculatorTest'**.
+
+## Розуміння коду
+
+Переглянемо кожний рядок окремо.
+
+* `class CubeCalculatorTest` означає, що ми тестуємо об'єкт `CubeCalculator`
+* `extends AnyFunSuite` використовуємо функціональність класу AnyFunSuite з ScalaTest, насамперед функцію `test`
+* `test` функція з AnyFunSuite, що збирає результати тверджень (assertions) у тілі функції.
+* `"CubeCalculator.cube"` назва тесту. Ви можете обрати будь-яку назву, але існує домовленість називати "ClassName.methodName".
+* `assert` приймає булеву умову і визначає, пройшов тест чи не пройшов.
+* `CubeCalculator.cube(3) === 27` перевіряє чи дорівнює результат функції `cube` значенню 27.
+ Оператор `===` є частиною ScalaTest та надає чисті повідомлення про помилки.
+
+## Додати інший тест-кейс
+1. Додайте інший тестовий блок з власним `assert`, що перевіряє значення куба `0`.
+1. Виконайте `sbt test` знову, двічі клацнувши правою кнопкою миші на `CubeCalculatorTest` та обравши 'Run **CubeCalculatorTest**'.
+
+## Висновок
+Ви побачили один шлях тестування вашого Scala коду. Більше про
+FunSuite ScalaTest на [офіційному вебсайті](https://www.scalatest.org/getting_started_with_fun_suite).
+Ви можете проглянути інші фреймворки для тестування такі як [ScalaCheck](https://www.scalacheck.org/) та [Specs2](https://etorreborre.github.io/specs2/).
diff --git a/_uk/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.md b/_uk/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.md
new file mode 100644
index 0000000000..58adf6baf9
--- /dev/null
+++ b/_uk/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.md
@@ -0,0 +1,84 @@
+---
+title: Початок роботи зі Scala і sbt у командному рядку
+layout: singlepage-overview
+partof: getting-started-with-scala-and-sbt-on-the-command-line
+language: uk
+disqus: true
+next-page: /uk/testing-scala-with-sbt-on-the-command-line
+---
+
+У цьому посібнику ви дізнаєтесь, як створити проєкт Scala шаблон.
+Ви можете використовувати це як відправну точку для власного проєкту.
+Ми використаємо [sbt](https://www.scala-sbt.org/1.x/docs/index.html), що де-факто є основним інструментом збірки для Scala.
+sbt компілює, запускає, та тестує ваші проєкти поміж інших корисних задач.
+Ми припускаємо, що ви знаєте, як користуватися терміналом.
+
+## Встановлення
+1. Впевніться, що ви вже встановили Java 8 JDK (також відому як 1.8)
+ * Запустіть `javac -version` у командному рядку і впевніться, що бачите
+ `javac 1.8.___`
+ * Якщо у вас не встановлена версія 1.8 або вище, [встановіть JDK](https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
+1. Встановіть sbt
+ * [Mac](https://www.scala-sbt.org/1.x/docs/Installing-sbt-on-Mac.html)
+ * [Windows](https://www.scala-sbt.org/1.x/docs/Installing-sbt-on-Windows.html)
+ * [Linux](https://www.scala-sbt.org/1.x/docs/Installing-sbt-on-Linux.html)
+
+## Створити проєкт
+1. Перейдіть (`cd`) у пусту директорію.
+1. Виконайте наступну команду `sbt new scala/hello-world.g8`.
+Це завантажує шаблон 'hello-world' з GitHub.
+Також буде створена директорія `target`, яку можна ігнорувати.
+1. Коли буде запропоновано, назвіть застосунок `hello-world`. Це створить проєкт з назвою "hello-world".
+1. А тепер подивимось що було згенеровано:
+
+```
+- hello-world
+ - project (sbt uses this to install and manage plugins and dependencies)
+ - build.properties
+ - src
+ - main
+ - scala (All of your scala code goes here)
+ - Main.scala (Entry point of program) <-- this is all we need for now
+ - build.sbt (sbt's build definition file)
+```
+
+Після збірки вашого проєкту, sbt створить більше `target` директорій для згенерованих файлів.
+
+## Запуск проєкту
+1. Перейдіть (`cd`) у `hello-world`.
+1. Виконайте `sbt`. Це запустить sbt консоль.
+1. Наберіть `~run`. Символ `~` є опціональним та означає перебудову при кожному збереженні файлу,
+ що дає можливість пришвидшити цикл редагування/запуск/відлагодження.
+
+## Модифікація коду
+1. Відкрийте файл `src/main/scala/Main.scala` у вашому текстовому редакторі.
+1. Змініть "Hello, World!" на "Hello, New York!"
+1. Якщо ви не зупинили роботу sbt, ви побачите як на консолі з'явиться "Hello, New York!".
+1. Ви можете продовжити робити зміни та бачити результати на консолі.
+
+## Додання залежностей
+Давайте ненадовго змістимо фокус на використання опублікованих бібліотек для забезпечення додаткової функціональності ваших програм.
+
+1. Відкрийте `build.sbt` та додайте наступний рядок:
+
+```
+libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2"
+```
+
+Тут `libraryDependencies` є набором залежностей та використовуючи `+=`,
+ми додаємо залежність [scala-parser-combinators](https://github.com/scala/scala-parser-combinators) до набору залежностей,
+які необхідні для sbt та які завантажаться при його запуску. Тепер в будь-якому Scala файлі ви можете використати
+класи, об'єкти тощо з scala-parser-combinators через звичайний "import".
+
+Більше опублікованих бібліотек можна знайти на
+[Scaladex](https://index.scala-lang.org/) - індекс бібліотек Scala, місце куди ви можете зайти, щоб скопіювати інформацію про бібліотеку
+та додати у ваш `build.sbt` файл.
+
+## Наступні кроки
+
+Перейдіть до наступного посібника з серії _початок роботи з sbt_, та дізнайтесь про [тестування Scala з sbt та ScalaTest в командному рядку](testing-scala-with-sbt-on-the-command-line.html).
+
+**або**
+
+- Продовжить вивчати Scala інтерактивно нам [Вправи зі Scala](https://www.scala-exercises.org/scala_tutorial).
+- Дізнайтеся про можливості Scala у коротких статтях, переглянувши наш [Тур по Scala]({{ site.baseurl }}/tour/tour-of-scala.html).
diff --git a/_uk/getting-started/sbt-track/testing-scala-with-sbt-on-the-command-line.md b/_uk/getting-started/sbt-track/testing-scala-with-sbt-on-the-command-line.md
new file mode 100644
index 0000000000..fc0a6e62ac
--- /dev/null
+++ b/_uk/getting-started/sbt-track/testing-scala-with-sbt-on-the-command-line.md
@@ -0,0 +1,104 @@
+---
+title: Тестування Scala з sbt та ScalaTest в командному рядку
+layout: singlepage-overview
+partof: testing-scala-with-sbt-on-the-command-line
+language: uk
+disqus: true
+previous-page: /uk/getting-started-with-scala-and-sbt-on-the-command-line
+---
+
+Існує кілька бібліотек і методологій тестування для Scala,
+але в цьому посібнику ми продемонструємо один популярний варіант для фреймворку ScalaTest,
+що називається [AnyFunSuite](https://www.scalatest.org/scaladoc/3.2.2/org/scalatest/funsuite/AnyFunSuite.html).
+
+Ми припускаємо, що ви знаєте [як створити проєкт Scala за допомогою sbt](getting-started-with-scala-and-sbt-on-the-command-line.html).
+
+## Налаштування
+1. Створіть десь новий каталог через командний рядок.
+1. Перейдіть (`cd`) в директорію та запустіть `sbt new scala/scalatest-example.g8`
+1. Назвіть проєкт `ScalaTestTutorial`.
+1. Проєкт вже має ScalaTest як залежність у файлі `build.sbt`.
+1. Перейдіть (`cd`) в директорію та запустіть `sbt test`. Це запустить тестове середовище `CubeCalculatorTest` з єдиним тестом `CubeCalculator.cube`.
+
+```
+sbt test
+[info] Loading global plugins from /Users/username/.sbt/0.13/plugins
+[info] Loading project definition from /Users/username/workspace/sandbox/my-something-project/project
+[info] Set current project to scalatest-example (in build file:/Users/username/workspace/sandbox/my-something-project/)
+[info] CubeCalculatorTest:
+[info] - CubeCalculator.cube
+[info] Run completed in 267 milliseconds.
+[info] Total number of tests run: 1
+[info] Suites: completed 1, aborted 0
+[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
+[info] All tests passed.
+[success] Total time: 1 s, completed Feb 2, 2017 7:37:31 PM
+```
+
+## Розуміння тестів
+1. Відкрийте два файли в текстовому редакторі:
+ * `src/main/scala/CubeCalculator.scala`
+ * `src/test/scala/CubeCalculatorTest.scala`
+1. У файлі `CubeCalculator.scala`, визначте функцію `cube`.
+1. У файлі `CubeCalculatorTest.scala`, ви побачите, що клас, що названий так само як і об'єкт, що ми тестуємо.
+
+```
+ import org.scalatest.funsuite.AnyFunSuite
+
+ class CubeCalculatorTest extends AnyFunSuite {
+ test("CubeCalculator.cube") {
+ assert(CubeCalculator.cube(3) === 27)
+ }
+ }
+```
+
+Переглянемо кожний рядок окремо.
+
+* `class CubeCalculatorTest` означає, що ми тестуємо об'єкт `CubeCalculator`
+* `extends AnyFunSuite` використовуємо функціональність класу AnyFunSuite з ScalaTest, насамперед функцію `test`
+* `test` функція з AnyFunSuite, що збирає результати тверджень (assertions) у тілі функції.
+* `"CubeCalculator.cube"` назва тесту. Ви можете обрати будь-яку назву, але існує домовленість називати "ClassName.methodName".
+* `assert` приймає булеву умову і визначає, пройшов тест чи не пройшов.
+* `CubeCalculator.cube(3) === 27` перевіряє чи дорівнює результат функції `cube` значенню 27.
+ Оператор `===` є частиною ScalaTest та надає чисті повідомлення про помилки.
+
+## Додати інший тест-кейс
+1. Додайте інший тестовий блок з власним `assert`, що перевіряє значення куба '0'.
+
+ ```
+ import org.scalatest.funsuite.AnyFunSuite
+
+ class CubeCalculatorTest extends AnyFunSuite {
+ test("CubeCalculator.cube 3 should be 27") {
+ assert(CubeCalculator.cube(3) === 27)
+ }
+
+ test("CubeCalculator.cube 0 should be 0") {
+ assert(CubeCalculator.cube(0) === 0)
+ }
+ }
+ ```
+
+1. Виконайте `sbt test` знову, щоб побачити результати.
+
+ ```
+ sbt test
+ [info] Loading project definition from C:\projects\scalaPlayground\scalatestpractice\project
+ [info] Loading settings for project root from build.sbt ...
+ [info] Set current project to scalatest-example (in build file:/C:/projects/scalaPlayground/scalatestpractice/)
+ [info] Compiling 1 Scala source to C:\projects\scalaPlayground\scalatestpractice\target\scala-2.13\test-classes ...
+ [info] CubeCalculatorTest:
+ [info] - CubeCalculator.cube 3 should be 27
+ [info] - CubeCalculator.cube 0 should be 0
+ [info] Run completed in 257 milliseconds.
+ [info] Total number of tests run: 2
+ [info] Suites: completed 1, aborted 0
+ [info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0
+ [info] All tests passed.
+ [success] Total time: 3 s, completed Dec 4, 2019 10:34:04 PM
+ ```
+
+## Висновок
+Ви побачили один шлях тестування вашого Scala коду. Більше про
+FunSuite ScalaTest на [офіційному вебсайті](https://www.scalatest.org/getting_started_with_fun_suite).
+Ви можете проглянути інші фреймворки для тестування такі як [ScalaCheck](https://www.scalacheck.org/) та [Specs2](https://etorreborre.github.io/specs2/).
diff --git a/_uk/index.md b/_uk/index.md
new file mode 100644
index 0000000000..6242b6e807
--- /dev/null
+++ b/_uk/index.md
@@ -0,0 +1,105 @@
+---
+layout: landing-page
+title: Документація
+language: uk
+partof: documentation
+discourse: true
+more-resources-label: Додаткові Матеріали
+
+
+# Content masthead links
+
+
+sections:
+ - title: "Перші кроки..."
+ links:
+ - title: "Початок роботи"
+ description: "Встанови Scala на свій комп'ютер і почни писати код Scala!"
+ icon: "fa fa-rocket"
+ link: /uk/getting-started/install-scala.html
+ - title: "Екскурсія по Скала"
+ description: "Короткі введення в основні особливості мови."
+ icon: "fa fa-flag"
+ link: /tour/tour-of-scala.html
+ - title: "Книга по Scala 3"
+ description: "Вивчи Scala, прочитавши серію коротких уроків."
+ icon: "fa fa-book-open"
+ link: /scala3/book/introduction.html
+ - title: "Онлайн курси"
+ description: "MOOC для вивчення Scala для початківців і досвідчених програмістів."
+ icon: "fa fa-cloud"
+ link: /online-courses.html
+ - title: "Книги"
+ description: "Друковані та цифрові книги по Scala."
+ icon: "fa fa-book"
+ link: /books.html
+ - title: "Посібники"
+ description: "Путівник з серії кроків для створення програм на Scala."
+ icon: "fa fa-tasks"
+ link: /tutorials.html
+
+ - title: "Для досвічених"
+ links:
+ - title: "API"
+ description: "Документація API для кожної версії Scala."
+ icon: "fa fa-file-alt"
+ link: /api/all.html
+ - title: "Посібники та огляди"
+ description: "Поглиблена документація, що покриває багато особливостей Scala."
+ icon: "fa fa-database"
+ link: /uk/overviews/index.html
+ - title: "Довідник по стилю"
+ description: "Поглиблений посібник з написання ідіоматичного коду на Scala."
+ icon: "fa fa-bookmark"
+ link: /style/index.html
+ - title: "Шпаргалка"
+ description: "Зручна шпаргалка з основ синтаксису Scala."
+ icon: "fa fa-list"
+ link: /uk/cheatsheets/index.html
+ - title: "Питання-Відповіді"
+ description: "Відповіді на часті запитання про Scala."
+ icon: "fa fa-question-circle"
+ link: /tutorials/FAQ/index.html
+ - title: "Специфікація мови"
+ description: "Специфікація формальної мови Scala."
+ icon: "fa fa-book"
+ link: https://scala-lang.org/files/archive/spec/2.13/
+ - title: "Довідник про мову"
+ description: "Довідкова інформація про мову Scala 3."
+ icon: "fa fa-book"
+ link: https://docs.scala-lang.org/scala3/reference
+
+ - title: "Дослідіть Scala 3"
+ links:
+ - title: "Посібник з міграції"
+ description: "Посібник, що допоможе перейти від Scala 2 до Scala 3."
+ icon: "fa fa-suitcase"
+ link: /scala3/guides/migration/compatibility-intro.html
+ - title: "Нове у Scala 3"
+ description: "Огляд нових функцій у Scala 3."
+ icon: "fa fa-star"
+ link: /uk/scala3/new-in-scala3.html
+ - title: "Новий Scaladoc для Scala 3"
+ description: "Основні характеристики нових функцій у Scaladoc."
+ icon: "fa fa-star"
+ link: /uk/scala3/scaladoc.html
+ - title: "Доповіді"
+ description: "Онлайн доповіді про Scala 3."
+ icon: "fa fa-play-circle"
+ link: /uk/scala3/talks.html
+
+ - title: "Еволюція Scala"
+ links:
+ - title: "SIPs"
+ description: "Процес удосконалення Scala (Scala Improvement Process). Еволюція мови та компілятора."
+ icon: "fa fa-cogs"
+ link: /sips/index.html
+ - title: "Внесок у Scala"
+ description: "Повний посібник із участі в проекті Scala."
+ icon: "fa fa-cogs"
+ link: /contribute/
+ - title: "Посібник з внесення змін у Scala 3"
+ description: "Посібник з компілятора Scala 3 та вирішення проблем."
+ icon: "fa fa-cogs"
+ link: /scala3/guides/contribution/contribution-intro.html
+---
diff --git a/_uk/overviews/index.md b/_uk/overviews/index.md
new file mode 100644
index 0000000000..355fc560fa
--- /dev/null
+++ b/_uk/overviews/index.md
@@ -0,0 +1,8 @@
+---
+layout: overviews
+partof: overviews
+title: Документація
+language: uk
+---
+
+
diff --git a/_uk/scala3/guides/tasty-overview.md b/_uk/scala3/guides/tasty-overview.md
new file mode 100644
index 0000000000..53eed66f34
--- /dev/null
+++ b/_uk/scala3/guides/tasty-overview.md
@@ -0,0 +1,164 @@
+---
+layout: singlepage-overview
+title: Огляд TASTy
+partof: tasty-overview
+language: uk
+scala3: true
+versionSpecific: true
+---
+Створіть файл вихідного коду Scala 3 _Hello.scala_:
+
+```scala
+@main def hello = println("Hello, world")
+```
+
+і скомпілюйте файл з `scalac`:
+
+```bash
+$ scalac Hello.scala
+```
+
+ви помітите, що серед інших отриманих файлів, `scalac` створює файли з розширенням _.tasty_:
+
+```bash
+$ ls -1
+Hello$package$.class
+Hello$package.class
+Hello$package.tasty
+Hello.scala
+hello.class
+hello.tasty
+```
+
+Виникає питання: «Що таке tasty?»
+
+
+
+## Що таке TASTy?
+
+TASTy це акронім терміну, _Типізоване абстрактне синтаксичне дерево (Typed Abstract Syntax Trees)_.
+Це високорівневий формат для Scala 3, і в цьому документі ми називатимемо його як _Tasty_.
+
+Перше, що важливо знати, це те, що файли Tasty генеруються компілятором `scalac`,
+та містять _всю_ інформацію про ваш вихідний код, включаючи синтаксичну структуру вашої програми,
+і _повну_ інформацію про типи, позицію та навіть документацію.
+Файли Tasty містять набагато більше інформації, ніж файли _.class_, які створюються для роботи на JVM. (Детальніше далі.)
+
+У Scala 3 процес компіляції виглядає так:
+
+```text
+ +-------------+ +-------------+ +-------------+
+$ scalac | Hello.scala | -> | Hello.tasty | -> | Hello.class |
+ +-------------+ +-------------+ +-------------+
+ ^ ^ ^
+ | | |
+ Ваш вихідний Файл TASTy Файл класу
+ код для scalac для JVM
+ (містить повну (неповна
+ інформацію) інформація)
+```
+
+Ви можете переглянути вміст файлу _.tasty_ у зрозумілій формі, запустивши на ньому компілятор із прапорцем `-print-tasty`.
+Ви також можете переглянути вміст, декомпільований у формі, подібній до вихідного коду Scala, використовуючи прапор `-decompile`.
+```bash
+$ scalac -print-tasty hello.tasty
+$ scalac -decompile hello.tasty
+```
+
+### Проблеми з файлами _.class_
+
+Через проблему [стирання типів][erasure], файли _.class_ містять неповне представлення про ваш код.
+Простий спосіб продемонструвати це приклад з `List`.
+
+_Стирання типів_ означає, що коли ви пишете наступний код Scala:
+
+```scala
+val xs: List[Int] = List(1, 2, 3)
+```
+
+цей код компілюється у файл _.class_, який має бути сумісним із JVM. Результатом цієї вимоги сумісності код всередині цього файлу класу — який ви можете побачити за допомогою команди `javap` — виглядає так:
+
+```java
+public scala.collection.immutable.List xs();
+```
+
+Результат команди `javap` показує Java-уявлення того, що міститься у файлі класу. Зверніть увагу, що `xs` більше _не_ визначений як `List[Int]`; він по суті представлений як `List[java.lang.Object]`. Щоб ваш код Scala працював із JVM, тип `Int` має бути стертим.
+
+Далі, коли ви отримуєте елемент вашого `List[Int]` у вашому Scala коді, наприклад:
+
+```scala
+val x = xs(0)
+```
+
+отриманий файл класу матиме операцію перетворення для цього рядка коду, яку ви можете уявити так:
+
+```
+int x = (Int) xs.get(0) // Java-подібно
+val x = xs.get(0).asInstanceOf[Int] // більш Scala-подібно
+```
+
+Знову ж таки, це зроблено для сумісності, щоб ваш код Scala міг працювати на JVM.
+Однак, інформація про те, що ми вже мали список цілих чисел, втрачається у файлах класу.
+Це створює проблеми під час спроби збірки Scala програми з уже скомпільованою бібліотекою.
+Для цього нам потрібно більше інформації, ніж зазвичай міститься у файлах класу.
+
+Ця дискусія охоплює лише тему стирання типу.
+Існують подібні проблеми для кожної іншої конструкції Scala, про які JVM не знає, включно з union, intersection, trait with parameters та багатьма іншими відмінностями Scala 3.
+
+### На допомогу приходить TASTy
+Таким чином, на відміну від відсутньої інформації про вихідні типи у _.class_ файлах або тільки публічного API (як у «Pickle» форматі Scala 2.13), формат TASTy зберігає повне абстрактне синтаксичне дерево (AST) після перевірки типів.
+Зберігання всього AST має багато переваг: воно дає можливість окремої компіляції, перекомпіляції для іншої версії JVM, статичного аналізу програм і багато іншого.
+
+### Ключові моменти
+
+Отже, це перший висновок з цього розділу: типи, які ви вказуєте у своєму коді Scala, не зовсім точно представлені у файлах _.class_.
+
+Другим ключовим моментом є розуміння того, що існують відмінності між інформацією, яка доступна під час _компіляції_ та _виконання_:
+
+- Під **час компіляції**, `scalac` читає та аналізує ваш код, він знає, що `xs` є `List[Int]`
+- Коли компілятор записує ваш код у файл класу, він записує `xs` як `List[Object]`, та додає інформацію про перетворення усюди, де йде звернення до `xs`
+- Потім під **час виконання** — коли ваш код працює в JVM — JVM не знає, що ваш список є `List[Int]`
+
+Зі Scala 3 та Tasty, є ще одна важлива примітка про час компіляції:
+
+- Коли ви пишете код на Scala 3, що використовує інші Scala 3 бібліотеки, `scalac` більше не має читати їх _.class_ файли;
+ він може прочитати їх _.tasty_ файли, які, як згадувалось, є _точним_ представленням вашого коду.
+ Це важливо для забезпечення окремої компіляції та сумісності між Scala 2.13 і Scala 3.
+
+
+## Переваги Tasty
+
+Як ви можете зрозуміти, доступ до повного представлення вашого коду має [багато переваг][benefits]:
+
+- Компілятор використовує його для підтримки окремої компіляції.
+- Сервер мови, що базується на _Мовному серверному протоколі (Language Server Protocol)_ використовує його для підтримки гіперпосилань, завершення команд, документації, та таких глобальних операцій як, пошук звернень та перейменування.
+- Tasty створює чудову основу для нового покоління [макросів основаних на рефлексії][macros].
+- Оптимізатори та аналізатори можуть використовувати його для глибокого аналізу коду та розширеної генерації коду.
+
+У відповідній примітці, Scala 2.13.6 має програму для читання TASTy, а компілятор Scala 3 також може читати формат 2.13 «Pickle».
+У [сторінці з classpath сумісності][compatibility-ref] посібнику з міграції на Scala 3 пояснюється перевага можливості крос-компіляції.
+
+
+
+## Більше інформації
+
+Підсумовуючи, Tasty — це високорівневий формат обміну для Scala 3, а файли _.tasty_ містять повне представлення вашого вихідного коду, що надає до переваги, описані у попередніх розділах.
+Щоб дізнатися більше, перегляньте ці ресурси:
+
+- У [цьому відео](https://www.youtube.com/watch?v=YQmVrUdx8TU), Jamie Thompson зі Scala Center детально розповідає про те, як працює Tasty, та його переваги
+- Статті з [Бінарної сумісності для авторів бібліотек][binary] розглядаються теми бінарної сумісності, сумісності джерел та модель виконання JVM
+- [Подальша сумісність для Scala 3](https://www.scala-lang.org/blog/2020/11/19/scala-3-forward-compat.html) демонструє методи використання Scala 2.13 і Scala 3 в одному проєкті
+
+Ці статті містять додаткову інформацію про макроси Scala 3:
+
+- [Бібліотеки макросів Scala](https://scalacenter.github.io/scala-3-migration-guide/docs/macros/macro-libraries.html)
+- [Макроси: плани для Scala 3](https://www.scala-lang.org/blog/2018/04/30/in-a-nutshell.html)
+- [Довідник по рефлексії цитат (Quotes Reflect)][quotes-reflect]
+- [Довідник по макросах](/scala3/guides/macros)
+
+[benefits]: https://www.scala-lang.org/blog/2018/04/30/in-a-nutshell.html
+[erasure]: https://www.scala-lang.org/files/archive/spec/2.13/03-types.html#type-erasure
+[binary]: {% link _overviews/tutorials/binary-compatibility-for-library-authors.md %}
+[compatibility-ref]: {% link _overviews/scala3-migration/compatibility-classpath.md %}
+[quotes-reflect]: {{ site.scala3ref }}/metaprogramming/reflection.html
+[macros]: {{ site.scala3ref }}/metaprogramming/macros.html
diff --git a/_uk/scala3/new-in-scala3.md b/_uk/scala3/new-in-scala3.md
new file mode 100644
index 0000000000..0b00d60ca5
--- /dev/null
+++ b/_uk/scala3/new-in-scala3.md
@@ -0,0 +1,139 @@
+---
+layout: singlepage-overview
+title: Нове в Scala 3
+scala3: true
+language: uk
+---
+Нова версія Scala 3 принесла багато покращень і нові можливості.
+Тут наведено короткий огляд найважливіших змін.
+Якщо ви хочете розібратись детальніше глибше, у вашому розпорядженні є наступні посилання:
+
+- [Книга по Scala 3]({% link _overviews/scala3-book/introduction.md %}) націлений на розробників-початківців мови Scala.
+- [Конспект синтаксису][syntax-summary] надає формальний опис нового синтаксису.
+- [Довідник з мови][reference] дає детальний опис змін від Scala 2 до Scala 3.
+- [Посібник з міграції][migration] надає вам всю інформацію, необхідну для переходу від Scala 2 до Scala 3.
+- [Посібник для внесення змін в Scala 3][contribution] глибше занурюється в компілятор, включаючи посібник із розв'язання проблем.
+
+## Що нового в Scala 3
+Scala 3 - це повне перероблення мови Scala. Було змінено багато аспектів
+системи типів на більш принципові. Хоч це і надає нові можливості (наприклад, об’єднання типів),
+але в першу чергу це означає, що у вашій роботі стає менше системи типів та [наведення типів][type-inference].
+Також значно покращено процес перевантаження.
+
+### Нове і яскраве: Синтаксис
+Окрім багатьох (невеликих) очищень, синтаксис Scala 3 пропонує такі покращення:
+
+- Новий «тихий» синтаксис для керуючих структур, таких як `if`, `while` та `for` ([новий синтаксис керуючих структур][syntax-control])
+- Ключеве слово `new` тепер опціональне (_або_ [creator applications][creator])
+- [Опціональні дужки][syntax-indentation] привертають до стилю програмування на основі відступів
+- Зміна [символу підстановки типів][syntax-wildcard] з `_` на `?`.
+- Імплісіти (та їх синтаксис) були [ґрунтовно переглянуті][implicits].
+
+### Впертість: контекстні абстракції
+Одним з основних концептів Scala було (і залишається певною мірою)
+надання користувачам невеликого набору потужних можливостей, які можна комбінувати
+заради великої (а іноді навіть непередбачуваної) виразності. Наприклад, _implicits_
+використовувалися для моделювання контекстної абстракції, для вираження обчислення
+на рівні типів, моделювання типів-класів, виконання неявних приведень, кодування
+розширення методів та багато іншого.
+Базуючись на цих прикладах використання, Scala 3 використовує дещо інший підхід
+і фокусується на **намірі**, а не на **механізмі**.
+Замість того, щоб пропонувати одну дуже потужну функцію, Scala 3 пропонує кілька
+спеціальних мовних конструкцій, що дозволяють програмістам прямо висловлювати свої наміри:
+
+- **Абстрагування над контекстною інформацією**. [Ключове слово using][contextual-using] дозволяє програмістам абстрагуватися від інформації, яка доступна в контексті виклику і повинна передаватися неявно. Конструкція using є удосконаленням implicit зі Scala 2 та може бути визначена за типом, звільняючи сигнатури функцій від термів, на які ніколи не посилаються явно.
+
+- **Надання екземплярів класів типів**. [Наведені екземпляри][contextual-givens] дозволяють програмістам визначати _канонічне значення_ певного типу. Це робить програмування з класами типів простішим без витоку деталей реалізації.
+
+- **Ретроспективне розширення класів**. У Scala 2 методи розширення повинні бути закодовані за допомогою неявних перетворень або неявних класів. На відміну від цього, у Scala 3 [методи розширення][contextual-extension] тепер безпосередньо вбудовані в мову, що призводить до кращих повідомлень про помилки та покращеного виведення типу.
+
+- **Відображення одного типу як іншого**. Неявні перетворення були [перероблені][contextual-conversions] з нуля як екземпляри класу типів `Conversion`.
+
+- **Контекстні абстракції вищого порядку**. _Абсолютно нова_ можливість [контекстних функцій][contextual-functions] робить контекстні абстракції first-class citizen. Вони є важливим інструментом для авторів бібліотек і дозволяють стисло виразити домен-специфічні мови.
+
+- **Дієвий відгук від компілятора**. Якщо неявний параметр не може бути розв'язаний компілятором, то надаються [пропозиції імпорту](https://www.scala-lang.org/blog/2020/05/05/scala-3-import-suggestions.html), що можуть розв'язувати проблему.
+
+### Скажи що маєш на увазі: покращення системи типів
+Окрім значно покращеного виведення типів, система типів Scala 3 також пропонує багато нових функцій, надаючи вам потужні інструменти для статичного вираження інваріантів у типах:
+
+- **Перерахування**. [Enum][enums] був перероблений, щоб добре поєднуватися з кейс-класами та сформувати новий стандарт для вираження [алгебраїчних типів даних][enums-adts].
+
+- **Непрозорі типи**. Сховайте деталі реалізації за [псевдонімом непрозорого типу][types-opaque] без зниження перфомансу! Непрозорі типи замінюють класи значень і дозволяють налаштувати бар'єр абстракції без додаткових накладних витрат.
+
+- **Типи перетину та об'єднання**. Нові засади системи типів призвели до введення нових можливостей системи типів: екземпляр [типу Intersection][types-intersection], як `A & B`, є екземпляром _обох_ типів і `A` і `B`. Екземпляр [типу Union][types-union], як `A | B`, є екземпляром _або_ `A` або `B`. Обидві конструкції дозволяють програмістам гнучко обмежувати типи поза межами ієрархії наслідування.
+
+- **Залежні типи функцій**. Scala 2 вже дозволяє типам результату залежати від (значення) аргументів. У Scala 3 тепер можна абстрагуватися над цим шаблоном і виразити [залежні типи функцій][types-dependent]. В типі `type F = (e: Entry) => e.Key` результат _залежить_ від аргументу!
+
+- **Поліморфні типи функцій**. Як і типи функцій залежності, Scala 2 підтримувала методи, які дозволяють параметри типу, але не дозволяла абстрагуватися над цими методами. У Scala 3, [поліморфні типи функцій][types-polymorphic], наприклад `[A] => List[A] => List[A]` абстрагується над функцією, що приймає _аргумент типу_ на додачу до аргументів значень.
+
+- **Лямбда типу**. Те, що виражалося з використанням [плагіна компілятора](https://github.com/typelevel/kind-projector) в Scala 2 тепер є першокласною особливістю в Scala 3: Лямбда типу — це функції рівня типів, які можна передавати як аргументи типу (вищого роду) без визначення допоміжного типу.
+
+- **Відповідність типів**. Замість того, щоб кодувати обчислення на рівні типу з використанням імплісітів, Scala 3 пропонує пряму підтримку [відповідності за типами][types-match]. Інтеграція обчислень на рівні типів у процес перевірки типів дозволяє покращити повідомлення про помилки та усуває необхідність у складному кодуванні.
+
+
+### Переосмислено: об'єктно-орієнтоване програмування
+Scala завжди була на межі між функціональним програмуванням та об'єктноорієнтованим програмуванням -- і Scala 3 розширює межі в обох напрямках!
+Вищезгадані зміни в системі типів і перероблення контекстних абстракцій роблять _функціональне програмування_ легшим, ніж раніше.
+Водночас наступні нові функції дозволяють добре структурувати _об'єктноорієнтовані проєкти_ та підтримують найкращі практики.
+
+- **Pass it on**. Трейти наближаються до класів і тепер також можуть приймати [параметри][oo-trait-parameters], що робить їх ще більш потужними як інструмент для модульної декомпозиції.
+- **План розширення**. Класи розширення, які не призначені для наслідування, є давньою проблемою в об'єктноорієнтованому програмуванні. Для розв'язання цього питання, [відкриті класи][oo-open] вимагають у розробників бібліотек _явно_ позначити класи як відкриті.
+- **Приховати деталі реалізації**. Утилітні трейти, які іноді реалізують поведінку, не повинні входити до складу виведених типів. У Scala 3, такі трейти можуть бути позначені як [прозорі][oo-transparent] приховуючи наслідування від користувача (у виведених типах).
+- **Композиція понад спадковістю**. Це поняття широко згадується, але є важким у реалізації. Але не з [export][oo-export] у Scala 3's: симетричні до імпорту, експорти дозволяють користувачеві визначати псевдоніми для вибраних членів об'єкта.
+- **Більше без NPE**. Scala 3 безпечніша, ніж будь-коли: [явний null][oo-explicit-null] виводить `null` з ієрархії типів, допомагаючи статично виловлювати помилки; додаткові перевірки для [безпечної ініціалізації][oo-safe-init] виявляють доступ до неініціалізованих об'єктів.
+
+
+### Батарейки в комплекті: метапрограмування
+Хоча макроси в Scala 2 були лише експериментальною функцією, Scala 3 поставляється з потужним арсеналом інструментів для метапрограмування.
+[Посібник по макросах]({% link _overviews/scala3-macros/tutorial/index.md %}) містить детальну інформацію про різні об'єкти. Зокрема, Scala 3 пропонує наступні можливості для метапрограмування:
+
+- **Inline**. Як відправна точка, [inline][meta-inline] дозволяє редукувати значення та методи під час компіляції. Ця проста функція вже охоплює багато варіантів використання і в той же час є точкою входу для більш розширених функцій.
+- **Операції під час компіляції**. Пакет [`scala.compiletime`][meta-compiletime] містить додаткову функціональність, яку можна використовувати для реалізації вбудованих методів.
+- **Цитування блоків коду**. Scala 3 додає нову можливість [квазі-цитування][meta-quotes] коду, що надає зручний інтерфейс високого рівня для побудови та аналізу коду. Побудувати код для додавання одиниці до одиниці так само просто, як і `'{ 1 + 1 }`.
+- **API рефлексії**. Для більш просунутих випадків використання [quotes.reflect][meta-reflection] забезпечує більш детальний контроль для перевірки та створення дерев програм.
+
+Якщо ви хочете дізнатися більше про метапрограмування в Scala 3, пропонуємо подивитись на наш [посібник][meta-tutorial].
+
+
+[enums]: {{ site.scala3ref }}/enums/enums.html
+[enums-adts]: {{ site.scala3ref }}/enums/adts.html
+
+[types-intersection]: {{ site.scala3ref }}/new-types/intersection-types.html
+[types-union]: {{ site.scala3ref }}/new-types/union-types.html
+[types-dependent]: {{ site.scala3ref }}/new-types/dependent-function-types.html
+[types-lambdas]: {{ site.scala3ref }}/new-types/type-lambdas.html
+[types-polymorphic]: {{ site.scala3ref }}/new-types/polymorphic-function-types.html
+[types-match]: {{ site.scala3ref }}/new-types/match-types.html
+[types-opaque]: {{ site.scala3ref }}/other-new-features/opaques.html
+
+[type-inference]: {{ site.scala3ref }}/changed-features/type-inference.html
+[overload-resolution]: {{ site.scala3ref }}/changed-features/overload-resolution.html
+[reference]: {{ site.scala3ref }}/overview.html
+[creator]: {{ site.scala3ref }}/other-new-features/creator-applications.html
+[migration]: {% link _overviews/scala3-migration/compatibility-intro.md %}
+[contribution]: {% link _overviews/scala3-contribution/contribution-intro.md %}
+
+[implicits]: {{ site.scala3ref }}/contextual
+[contextual-using]: {{ site.scala3ref }}/contextual/using-clauses.html
+[contextual-givens]: {{ site.scala3ref }}/contextual/givens.html
+[contextual-extension]: {{ site.scala3ref }}/contextual/extension-methods.html
+[contextual-conversions]: {{ site.scala3ref }}/contextual/conversions.html
+[contextual-functions]: {{ site.scala3ref }}/contextual/context-functions.html
+
+[syntax-summary]: {{ site.scala3ref }}/syntax.html
+[syntax-control]: {{ site.scala3ref }}/other-new-features/control-syntax.html
+[syntax-indentation]: {{ site.scala3ref }}/other-new-features/indentation.html
+[syntax-wildcard]: {{ site.scala3ref }}/changed-features/wildcards.html
+
+[meta-tutorial]: {% link _overviews/scala3-macros/tutorial/index.md %}
+[meta-inline]: {% link _overviews/scala3-macros/tutorial/inline.md %}
+[meta-compiletime]: {% link _overviews/scala3-macros/tutorial/compiletime.md %}
+[meta-quotes]: {% link _overviews/scala3-macros/tutorial/quotes.md %}
+[meta-reflection]: {% link _overviews/scala3-macros/tutorial/reflection.md %}
+
+[oo-explicit-null]: {{ site.scala3ref }}/experimental/explicit-nulls.html
+[oo-safe-init]: {{ site.scala3ref }}/other-new-features/safe-initialization.html
+[oo-trait-parameters]: {{ site.scala3ref }}/other-new-features/trait-parameters.html
+[oo-open]: {{ site.scala3ref }}/other-new-features/open-classes.html
+[oo-transparent]: {{ site.scala3ref }}/other-new-features/transparent-traits.html
+[oo-export]: {{ site.scala3ref }}/other-new-features/export.html
diff --git a/_uk/scala3/scaladoc.md b/_uk/scala3/scaladoc.md
new file mode 100644
index 0000000000..66a6d12805
--- /dev/null
+++ b/_uk/scala3/scaladoc.md
@@ -0,0 +1,89 @@
+---
+layout: singlepage-overview
+title: Нові можливості в Scaladoc
+partof: scala3-scaladoc
+language: uk
+scala3: true
+---
+
+Нова версія Scala 3 поставляється з абсолютно новою реалізацією генератора документації _Scaladoc_, переписаною з нуля.
+У цій статті ви можете знайти огляд нових функцій, які є або будуть представлені в Scaladoc.
+Для загальної довідки відвідайте [посібник Scaladoc]({% link _overviews/scala3-scaladoc/index.md %}).
+
+## Нові можливості
+
+### Синтаксис Markdown
+
+Найбільшою зміною, внесеною в нову версію Scaladoc, є зміна мови за замовчуванням для docstrings. Поки що Scaladoc підтримував лише синтаксис Wikidoc.
+Новий Scaladoc все ще може аналізувати застарілий синтаксис `Wikidoc`, однак Markdown вибрано як основну мову для форматування коментарів.
+Щоб повернутися до `Wikidoc`, можна передати глобальний прапор перед запуском `doc` або визначити його для конкретних коментарів за допомогою директиви `@syntax wiki`.
+
+Щоб отримати додаткову інформацію про те, як використовувати повну силу документації, перегляньте [Scaladoc docstrings][scaladoc-docstrings]
+
+
+### Статичні вебсайти
+
+Scaladoc також забезпечує простий спосіб створення **статичних сайтів** як для документації, так і для публікацій у блозі, подібно до того, як це робить Jekyll.
+Завдяки цій функції ви можете зберігати свою документацію разом зі згенерованим API Scaladoc дуже зручним способом.
+
+Щоб отримати додаткову інформацію про те, як налаштувати генерацію статичних сайтів, перегляньте абзац [Статична документація][static-documentation]
+
+
+
+### Публікації в блозі
+
+Дописи в блозі – це особливий тип статичних сайтів. У посібнику Scaladoc ви можете знайти додаткову інформацію про те, як працювати з [публікаціями в блозі][built-in-blog].
+
+
+
+### Посилання на соціальні мережі
+
+Крім того, Scaladoc надає простий спосіб налаштувати [посилання на соціальні мережі][social-links], наприклад Twitter чи Discord.
+
+{: style="width: 180px"}
+
+## Експериментальні особливості
+
+На поточний час (травень 2021 р.) перелічені нижче функції не можуть бути випущені разом із Scaladoc, однак ми будемо раді почути ваші відгуки.
+Кожна функція має власний розділ на сайті учасників scala-lang, де ви можете поділитися своїми думками.
+
+### Компіляція фрагментів
+
+Одним з експериментальних особливостей Scaladoc є компілятор фрагментів (snippets compiler).
+Цей інструмент дозволить вам компілювати фрагменти, які ви додаєте до docstring, щоб перевірити, чи вони насправді поводяться належним чином.
+Ця функція дуже схожа на інструменти `tut` або `mdoc`, але буде поставлятися разом із Scaladoc для легкого налаштування та інтеграції у ваш проєкт.
+Зробити фрагменти інтерактивними, наприклад, дозволити користувачам редагувати та компілювати їх у браузері, наразі розглядається.
+
+Вітрина:
+* Приховування коду 
+* Виявлення помилок компіляції 
+* Включення фрагментів 
+
+Для більш детальної інформації дивіться [Посібники](/scala3/guides/scaladoc/snippet-compiler.html), або перейдіть у [тред Scala Contributors](https://contributors.scala-lang.org/t/snippet-validation-in-scaladoc-for-scala-3/4976)
+
+### Пошук, оснований на типах
+
+Пошук функцій за їх символьними назвами може зайняти багато часу.
+Саме тому новий Scaladoc дозволяє шукати методи та поля за їх типами.
+
+Тому для декларації:
+```
+extension [T](arr: IArray[T]) def span(p: T => Boolean): (IArray[T], IArray[T]) = ...
+```
+Замість того, щоб шукати `span`, ми можемо шукати `IArray[A] => (A => Boolean) => (IArray[A], IArray[A])`.
+
+Щоб скористатися цією функцією, просто введіть підпис функції, яку ви шукаєте, на панелі пошуку scaladoc. Ось як це працює:
+
+
+
+Ця функція забезпечується пошуковою системою [Inkuire](https://github.com/VirtusLab/Inkuire), яка працює для Scala 3 і Kotlin. Щоб бути в курсі розвитку цього інструменту, підпишіться на оновлення [репозиторію Inkuire](https://github.com/VirtusLab/Inkuire).
+
+Для отримання додаткової інформації дивіться [Посібники](/scala3/guides/scaladoc/search-engine.html)
+
+Зауважте, що ця функція все ще знаходиться на стадії розробки, тому вона може зазнати значних змін.
+Якщо ви зіткнулися з помилкою або маєте ідею щодо покращення, не соромтеся створювати проблему на [Inkuire](https://github.com/VirtusLab/Inkuire/issues/new) або [dotty](https://github.com/scala/scala3/issues/new).
+
+[scaladoc-docstrings]: {% link _overviews/scala3-scaladoc/docstrings.md %}
+[static-documentation]: {% link _overviews/scala3-scaladoc/static-site.md %}
+[built-in-blog]: {% link _overviews/scala3-scaladoc/blog.md %}
+[social-links]: {% link _overviews/scala3-scaladoc/settings.md %}#-social-links
diff --git a/_uk/scala3/talks.md b/_uk/scala3/talks.md
new file mode 100644
index 0000000000..01087ab671
--- /dev/null
+++ b/_uk/scala3/talks.md
@@ -0,0 +1,90 @@
+---
+layout: singlepage-overview
+title: Розмови
+partof: scala3-talks
+language: uk
+scala3: true
+versionSpecific: true
+---
+
+Серія "Поговорімо про Scala 3"
+-------------------------------
+
+[Поговорімо про Scala 3](https://www.youtube.com/playlist?list=PLTx-VKTe8yLxYQfX_eGHCxaTuWvvG28Ml) є серією
+коротких (близько 15 хвилин) розмов про Scala 3. Він охоплює різноманітні теми, наприклад, як почати, як застосувати
+переваги нових функцій мови, або як перейти з Scala 2.
+
+Talks on Scala 3
+----------------
+- (ScalaDays 2019, Lausanne) [Тур по Scala 3](https://www.youtube.com/watch?v=_Rnrx2lo9cw)
+ від [Martin Odersky](http://x.com/odersky)
+
+- (ScalaDays 2016, Berlin) [Попереду дорога Scala](https://www.youtube.com/watch?v=GHzWqJKFCk4)
+ від [Martin Odersky](http://x.com/odersky)
+ [\[слайди\]](http://www.slideshare.net/Odersky/scala-days-nyc-2016)
+
+- (JVMLS 2015) [Compilers are Databases](https://www.youtube.com/watch?v=WxyyJyB_Ssc)
+ від [Martin Odersky](http://x.com/odersky)
+ [\[слайди\]](http://www.slideshare.net/Odersky/compilers-are-databases)
+
+- (Scala World 2015) [Dotty: Досліджуємо майбутнє Scala](https://www.youtube.com/watch?v=aftdOFuVU1o)
+ від [Dmitry Petrashko](http://x.com/darkdimius)
+ [\[слайди\]](https://d-d.me/scalaworld2015/#/).
+ Розповідь Дмітрія охоплює багато нових функцій, які приносить Dotty, наприклад типи Intersection та Union, покращена ініціалізація lazy val тощо.
+ Дмітрій також розповідає внутрішню архітектуру Dotty і, зокрема, високий рівень контекстуальних абстракцій Dotty. Ви
+ ознайомитесь з багатьма базовими поняттями, такими як «Denotations» та їх особливостями.
+
+Deep Dive with Scala 3
+----------------------
+- (ScalaDays 2019, Lausanne) [Метапрограмування in Dotty](https://www.youtube.com/watch?v=ZfDS_gJyPTc)
+ від [Nicolas Stucki](https://github.com/nicolasstucki).
+
+- (ScalaDays 2019, Lausanne) [Future-proofing в Scala: проміжна репрезентація TASTY](https://www.youtube.com/watch?v=zQFjC3zLYwo)
+ від [[Guillaume Martres](http://guillaume.martres.me/)](http://guillaume.martres.me/).
+
+- (Mar 21, 2017) [Dotty Internals 1: Trees та Symbols](https://www.youtube.com/watch?v=yYd-zuDd3S8)
+ від [Dmitry Petrashko](http://x.com/darkdimius)
+ [\[meeting notes\]](https://dotty.epfl.ch/docs/internals/dotty-internals-1-notes.html).
+ Це запис зустрічі EPFL та Waterloo, де були представлені перші нотатки про Dotty: Trees та Symbols.
+
+- (Mar 21, 2017) [Dotty Internals 2: Types](https://www.youtube.com/watch?v=3gmLIYlGbKc)
+ від [Martin Odersky](http://x.com/odersky) та [Dmitry Petrashko](http://x.com/darkdimius).
+ Це запис зустрічі EPFL та Waterloo, де були представлено як представлені типи всередині Dotty.
+
+- (Jun 15, 2017) [Dotty Internals 3: Denotations](https://youtu.be/9iPA7zMRGKY)
+ від [Martin Odersky](http://x.com/odersky) та [Dmitry Petrashko](http://x.com/darkdimius).
+ Це запис зустрічі EPFL та Waterloo, де були представлена денотація в Dotty.
+
+- (JVM Language Summit) [Як зробити компілятор Dotty швидким](https://www.youtube.com/watch?v=9xYoSwnSPz0)
+ від [Dmitry Petrashko](http://x.com/darkdimius).
+ Дмітрій дає високорівневий вступ до того, що було зроблено для створення Dotty .
+
+- (Typelevel Summit Oslo, May 2016) [Dotty та типи: поки що історія](https://www.youtube.com/watch?v=YIQjfCKDR5A)
+ від [Guillaume Martres](http://guillaume.martres.me/)
+ [\[слайди\]](http://guillaume.martres.me/talks/typelevel-summit-oslo/).
+ Гійом зосередився на деяких практичних вдосконаленнях системи типів, які робить Dotty. Це новий алгоритм параметру типу,
+ який здатний робити висновки про безпеку типів для більшої кількості ситуацій ніж scalac.
+
+- (flatMap(Oslo) 2016) [AutoSpecialization в Dotty](https://vimeo.com/165928176)
+ від [Dmitry Petrashko](http://x.com/darkdimius)
+ [\[слайди\]](https://d-d.me/talks/flatmap2016/#/).
+ Компонувальник Dotty аналізує вашу програму та її залежності, щоб застосувати нову схему спеціалізації.
+ Віна ґрунтується на нашому досвіді з Specialization, Miniboxing та Valhalla Project,
+ і різко зменшує розмір байт-коду. І, що найкраще, це завжди ввімкнено, відбувається за кулісами без анотацій,
+ що призводить до прискорення понад 20 разів. Крім того, він «просто працює» на колекціях Scala.
+
+- (ScalaSphere 2016) [Hacking on Dotty: жива демонстрація](https://www.youtube.com/watch?v=0OOYGeZLHs4)
+ від [Guillaume Martres](http://guillaume.martres.me/)
+ [\[слайди\]](http://guillaume.martres.me/talks/dotty-live-demo/).
+ Прийоми Гійома для Dotty: демонстрація в реальному часі, під час якої він створює просту фазу компілятора для відстеження викликів методів під час виконання.
+
+- (Scala By the Bay 2016) [Dotty: що це і як працює](https://www.youtube.com/watch?v=wCFbYu7xEJA)
+ від [Guillaume Martres](http://guillaume.martres.me/)
+ [\[слайди\]](http://guillaume.martres.me/talks/dotty-tutorial/#/).
+ Гійом демонструє високорівневе представлення пайплайну компіляції в Dotty.
+
+- (ScalaDays 2015, Amsterdam) [Як зробити ваші програми на Scala меншими та швидшими за допомогою компонувальника Dotty](https://www.youtube.com/watch?v=xCeI1ArdXM4)
+ від [Dmitry Petrashko](http://x.com/darkdimius)
+ [\[слайди\]](https://d-d.me/scaladays2015/#/).
+ Дмитрій представляє алгоритм аналізу графу виклик у Dotty та переваги продуктивності, які ми можемо отримати з точки зору кількості методів,
+ розміру байт-коду, розміру коду JVM і кількість об'єктів, виділених в кінці.
diff --git a/_zh-cn/glossary/index.md b/_zh-cn/glossary/index.md
index dc82232e3f..055eff8026 100644
--- a/_zh-cn/glossary/index.md
+++ b/_zh-cn/glossary/index.md
@@ -16,381 +16,381 @@ language: zh-cn
-* [致谢名单](/zh-cn/overviews/thanks.html)
+
diff --git a/_zh-cn/overviews/parallel-collections/concrete-parallel-collections.md b/_zh-cn/overviews/parallel-collections/concrete-parallel-collections.md
index e73a131409..ea11bedf72 100644
--- a/_zh-cn/overviews/parallel-collections/concrete-parallel-collections.md
+++ b/_zh-cn/overviews/parallel-collections/concrete-parallel-collections.md
@@ -52,7 +52,7 @@ language: zh-cn
### 并行哈希表(Parallel Hash Tables)
-并行哈希表存储在底层数组的元素,并将它们放置在由各自元素的哈希码的位置。并行不变的哈希集(set)([mutable.ParHashSet](https://www.scala-lang.org/api/2.10.0/scala/collection/parallel/mutable/ParHashSet.html))和并行不变的哈希映射([mutable.ParHashMap](https://www.scala-lang.org/api/2.10.0/scala/collection/parallel/mutable/ParHashMap.html)) 是基于哈希表的。
+并行哈希表存储在底层数组的元素,并将它们放置在由各自元素的哈希码的位置。并行不变的哈希集(set)([mutable.ParHashSet](https://www.scala-lang.org/api/{{ site.scala-212-version}}/scala/collection/parallel/mutable/ParHashSet.html))和并行不变的哈希映射([mutable.ParHashMap](https://www.scala-lang.org/api/{{ site.scala-212-version}}/scala/collection/parallel/mutable/ParHashMap.html)) 是基于哈希表的。
scala> val phs = scala.collection.parallel.mutable.ParHashSet(1 until 2000: _*)
phs: scala.collection.parallel.mutable.ParHashSet[Int] = ParHashSet(18, 327, 736, 1045, 773, 1082,...
@@ -66,7 +66,7 @@ language: zh-cn
### 并行散列Tries(Parallel Hash Tries)
-并行hash tries是不可变(immutable)hash tries的并行版本,这种结果可以用来高效的维护不可变集合(immutable set)和不可变关联数组(immutable map)。他们都支持类[immutable.ParHashSet](https://www.scala-lang.org/api/2.10.0/scala/collection/parallel/immutable/ParHashSet.html)和[immutable.ParHashMap](https://www.scala-lang.org/api/2.10.0/scala/collection/parallel/immutable/ParHashMap.html)。
+并行hash tries是不可变(immutable)hash tries的并行版本,这种结果可以用来高效的维护不可变集合(immutable set)和不可变关联数组(immutable map)。他们都支持类[immutable.ParHashSet](https://www.scala-lang.org/api/{{ site.scala-212-version}}/scala/collection/parallel/immutable/ParHashSet.html)和[immutable.ParHashMap](https://www.scala-lang.org/api/{{ site.scala-212-version}}/scala/collection/parallel/immutable/ParHashMap.html)。
scala> val phs = scala.collection.parallel.immutable.ParHashSet(1 until 1000: _*)
phs: scala.collection.parallel.immutable.ParHashSet[Int] = ParSet(645, 892, 69, 809, 629, 365, 138, 760, 101, 479,...
@@ -80,7 +80,7 @@ language: zh-cn
### 并行并发tries(Parallel Concurrent Tries)
-[ concurrent.triemap ](https://www.scala-lang.org/api/2.10.0/scala/collection/concurrent/TrieMap.html)是竞争对手的线程安全的地图,而[ mutable.partriemap ](https://www.scala-lang.org/api/2.10.0/scala/collection/parallel/mutable/ParTrieMap.html) 是他的并行副本。如果这个数据结构在遍历的过程中被修改了,大多数竞争对手的数据结构不能确保一致遍历,尝试确保在下一次迭代中更新是可见的。这意味着,你可以在尝试遍历的时候改变这些一致性,如下例子所示输出1到99的平方根。
+[ concurrent.triemap ](https://www.scala-lang.org/api/{{ site.scala-212-version}}/scala/collection/concurrent/TrieMap.html)是竞争对手的线程安全的地图,而[ mutable.partriemap ](https://www.scala-lang.org/api/{{ site.scala-212-version}}/scala/collection/parallel/mutable/ParTrieMap.html) 是他的并行副本。如果这个数据结构在遍历的过程中被修改了,大多数竞争对手的数据结构不能确保一致遍历,尝试确保在下一次迭代中更新是可见的。这意味着,你可以在尝试遍历的时候改变这些一致性,如下例子所示输出1到99的平方根。
scala> val numbers = scala.collection.parallel.mutable.ParTrieMap((1 until 100) zip (1 until 100): _*) map { case (k, v) => (k.toDouble, v.toDouble) }
numbers: scala.collection.parallel.mutable.ParTrieMap[Double,Double] = ParTrieMap(0.0 -> 0.0, 42.0 -> 42.0, 70.0 -> 70.0, 2.0 -> 2.0,...
diff --git a/_zh-cn/overviews/reflection/.jekyll-metadata b/_zh-cn/overviews/reflection/.jekyll-metadata
new file mode 100644
index 0000000000..72fc01387f
Binary files /dev/null and b/_zh-cn/overviews/reflection/.jekyll-metadata differ
diff --git a/_zh-cn/overviews/reflection/environment-universes-mirrors.md b/_zh-cn/overviews/reflection/environment-universes-mirrors.md
new file mode 100644
index 0000000000..a42d247154
--- /dev/null
+++ b/_zh-cn/overviews/reflection/environment-universes-mirrors.md
@@ -0,0 +1,178 @@
+---
+layout: multipage-overview
+title: Environment, Universes, and Mirrors
+partof: reflection
+overview-name: Reflection
+
+num: 2
+language: zh-cn
+---
+
+EXPERIMENTAL
+
+## Environment
+
+反射环境根据反射工作是在运行时还是在编译时完成而有所不同。在运行时和编译时使用的环境之间的区别被封装在一个所谓的 *宇宙(universe)* 中。
+反射环境的另一个重要方面是我们可以反射的访问一组实体。这组实体由所谓的 *镜像(mirror)* 决定。
+
+例如,可通过运行时反射访问的实体由`ClassloaderMirror`提供。该镜像仅提供对由特定类加载器加载的实体(包,类型和成员)的访问。
+
+镜像不仅可以确定反射访问的实体集。它们还提供对这些实体执行的反射操作。例如,在运行时反射中,可以使用*调用者镜像*(invoker mirror)来调用类的方法或构造函数。
+
+## Universes
+
+宇宙有两种主要类型 - 由于同时具有运行时和编译时反射功能,一个人必须使用与即将完成的工作相对应的宇宙。二者之一:
+
+- `scala.reflect.runtime.universe` 用于 **运行时反射**,或者
+- `scala.reflect.macros.Universe` 用于 **编译时反射**。
+
+一个宇宙提供了反射中使用的所有主要概念的接口,例如类型(`Types`),树(`Trees`)和注解(`Annotations`)。
+
+## Mirrors
+
+反射提供的所有信息都可以通过*镜像*访问。根据要获得的信息类型或要采取的反射动作,必须使用不同类型的镜像。*类加载器镜像*可用于获取类型和成员的表示。
+从类加载器镜像中,可以获得更专门的*调用者*镜像(最常用的镜像),这些镜像实现了反射调用,例如方法或构造函数调用以及字段访问。
+
+总结:
+
+- **"类加载器" 镜像**。这些镜像将名称转换为符号 (通过方法 `staticClass`/`staticModule`/`staticPackage`)。
+
+- **"调用者" 镜像**。这些镜像实现反射调用(通过方法 `MethodMirror.apply`,`FieldMirror.get`,等等。)。这些"调用者"镜像是最常用的镜像类型。
+
+### Runtime Mirrors
+
+在运行时使用的镜像的入口点是通过`ru.runtimeMirror()`,其中`ru`是`scala.reflect.runtime.universe`。
+
+一个`scala.reflect.api.JavaMirrors#runtimeMirror`的调用结果是一个类型为`scala.reflect.api.Mirrors#ReflectiveMirror`的类加载器镜像,它可以按名称加载符号。
+
+一个类加载器镜像可以创建多个调用者镜像(包括`scala.reflect.api.Mirrors#InstanceMirror`,`scala.reflect.api.Mirrors#MethodMirror`,`scala.reflect.api.Mirrors#FieldMirror`,`scala.reflect.api.Mirrors#ClassMirror`,和`scala.reflect.api.Mirrors#ModuleMirror`)。
+
+下面提供了这两种类型的反射镜像如何相互作用的示例。
+
+### Types of Mirrors, Their Use Cases & Examples
+
+`ReflectiveMirror`用于按名称加载符号,并用作调用者镜像的入口。入口点:`val m = ru.runtimeMirror()`。例如:
+
+ scala> val ru = scala.reflect.runtime.universe
+ ru: scala.reflect.api.JavaUniverse = ...
+
+ scala> val m = ru.runtimeMirror(getClass.getClassLoader)
+ m: scala.reflect.runtime.universe.Mirror = JavaMirror ...
+
+`InstanceMirror`用于为方法和字段以及内部类和内部对象(模块)创建调用者镜像。入口点:`val im = m.reflect()`。例如:
+
+ scala> class C { def x = 2 }
+ defined class C
+
+ scala> val im = m.reflect(new C)
+ im: scala.reflect.runtime.universe.InstanceMirror = instance mirror for C@3442299e
+
+`MethodMirror`用于调用实例方法(Scala仅具有实例方法-对象的方法是对象实例的实例方法,可通过`ModuleMirror.instance`获得)。入口点:`val mm = im.reflectMethod()`)。例如:
+
+ scala> val methodX = ru.typeOf[C].decl(ru.TermName("x")).asMethod
+ methodX: scala.reflect.runtime.universe.MethodSymbol = method x
+
+ scala> val mm = im.reflectMethod(methodX)
+ mm: scala.reflect.runtime.universe.MethodMirror = method mirror for C.x: scala.Int (bound to C@3442299e)
+
+ scala> mm()
+ res0: Any = 2
+
+`FieldMirror`用于获取/设置实例字段(与方法类似,Scala仅具有实例字段,请参见上文)。入口点:`val fm = im.reflectField()`。例如:
+
+ scala> class C { val x = 2; var y = 3 }
+ defined class C
+
+ scala> val m = ru.runtimeMirror(getClass.getClassLoader)
+ m: scala.reflect.runtime.universe.Mirror = JavaMirror ...
+
+ scala> val im = m.reflect(new C)
+ im: scala.reflect.runtime.universe.InstanceMirror = instance mirror for C@5f0c8ac1
+
+ scala> val fieldX = ru.typeOf[C].decl(ru.TermName("x")).asTerm.accessed.asTerm
+ fieldX: scala.reflect.runtime.universe.TermSymbol = value x
+
+ scala> val fmX = im.reflectField(fieldX)
+ fmX: scala.reflect.runtime.universe.FieldMirror = field mirror for C.x (bound to C@5f0c8ac1)
+
+ scala> fmX.get
+ res0: Any = 2
+
+ scala> fmX.set(3)
+
+ scala> val fieldY = ru.typeOf[C].decl(ru.TermName("y")).asTerm.accessed.asTerm
+ fieldY: scala.reflect.runtime.universe.TermSymbol = variable y
+
+ scala> val fmY = im.reflectField(fieldY)
+ fmY: scala.reflect.runtime.universe.FieldMirror = field mirror for C.y (bound to C@5f0c8ac1)
+
+ scala> fmY.get
+ res1: Any = 3
+
+ scala> fmY.set(4)
+
+ scala> fmY.get
+ res2: Any = 4
+
+`ClassMirror`用于为构造函数创建调用者镜像。入口点:对于静态类`val cm1 = m.reflectClass()`,对于内部类`val mm2 = im.reflectClass()`。例如:
+
+ scala> case class C(x: Int)
+ defined class C
+
+ scala> val m = ru.runtimeMirror(getClass.getClassLoader)
+ m: scala.reflect.runtime.universe.Mirror = JavaMirror ...
+
+ scala> val classC = ru.typeOf[C].typeSymbol.asClass
+ classC: scala.reflect.runtime.universe.Symbol = class C
+
+ scala> val cm = m.reflectClass(classC)
+ cm: scala.reflect.runtime.universe.ClassMirror = class mirror for C (bound to null)
+
+ scala> val ctorC = ru.typeOf[C].decl(ru.termNames.CONSTRUCTOR).asMethod
+ ctorC: scala.reflect.runtime.universe.MethodSymbol = constructor C
+
+ scala> val ctorm = cm.reflectConstructor(ctorC)
+ ctorm: scala.reflect.runtime.universe.MethodMirror = constructor mirror for C.(x: scala.Int): C (bound to null)
+
+ scala> ctorm(2)
+ res0: Any = C(2)
+
+`ModuleMirror`用于访问单例对象的实例。入口点:对于静态对象`val mm1 = m.reflectModule()`,对于内部对象`val mm2 = im.reflectModule()`。例如:
+
+ scala> object C { def x = 2 }
+ defined module C
+
+ scala> val m = ru.runtimeMirror(getClass.getClassLoader)
+ m: scala.reflect.runtime.universe.Mirror = JavaMirror ...
+
+ scala> val objectC = ru.typeOf[C.type].termSymbol.asModule
+ objectC: scala.reflect.runtime.universe.ModuleSymbol = object C
+
+ scala> val mm = m.reflectModule(objectC)
+ mm: scala.reflect.runtime.universe.ModuleMirror = module mirror for C (bound to null)
+
+ scala> val obj = mm.instance
+ obj: Any = C$@1005ec04
+
+### Compile-Time Mirrors
+
+编译时镜像仅使用类加载器镜像来按名称加载符号。
+
+类加载器镜像的入口点通过`scala.reflect.macros.Context#mirror`。使用类加载器镜像的典型方法包括`scala.reflect.api.Mirror#staticClass`,`scala.reflect.api.Mirror#staticModule`和`scala.reflect.api.Mirror#staticPackage`。例如:
+
+ import scala.reflect.macros.Context
+
+ case class Location(filename: String, line: Int, column: Int)
+
+ object Macros {
+ def currentLocation: Location = macro impl
+
+ def impl(c: Context): c.Expr[Location] = {
+ import c.universe._
+ val pos = c.macroApplication.pos
+ val clsLocation = c.mirror.staticModule("Location") // get symbol of "Location" object
+ c.Expr(Apply(Ident(clsLocation), List(Literal(Constant(pos.source.path)), Literal(Constant(pos.line)), Literal(Constant(pos.column)))))
+ }
+ }
+
+注意:有几种高级替代方法,可以避免必须手动查找符号。例如,`typeOf[Location.type].termSymbol`(如果需要`ClassSymbol`,则为`typeOf[Location].typeSymbol`),因为我们不必使用字符串来查找符号,所以它们是类型安全的。
\ No newline at end of file
diff --git a/_zh-cn/overviews/reflection/overview.md b/_zh-cn/overviews/reflection/overview.md
index 02adf8ecc2..25f54810e9 100644
--- a/_zh-cn/overviews/reflection/overview.md
+++ b/_zh-cn/overviews/reflection/overview.md
@@ -85,7 +85,7 @@ decls: Iterable[ru.Symbol] = List(constructor List, method companion, method isE
#### 1.1.2 运行时实例化一个类型
-通过反射获得的类型,可以通过使用适当的“调用器”镜像调用它们的构造函数来实例化(镜像`mirros`的概念在[后续文档中说明](https://docs.scala-lang.org/overviews/reflection/overview.html#mirrors))。
+通过反射获得的类型,可以通过使用适当的“调用器”镜像调用它们的构造函数来实例化(镜像`mirrors`的概念在[后续文档中说明](https://docs.scala-lang.org/overviews/reflection/overview.html#mirrors))。
让我们通过一个REPL的示例说明:
@@ -269,7 +269,7 @@ Scala反射实现了允许在编译阶段就对程序进行修改的一种元编
这个反射环境根据是在运行时环境完成反射任务还是在编译时环境完成反射任务而有所区别。
这个区别被封装于所谓的`universe`中。
反射环境的另一个重要方面就是我们可以访问想反射的那组实体,
-这组实体由所谓的镜像`mirros`去确定。
+这组实体由所谓的镜像`mirrors`去确定。
镜像不仅决定反射化操作有哪些实体要被访问到,而且它还提供了反射操作去执行那些实体。
比如在运行时反射过程中可以调用镜像去操作类中一个方法或构造器。
@@ -279,7 +279,7 @@ Scala反射实现了允许在编译阶段就对程序进行修改的一种元编
`Universe`是Scala反射的切入点。
`universe`提供了使用反射所关联的很多核心概念,比如`Types`,`Trees`,以及`Annotations`。
-更多细节请参阅指南中[Universes](https://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html)部分,或者看`scala.reflect.api`包的[Universes API文档](https://www.scala-lang.org/api/current/scala-reflect/scala/reflect/api/Universe.html)。
+更多细节请参阅指南中[Universes](https://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html)部分,或者看`scala.reflect.api`包的[Universes API文档](https://www.scala-lang.org/api/2.x/scala-reflect/scala/reflect/api/Universe.html)。
本指南中提供了大多数情况下Scala反射要用到的部分,一般在使用运行时反射的场景下,直接导入所有`universe`成员去用即可:
@@ -293,4 +293,4 @@ import scala.reflect.runtime.universe._
反射所能提供的信息都是通过镜像去访问的。
根据不同的类型信息或不同的反射操作,必须要使用不同类型的镜像。
-更多细节请参阅指南中[Mirros](https://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html)部分,或者看`scala.reflect.api`包的[Mirrors API文档](https://www.scala-lang.org/api/current/scala-reflect/scala/reflect/api/Mirrors.html)。
+更多细节请参阅指南中[Mirrors](https://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html)部分,或者看`scala.reflect.api`包的[Mirrors API文档](https://www.scala-lang.org/api/2.x/scala-reflect/scala/reflect/api/Mirrors.html)。
diff --git a/_zh-cn/overviews/reflection/thread-safety.md b/_zh-cn/overviews/reflection/thread-safety.md
new file mode 100644
index 0000000000..e601c8e7e8
--- /dev/null
+++ b/_zh-cn/overviews/reflection/thread-safety.md
@@ -0,0 +1,47 @@
+---
+layout: multipage-overview
+title: 线程安全
+partof: reflection
+overview-name: Reflection
+
+num: 6
+language: zh-cn
+---
+
+EXPERIMENTAL
+
+**Eugene Burmako**
+
+遗憾的是,在scala2.10.0发布的现行状态下,反射不是线程安全的。
+这里有个JIRA问题 [SI-6240](https://issues.scala-lang.org/browse/SI-6240),它可以用来跟踪我们的进度和查找技术细节,下面是最新技术的简要总结。
+
+
NEWThread safety issues have been fixed in Scala 2.11.0-RC1, but we are going to keep this document available for now, since the problem still remains in the Scala 2.10.x series, and we currently don't have concrete plans on when the fix is going to be backported.
+
+目前,在反射相关方面存在两种竞争状态。 第一是反射的初始化(当调用代码首次访问`scala.reflect.runtime.universe`时)无法从多个线程安全地调用。第二是符号的初始化(当调用代码第一次访问符号的标记或类型签名时)也不安全。
+这是一个典型的表现:
+
+ java.lang.NullPointerException:
+ at s.r.i.Types$TypeRef.computeHashCode(Types.scala:2332)
+ at s.r.i.Types$UniqueType.(Types.scala:1274)
+ at s.r.i.Types$TypeRef.(Types.scala:2315)
+ at s.r.i.Types$NoArgsTypeRef.(Types.scala:2107)
+ at s.r.i.Types$ModuleTypeRef.(Types.scala:2078)
+ at s.r.i.Types$PackageTypeRef.(Types.scala:2095)
+ at s.r.i.Types$TypeRef$.apply(Types.scala:2516)
+ at s.r.i.Types$class.typeRef(Types.scala:3577)
+ at s.r.i.SymbolTable.typeRef(SymbolTable.scala:13)
+ at s.r.i.Symbols$TypeSymbol.newTypeRef(Symbols.scala:2754)
+
+好消息是,编译时反射(通过`scala.reflect.macros.Context`暴露给宏的那一种)比运行时反射(通过`scala.reflect.runtime.universe`暴露出的那一种)更不容易受到线程问题的影响。
+第一个原因是,当宏有机会运行时,编译时反射`universe`已经初始化,这规避了我们的竞争条件1。第二个理由是至今为止没有编译程序本身就是线程安全,所以没有并行执行的工具。但是,如果您的宏产生了多个线程,则你仍应该小心。
+
+
+不过,对于运行时反射来说,情况要糟糕得多。首次初始化`scala.reflect.runtime.universe`时,称为反射初始化,而且这种初始化可以间接发生。
+此处最突出的示例是,调用带有`TypeTag`上下文边界的方法可能会带来问题,因为调用这种方法,Scala通常需要构造一个自动生成的类型标签,该标签需要创建一个类型,并需要初始化反射`universe`。
+这个结果是,如果不采取特殊措施,就无法在测试中可靠地调用基于`TypeTag`的方法,这是因为sbt等很多工具并行执行测试。
+
+汇总:
+* 如果您正在编写一个没有显式创建线程的宏那就没有问题。
+* 线程或参与者(actors)混在一起的运行时反射可能很危险。
+* 多个带有`TypeTag`上下文边界的线程调用方法可能导致不确定的结果。
+* 请查看 [SI-6240](https://issues.scala-lang.org/browse/SI-6240),以了解我们在此问题上的进展。
diff --git a/_zh-cn/overviews/reflection/typetags-manifests.md b/_zh-cn/overviews/reflection/typetags-manifests.md
new file mode 100644
index 0000000000..ab3f5d448c
--- /dev/null
+++ b/_zh-cn/overviews/reflection/typetags-manifests.md
@@ -0,0 +1,132 @@
+---
+layout: multipage-overview
+title: TypeTags 和 Manifests
+partof: reflection
+overview-name: Reflection
+
+num: 5
+language: zh-cn
+---
+
+与其他JVM语言一样,Scala的类型在运行时被擦除。这意味着,如果要检查某个实例的运行时类型,则可能无法访问Scala编译器在编译时可用的所有类型信息。
+
+如`scala.reflect.Manifest`,`TypeTags`可以看作是将编译时可用的所有类型信息携带到运行时的对象。
+例如,`TypeTag[T]`封装了某个编译时类型`T`的运行时类型表示。但是请注意,`TypeTag`应该被认为是对2.10之前的`Manifest`概念的更丰富的替代品,后者还与Scala反射完全集成。
+
+有三种不同类型的类型标记:
+
+1. `scala.reflect.api.TypeTags#TypeTag`。
+Scala类型的完整类型描述符。例如,`TypeTag[List[String]]`包含所有类型信息,在本例中是类型`scala.List[String]`。
+
+2. `scala.reflect.ClassTag`。
+Scala类型的部分类型描述符。例如,`ClassTag[List[String]]`只包含已擦除、关于类的类型信息,在本例中为`scala.collection.immutable.List`。`ClassTag`只提供对类型的运行时类的访问。其类似于`scala.reflect.ClassManifest`。
+
+3. `scala.reflect.api.TypeTags#WeakTypeTag`。
+抽象类型的类型描述符(参见下面相应的小节)。
+
+## 获取`TypeTag`
+
+与`Manifest`类似,`TypeTag`总是由编译器生成,可以通过三种方式获得。
+
+### 通过方法`typeTag`、`classTag`或`weakTypeTag`
+
+通过使用通过`Universe`提供的方法`typeTag`,就可以直接获得特定类型的`TypeTag`。
+
+例如,要获取表示`Int`的`TypeTag`,我们可以执行以下操作:
+
+ import scala.reflect.runtime.universe._
+ val tt = typeTag[Int]
+
+或者类似地,要获得表示`String`的`ClassTag`,我们可以执行以下操作:
+
+ import scala.reflect._
+ val ct = classTag[String]
+
+这些方法中的每个方法都为给定的类型参数`T`构造一个`TypeTag[T]`或`ClassTag[T]`。
+
+### 使用类型为`TypeTag[T]`、`ClassTag[T]`或`WeakTypeTag[T]`的隐式参数
+
+与`Manifest`一样,实际上可以 _请求_ 编译器生成`TypeTag`。这只需指定一个类型为`TypeTag[T]`的隐式 _证据_ 参数即可完成。如果编译器在隐式搜索期间找不到匹配的隐式值,它将自动生成一个`TypeTag[T]`。
+
+_注意_:这通常是通过在方法上使用隐式参数来实现的,并且只能在类上。
+
+例如,我们可以编写一个方法,它可以接受任意对象,并且使用`TypeTag`打印有关该对象的类型参数的信息:
+
+ import scala.reflect.runtime.universe._
+
+ def paramInfo[T](x: T)(implicit tag: TypeTag[T]): Unit = {
+ val targs = tag.tpe match { case TypeRef(_, _, args) => args }
+ println(s"type of $x has type arguments $targs")
+ }
+
+这里,我们在`T`上编写了一个参数化的泛型方法`paramInfo`,并提供了一个隐式参数`(implicit tag: TypeTag[T])`。
+那我们就可以使用`TypeTag`的方法`tpe`直接访问`tag`表示的类型(`type`类型)。
+
+然后,我们可以使用方法`paramInfo`,如下所示:
+
+ scala> paramInfo(42)
+ type of 42 has type arguments List()
+
+ scala> paramInfo(List(1, 2))
+ type of List(1, 2) has type arguments List(Int)
+
+### 使用类型参数的上下文绑定
+
+要实现与上述完全相同的效果,一种不太冗长的方法是在类型参数上使用上下文绑定。不需要提供单独的隐式参数,只需在类型参数列表中包含`TypeTag`,如下所示:
+
+ def myMethod[T: TypeTag] = ...
+
+给定上下文绑定的`[T: TypeTag]`,编译器只需生成类型为`TypeTag[T]`的隐式参数,这将重写方法以进行查找,就像上一节中使用隐式参数的示例一样。
+
+上面重写为使用上下文边界的示例如下:
+
+
+ import scala.reflect.runtime.universe._
+
+ def paramInfo[T: TypeTag](x: T): Unit = {
+ val targs = typeOf[T] match { case TypeRef(_, _, args) => args }
+ println(s"type of $x has type arguments $targs")
+ }
+
+ scala> paramInfo(42)
+ type of 42 has type arguments List()
+
+ scala> paramInfo(List(1, 2))
+ type of List(1, 2) has type arguments List(Int)
+
+## WeakTypeTags
+
+`WeakTypeTag[T]`泛化了`TypeTag`(意思是`TypeTag`是继承自`WeakTypeTag`的),`WeakTypeTag`与普通的`TypeTag`不同,
+
+其类型表示的组件可以是对类型参数或抽象类型的引用。但是,`WeakTypeTag[T]`试图尽可能的具体(意思是如果都存在则优先更加具体的类型(参数)),也就是说,如果类型标记可用于被引用的类型参数或抽象类型,则它们用于将具体类型嵌入到`WeakTypeTag[T]`中。
+
+继续上面的例子:
+
+ def weakParamInfo[T](x: T)(implicit tag: WeakTypeTag[T]): Unit = {
+ val targs = tag.tpe match { case TypeRef(_, _, args) => args }
+ println(s"type of $x has type arguments $targs")
+ }
+
+ scala> def foo[T] = weakParamInfo(List[T]())
+ foo: [T]=> Unit
+
+ scala> foo[Int]
+ type of List() has type arguments List(T)
+
+## TypeTags and Manifests
+
+`TypeTag`可以大致对应2.10之前的`scala.reflect.Manifest`、 虽然`scala.reflect.ClassTag`对应于`scala.reflect.ClassManifest`而`scala.reflect.api.TypeTags#TypeTag`主要对应于`scala.reflect.Manifest`,但其他2.10版之前的`Manifest`类型与2.10版的`Tag`类型没有直接对应关系。
+
+- **不支持scala.reflect.OptManifest。**
+这是因为`Tag`可以具体化任意类型,所以它们总是可用的。
+
+- **没有对应的scala.reflect.AnyValManifest。**
+取而代之的是,可以将其`Tag`与基本`Tag`之一(在相应的伴随对象中定义)进行比较,以找出其是否代表原始值类。此外,可以简单地使用`.tpe.typeSymbol.isPrimitiveValueClass`。
+
+- **无法替换Manifest伴随对象中定义的工厂方法。**
+取而代之的是,可以使用Java(用于类)和Scala(用于类型)提供的反射API生成相应的类型。
+
+- **不支持某些manifest操作(即`<:<`, `>:>`和`typeArguments`)。**
+取而代之的是,可以使用Java(用于类)和Scala(用于类型)提供的反射API。
+
+在Scala 2.10中,不建议使用`scala.reflect.ClassManifest`,而推荐使用`TypeTag`和`ClassTag`,并且计划在即将发布的版本中弃用`scala.reflect.Manifest`。因此,建议迁移任何基于`Manifest`的API以使用`Tag`。
diff --git a/_zh-cn/overviews/scala3-book/ca-context-bounds.md b/_zh-cn/overviews/scala3-book/ca-context-bounds.md
new file mode 100644
index 0000000000..9e9c84238c
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/ca-context-bounds.md
@@ -0,0 +1,114 @@
+---
+title: 上下文绑定
+type: section
+description: This page demonstrates Context Bounds in Scala 3.
+language: zh-cn
+num: 62
+previous-page: ca-context-parameters
+next-page: ca-given-imports
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+---
+
+
+在许多情况下,[上下文参数]({% link _overviews/scala3-book/ca-context-parameters.md %}#context-parameters) 的名称不必显式提及,因为它仅在编译器为其他上下文参数合成实参的时候用到。
+在这种情况下,您不必定义参数名称,只需提供参数类型即可。
+
+## 背景
+
+例如,假设一个 `maxElement` 方法返回一个集合里的最大值:
+
+{% tabs context-bounds-max-named-param class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+def maxElement[A](as: List[A])(implicit ord: Ord[A]): A =
+ as.reduceLeft(max(_, _)(ord))
+```
+{% endtab %}
+{% tab 'Scala 3' %}
+```scala
+def maxElement[A](as: List[A])(using ord: Ord[A]): A =
+ as.reduceLeft(max(_, _)(using ord))
+```
+{% endtab %}
+{% endtabs %}
+
+上面这个 `maxElement` 方法只接受一个类型为 `Ord[A]` 的 _上下文参数_ 并将其作为实参传给 `max` 方法。
+
+完整起见,以下是 `max` 和 `Ord` 的定义(注意,在实践中我们会使用 `List` 中已有的 `max` 方法 ,
+但我们为了说明目的而编造了这个例子):
+
+{% tabs context-bounds-max-ord class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+/** Defines how to compare values of type `A` */
+trait Ord[A] {
+ def greaterThan(a1: A, a2: A): Boolean
+}
+
+/** Returns the maximum of two values */
+def max[A](a1: A, a2: A)(implicit ord: Ord[A]): A =
+ if (ord.greaterThan(a1, a2)) a1 else a2
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+/** Defines how to compare values of type `A` */
+trait Ord[A]:
+ def greaterThan(a1: A, a2: A): Boolean
+
+/** Returns the maximum of two values */
+def max[A](a1: A, a2: A)(using ord: Ord[A]): A =
+ if ord.greaterThan(a1, a2) then a1 else a2
+```
+{% endtab %}
+{% endtabs %}
+
+`max` 方法用了类型为 `Ord[A]` 的上下文参数, 就像 `maxElement` 方法一样。
+
+## 省略上下文参数
+
+因为 `ord` 是 `max` 方法的上下文参数,当我们调用方法 `max` 时, 编译器可以在 `maxElement` 的实现中为我们提供它:
+
+{% tabs context-bounds-context class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+def maxElement[A](as: List[A])(implicit ord: Ord[A]): A =
+ as.reduceLeft(max(_, _))
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+def maxElement[A](as: List[A])(using Ord[A]): A =
+ as.reduceLeft(max(_, _))
+```
+
+注意,因为我们不用显示传递给 `max` 方法,我们可以在 `maxElement` 定义里不命名。
+这是 _匿名上下文参数_ 。
+{% endtab %}
+{% endtabs %}
+
+## 上下文绑定
+
+鉴于此背景,_上下文绑定_ 是一种简写语法,用于表达“依赖于类型参数的上下文参数”模式。
+
+使用上下文绑定,`maxElement` 方法可以这样写:
+
+{% tabs context-bounds-max-rewritten %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def maxElement[A: Ord](as: List[A]): A =
+ as.reduceLeft(max(_, _))
+```
+{% endtab %}
+{% endtabs %}
+
+方法或类的类型参数 `A`,有类似 `:Ord` 的绑定,它表示有 `Ord[A]` 的上下文参数。
+在后台,编译器将此语法转换为“背景”部分中显示的语法。
+
+有关上下文绑定的更多信息,请参阅 Scala 常见问题解答的 [“什么是上下文绑定?”](https://docs.scala-lang.org/tutorials/FAQ/context-bounds.html) 部分。
diff --git a/_zh-cn/overviews/scala3-book/ca-context-parameters.md b/_zh-cn/overviews/scala3-book/ca-context-parameters.md
new file mode 100644
index 0000000000..3742d36de1
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/ca-context-parameters.md
@@ -0,0 +1,152 @@
+---
+title: Given 实例和 Using 语句
+type: section
+description: This page demonstrates how to use 'given' instances and 'using' clauses in Scala 3.
+language: zh-cn
+num: 61
+previous-page: ca-extension-methods
+next-page: ca-context-bounds
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+---
+
+
+
+ class Person {
+ public String firstName;
+ public String lastName;
+ public int age;
+ public Person(
+ String firstName,
+ String lastName,
+ int age
+ ) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.age = age;
+ }
+ public String toString() {
+ return String.format("%s %s is %d years old.", firstName, lastName, age);
+ }
+ }
+
+
+
+
+ class Person (
+ var firstName: String,
+ var lastName: String,
+ var age: Int
+ ):
+ override def toString = s"$firstName $lastName is $age years old."
+
+
+
+
+
+
+### 辅助构造函数:
+
+
+
+
+
+ public class Person {
+ public String firstName;
+ public String lastName;
+ public int age;
+
+ // primary constructor
+ public Person(
+ String firstName,
+ String lastName,
+ int age
+ ) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.age = age;
+ }
+
+ // zero-arg constructor
+ public Person() {
+ this("", "", 0);
+ }
+
+ // one-arg constructor
+ public Person(String firstName) {
+ this(firstName, "", 0);
+ }
+
+ // two-arg constructor
+ public Person(
+ String firstName,
+ String lastName
+ ) {
+ this(firstName, lastName, 0);
+ }
+
+ }
+
+
+
+
+ class Person (
+ var firstName: String,
+ var lastName: String,
+ var age: Int
+ ):
+ // zero-arg auxiliary constructor
+ def this() = this("", "", 0)
+
+ // one-arg auxiliary constructor
+ def this(firstName: String) =
+ this(firstName, "", 0)
+
+ // two-arg auxiliary constructor
+ def this(
+ firstName: String,
+ lastName: String
+ ) =
+ this(firstName, lastName, 0)
+
+ end Person
+
+
+
+
+
+### 类默认是封闭的:
+“Plan for inheritance or else forbid it.”
+
+
+
+
+
+ final class Person
+
+
+
+
+ class Person
+
+
+
+
+
+### 为扩展开放的类:
+
+
+
+
+
+ class Person
+
+
+
+
+ open class Person
+
+
+
+
+
+### 单行方法:
+
+
+
+
+
+ public int add(int a, int b) {
+ return a + b;
+ }
+
+ public interface Adder {
+ public int add(int a, int b);
+ }
+
+
+
+
+ trait Adder:
+ def add(a: Int, b: Int): Int
+
+
+
+
+
+### 有实体方法的接口:
+
+
+
+
+
+ public interface Adder {
+ int add(int a, int b);
+ default int multiply(
+ int a, int b
+ ) {
+ return a * b;
+ }
+ }
+
+
+
+
+ trait Adder:
+ def add(a: Int, b: Int): Int
+ def multiply(a: Int, b: Int): Int =
+ a * b
+
+
+
+
+
+### 继承:
+
+
+
+
+
+ class Dog extends Animal implements HasLegs, HasTail
+
+
+
+
+ class Dog extends Animal, HasLegs, HasTail
+
+
+
+
+
+### 扩展多个接口
+
+这些接口和特征具有具体的、已实现的方法(默认方法):
+
+
+
+
+
+ interface Adder {
+ default int add(int a, int b) {
+ return a + b;
+ }
+ }
+
+ interface Multiplier {
+ default int multiply (
+ int a,
+ int b)
+ {
+ return a * b;
+ }
+ }
+
+ public class JavaMath implements Adder, Multiplier {}
+
+ JavaMath jm = new JavaMath();
+ jm.add(1,1);
+ jm.multiply(2,2);
+
+
+
+
+ trait Adder:
+ def add(a: Int, b: Int) = a + b
+
+ trait Multiplier:
+ def multiply(a: Int, b: Int) = a * b
+
+ class ScalaMath extends Adder, Multiplier
+
+ val sm = new ScalaMath
+ sm.add(1,1)
+ sm.multiply(2,2)
+
+
+
+
+
+### 混搭:
+
+
+
+
+
+ N/A
+
+
+
+
+ class DavidBanner
+
+ trait Angry:
+ def beAngry() =
+ println("You won’t like me ...")
+
+ trait Big:
+ println("I’m big")
+
+ trait Green:
+ println("I’m green")
+
+ // mix in the traits as DavidBanner
+ // is created
+ val hulk = new DavidBanner with Big with Angry with Green
+
+
+ // use single- or double-quotes
+ let msg = 'Hello, world';
+ let msg = "Hello, world";
+
+
+
+
+ // use only double-quotes
+ val msg = "Hello, world"
+
+
+
+
+
+### 插入
+
+
+
+
+
+ let name = 'Joe';
+
+ // JavaScript uses backticks
+ let msg = `Hello, ${name}`;
+
+
+
+
+ val name = "Joe"
+ val age = 42
+ val weight = 180.5
+
+ // use `s` before a string for simple interpolation
+ println(s"Hi, $name") // "Hi, Joe"
+ println(s"${1 + 1}") // "2"
+
+ // `f` before a string allows printf-style formatting.
+ // this example prints:
+ // "Joe is 42 years old, and weighs"
+ // "180.5 pounds."
+ println(f"$name is $age years old, and weighs $weight%.1f pounds.")
+
+
+
+
+
+### 带插入的多行字符串
+
+
+
+
+
+ let name = "joe";
+ let str = `
+ Hello, ${name}.
+ This is a multiline string.
+ `;
+
+
+
+
+
+ val name = "Martin Odersky"
+
+ val quote = s"""
+ |$name says
+ |Scala is a fusion of
+ |OOP and FP.
+ """.stripMargin.replaceAll("\n", " ").trim
+
+ // result:
+ // "Martin Odersky says Scala is a fusion of OOP and FP."
+
+
+ let d = new Date();
+ // result:
+ // Sun Nov 29 2020 18:47:57 GMT-0700 (Mountain Standard Time)
+
+
+
+
+
+ // different ways to get the current date and time
+ import java.time.*
+
+ val a = LocalDate.now
+ // 2020-11-29
+ val b = LocalTime.now
+ // 18:46:38.563737
+ val c = LocalDateTime.now
+ // 2020-11-29T18:46:38.563750
+ val d = Instant.now
+ // 2020-11-30T01:46:38.563759Z
+
+
+
+
+
+### 指定不同的日期:
+
+
+
+
+
+ let d = Date(2020, 1, 21, 1, 0, 0, 0);
+ let d = Date(2020, 1, 21, 1, 0, 0);
+ let d = Date(2020, 1, 21, 1, 0);
+ let d = Date(2020, 1, 21, 1);
+ let d = Date(2020, 1, 21);
+
+
+
+
+ val d = LocalDate.of(2020, 1, 21)
+ val d = LocalDate.of(2020, Month.JANUARY, 21)
+ val d = LocalDate.of(2020, 1, 1).plusDays(20)
+
+
+ // arrow function
+ let log = (s) => console.log(s)
+
+ // anonymous function
+ let log = function(s) {
+ console.log(s);
+ }
+
+ // use either of those functions here
+ function printA(a, log) {
+ log(a);
+ }
+
+
+
+
+ // a function (an anonymous function assigned to a variable)
+ val log = (s: String) => console.log(s)
+
+ // a scala method. methods tend to be used much more often,
+ // probably because they’re easier to read.
+ def log(a: Any) = console.log(a)
+
+ // a function or a method can be passed into another
+ // function or method
+ def printA(a: Any, f: log: Any => Unit) = log(a)
+
+
+
+
+
+
+在 Scala 中,您很少使用所示的第一种语法来定义函数。
+相反,您经常在使用点定义匿名函数。
+许多集合方法是 [高阶函数][hofs]并接受函数参数,因此您编写如下代码:
+
+```scala
+// map method, long form
+List(1,2,3).map(i => i * 10) // List(10,20,30)
+
+// map, short form (which is more commonly used)
+List(1,2,3).map(_ * 10) // List(10,20,30)
+
+// filter, short form
+List(1,2,3).filter(_ < 3) // List(1,2)
+
+// filter and then map
+List(1,2,3,4,5).filter(_ < 3).map(_ * 10) // List(10, 20)
+```
+
+## 类
+
+Scala 既有类也有样例类。
+_类_ 与 JavaScript 类相似,通常用于 [OOP 风格应用程序][modeling-oop](尽管它们也可以在 FP 代码中使用),并且 _样例类_有附加的特性,这让它在 [FP 风格应用][modeling-fp]中很有用。
+
+下面的例子展示了如何创建几个类型作为枚举,然后定义一个 OOP 风格的 `Pizza` 类。
+最后,创建并使用了一个 `Pizza` 实例:
+
+```scala
+// create some enumerations that the Pizza class will use
+enum CrustSize:
+ case Small, Medium, Large
+
+enum CrustType:
+ case Thin, Thick, Regular
+
+enum Topping:
+ case Cheese, Pepperoni, BlackOlives, GreenOlives, Onions
+
+// import those enumerations and the ArrayBuffer,
+// so the Pizza class can use them
+import CrustSize.*
+import CrustType.*
+import Topping.*
+import scala.collection.mutable.ArrayBuffer
+
+// define an OOP style Pizza class
+class Pizza(
+ var crustSize: CrustSize,
+ var crustType: CrustType
+):
+
+ private val toppings = ArrayBuffer[Topping]()
+
+ def addTopping(t: Topping): Unit =
+ toppings += t
+
+ def removeTopping(t: Topping): Unit =
+ toppings -= t
+
+ def removeAllToppings(): Unit =
+ toppings.clear()
+
+ override def toString(): String =
+ s"""
+ |Pizza:
+ | Crust Size: ${crustSize}
+ | Crust Type: ${crustType}
+ | Toppings: ${toppings}
+ """.stripMargin
+
+end Pizza
+
+// create a Pizza instance
+val p = Pizza(Small, Thin)
+
+// change the crust
+p.crustSize = Large
+p.crustType = Thick
+
+// add and remove toppings
+p.addTopping(Cheese)
+p.addTopping(Pepperoni)
+p.addTopping(BlackOlives)
+p.removeTopping(Pepperoni)
+
+// print the pizza, which uses its `toString` method
+println(p)
+```
+
+## 接口、trait 和继承
+
+Scala 使用 trait 作为接口,也可以创建混搭。
+trait 可以有抽象和具体的成员,包括方法和字段。
+
+这个例子展示了如何定义两个 traits,创建一个扩展和实现这些 traits 的类,然后创建和使用该类的一个实例:
+
+```scala
+trait HasLegs:
+ def numLegs: Int
+ def walk(): Unit
+ def stop() = println("Stopped walking")
+
+trait HasTail:
+ def wagTail(): Unit
+ def stopTail(): Unit
+
+class Dog(var name: String) extends HasLegs, HasTail:
+ val numLegs = 4
+ def walk() = println("I’m walking")
+ def wagTail() = println("⎞⎜⎛ ⎞⎜⎛")
+ def stopTail() = println("Tail is stopped")
+ override def toString = s"$name is a Dog"
+
+// create a Dog instance
+val d = Dog("Rover")
+
+// use the class’s attributes and behaviors
+println(d.numLegs) // 4
+d.wagTail() // "⎞⎜⎛ ⎞⎜⎛"
+d.walk() // "I’m walking"
+```
+
+## 控制结构
+
+除了在 JavaScript 中使用 `===` 和 `!==` 之外,比较和逻辑运算符在 JavaScript 和 Scala 中几乎相同。
+
+{% comment %}
+TODO: Sébastien mentioned that `===` is closest to `eql` in Scala. Update this area.
+{% endcomment %}
+
+### 比较运算符
+
+
+ // newer syntax
+ for (let i of nums) {
+ console.log(i);
+ }
+
+ // older
+ for (i=0; i<nums.length; i++) {
+ console.log(nums[i]);
+ }
+
+
+
+
+ // preferred
+ for i <- ints do println(i)
+
+ // also available
+ for (i <- ints) println(i)
+
+
+
+
+
+### `for` 循环,在循环体内多行
+
+
+
+
+
+ // preferred
+ for (let i of nums) {
+ let j = i * 2;
+ console.log(j);
+ }
+
+ // also available
+ for (i=0; i<nums.length; i++) {
+ let j = nums[i] * 2;
+ console.log(j);
+ }
+
+
+
+
+ // preferred
+ for i <- ints do
+ val i = i * 2
+ println(j)
+
+ // also available
+ for (i <- nums) {
+ val j = i * 2
+ println(j)
+ }
+
+
+
+
+
+### 在 `for` 循环中有多个生成器
+
+
+
+
+
+ let str = "ab";
+ for (let i = 1; i < 3; i++) {
+ for (var j = 0; j < str.length; j++) {
+ for (let k = 1; k < 11; k++) {
+ let c = str.charAt(j);
+ console.log(`i: ${i} j: ${c} k: ${k}`);
+ }
+ }
+ }
+
+
+
+
+ for
+ i <- 1 to 2
+ j <- 'a' to 'b'
+ k <- 1 to 10 by 5
+ do
+ println(s"i: $i, j: $j, k: $k")
+
+ if x == 1:
+ print("x is 1, as you can see:")
+ print(x)
+
+
+
+
+ if x == 1 then
+ println("x is 1, as you can see:")
+ println(x)
+
+
+
+
+
+### if, else if, else:
+
+
+
+
+
+ if x < 0:
+ print("negative")
+ elif x == 0:
+ print("zero")
+ else:
+ print("positive")
+
+
+
+
+ if x < 0 then
+ println("negative")
+ else if x == 0 then
+ println("zero")
+ else
+ println("positive")
+
+
+
+
+
+### 从 `if` 返回值:
+
+
+
+
+
+ min_val = a if a < b else b
+
+
+
+
+ val minValue = if a < b then a else b
+
+
+
+
+
+### `if` 作为方法体:
+
+
+
+
+
+ def min(a, b):
+ return a if a < b else b
+
+
+
+
+ def min(a: Int, b: Int): Int =
+ if a < b then a else b
+
+
+
+
+
+### `while` 循环:
+
+
+
+
+
+ i = 1
+ while i < 3:
+ print(i)
+ i += 1
+
+
+
+
+ var i = 1
+ while i < 3 do
+ println(i)
+ i += 1
+
+
+
+
+
+### 有范围的 `for` 循环:
+
+
+
+
+
+ for i in range(0,3):
+ print(i)
+
+
+
+
+ // preferred
+ for i <- 0 until 3 do println(i)
+
+ // also available
+ for (i <- 0 until 3) println(i)
+
+ // multiline syntax
+ for
+ i <- 0 until 3
+ do
+ println(i)
+
+
+
+
+
+### 列表的 `for` 循环:
+
+
+
+
+
+ for i in ints: print(i)
+
+ for i in ints:
+ print(i)
+
+
+
+
+ for i <- ints do println(i)
+
+
+
+
+
+### `for` 循环,多行:
+
+
+
+
+
+ for i in ints:
+ x = i * 2
+ print(f"i = {i}, x = {x}")
+
+
+
+
+ for
+ i <- ints
+ do
+ val x = i * 2
+ println(s"i = $i, x = $x")
+
+
+
+
+
+### 多“范围”生成器:
+
+
+
+
+
+ for i in range(1,3):
+ for j in range(4,6):
+ for k in range(1,10,3):
+ print(f"i = {i}, j = {j}, k = {k}")
+
+
+
+
+ for
+ i <- 1 to 2
+ j <- 4 to 5
+ k <- 1 until 10 by 3
+ do
+ println(s"i = $i, j = $j, k = $k")
+
+
+
+
+
+### 带守卫(`if` 表达式)的生成器:
+
+
+
+
+
+ for i in range(1,11):
+ if i % 2 == 0:
+ if i < 5:
+ print(i)
+
+
+
+
+ for
+ i <- 1 to 10
+ if i % 2 == 0
+ if i < 5
+ do
+ println(i)
+
+
+
+
+
+### 每行有多个 `if` 条件:
+
+
+
+
+
+ for i in range(1,11):
+ if i % 2 == 0 and i < 5:
+ print(i)
+
+
+
+
+ for
+ i <- 1 to 10
+ if i % 2 == 0 && i < 5
+ do
+ println(i)
+
+
+
+
+
+### 推导:
+
+
+
+
+
+ xs = [i * 10 for i in range(1, 4)]
+ # xs: [10,20,30]
+
+
+
+
+ val xs = for i <- 1 to 3 yield i * 10
+ // xs: Vector(10, 20, 30)
+
+
+
+
+
+### `match` 表达式:
+
+
+
+
+
+ # From 3.10, Python supports structural pattern matching
+ # You can also use dictionaries for basic “switch” functionality
+ match month:
+ case 1:
+ monthAsString = "January"
+ case 2:
+ monthAsString = "February"
+ case _:
+ monthAsString = "Other"
+
+
+
+
+ val monthAsString = month match
+ case 1 => "January"
+ case 2 => "February"
+ _ => "Other"
+
+
+
+
+
+### switch/match:
+
+
+
+
+
+ # Only from Python 3.10
+ match i:
+ case 1 | 3 | 5 | 7 | 9:
+ numAsString = "odd"
+ case 2 | 4 | 6 | 8 | 10:
+ numAsString = "even"
+ case _:
+ numAsString = "too big"
+
+
+
+
+ val numAsString = i match
+ case 1 | 3 | 5 | 7 | 9 => "odd"
+ case 2 | 4 | 6 | 8 | 10 => "even"
+ case _ => "too big"
+
+
+匹配表达式和模式匹配是 Scala 编程体验的重要组成部分,但这里只展示了几个 `match` 表达式功能。 有关更多示例,请参见 [控制结构][control-structures] 页面。
+
+## 集合类
+
+本节比较 Python 和 Scala 中可用的 [集合类][collections-classes],包括列表、字典/映射、集合和元组。
+
+### 列表
+
+Python 有它的列表,Scala 有几个不同的专门的可变和不可变序列类,具体取决于您的需要。
+因为 Python 列表是可变的,所以它最直接地与 Scala 的 `ArrayBuffer` 进行比较。
+
+### Python 列表 & Scala序列:
+Match expressions and pattern matching are a big part of the Scala programming experience, but only a few `match` expression features are shown here. See the [Control Structures][control-structures] page for many more examples.
+
+## Collections classes
+
+This section compares the [collections classes][collections-classes] that are available in Python and Scala, including lists, dictionaries/maps, sets, and tuples.
+
+### Lists
+
+Where Python has its list, Scala has several different specialized mutable and immutable sequence classes, depending on your needs.
+Because the Python list is mutable, it most directly compares to Scala’s `ArrayBuffer`.
+
+### Python list & Scala sequences:
+
+
+
+
+
+ a = [1,2,3]
+
+
+
+
+ // use different sequence classes
+ // as needed
+ val a = List(1,2,3)
+ val a = Vector(1,2,3)
+ val a = ArrayBuffer(1,2,3)
+
创建一个不可变变量——类似于 Java 中的 final。 您应该始终使用 val 创建一个变量,除非有理由使用可变变量。
+
+
+
var
+
创建一个可变变量,并且只应在变量的内容随时间变化时使用。
+
+
+
+
+这些示例展示了如何创建 `val` 和 `var` 变量:
+
+{% tabs var-express-1 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+// immutable
+val a = 0
+
+// mutable
+var b = 1
+```
+
+{% endtab %}
+{% endtabs %}
+
+在应用程序中,不能重新给一个 `val` 变量赋值。
+如果您尝试重新赋值一个 `val` 变量,将导致编译器错误:
+
+{% tabs var-express-2 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val msg = "Hello, world"
+msg = "Aloha" // "reassignment to val" error; this won’t compile
+```
+
+{% endtab %}
+{% endtabs %}
+
+相反,可以给 `var` 变量重新赋值:
+
+{% tabs var-express-3 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+var msg = "Hello, world"
+msg = "Aloha" // 因为可以重新分配 var,所以可以编译
+```
+
+{% endtab %}
+{% endtabs %}
+
+## 声明变量类型
+
+创建变量时,您可以显式声明其类型,或让编译器推断类型:
+
+{% tabs var-express-4 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val x: Int = 1 // 显式
+val x = 1 // 隐式的;编译器推断类型
+```
+
+{% endtab %}
+{% endtabs %}
+
+第二种形式称为 _类型推断_,它是帮助保持此类代码简洁的好方法。
+Scala 编译器通常可以为您推断数据类型,如以下 REPL 示例的输出所示:
+
+{% tabs var-express-5 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+scala> val x = 1
+val x: Int = 1
+
+scala> val s = "a string"
+val s: String = a string
+
+scala> val nums = List(1, 2, 3)
+val nums: List[Int] = List(1, 2, 3)
+```
+
+{% endtab %}
+{% endtabs %}
+
+如果您愿意,您始终可以显式声明变量的类型,但在像这样的简单赋值中,不须要这样:
+
+{% tabs var-express-6 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val x: Int = 1
+val s: String = "a string"
+val p: Person = Person("Richard")
+```
+
+{% endtab %}
+{% endtabs %}
+
+请注意,使用这种方法会感觉代码太啰嗦。
+
+{% comment %}
+TODO: Jonathan had an early comment on the text below: “While it might feel like this, I would be afraid that people automatically assume from this statement that everything is always boxed.” Suggestion on how to change this?
+{% endcomment %}
+
+## 内置数据类型
+
+Scala 带有你所期望的标准数值数据类型,它们都是类的成熟(full-blown)实例。
+在 Scala 中,一切都是对象。
+
+这些示例展示了如何声明数值类型的变量:
+
+{% tabs var-express-7 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val b: Byte = 1
+val i: Int = 1
+val l: Long = 1
+val s: Short = 1
+val d: Double = 2.0
+val f: Float = 3.0
+```
+
+{% endtab %}
+{% endtabs %}
+
+因为 `Int` 和 `Double` 是默认的数字类型,所以您通常创建它们而不显式声明数据类型:
+
+{% tabs var-express-8 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val i = 123 // 默认为 Int
+val j = 1.0 // 默认为 Double
+```
+
+{% endtab %}
+{% endtabs %}
+
+在您的代码中,您还可以将字符 `L`、`D` 和 `F`(或者它们对应的小写字母)加到数字后面以指定它们是 `Long`、`Double` 或 `Float` 值:
+
+{% tabs var-express-9 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val x = 1_000L // val x: Long = 1000
+val y = 2.2D // val y: Double = 2.2
+val z = 3.3F // val z: Float = 3.3
+```
+
+{% endtab %}
+{% endtabs %}
+
+当您需要非常大的数字时,请使用 `BigInt` 和 `BigDecimal` 类型:
+
+{% tabs var-express-10 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+var a = BigInt(1_234_567_890_987_654_321L)
+var b = BigDecimal(123_456.789)
+```
+
+{% endtab %}
+{% endtabs %}
+
+其中 `Double` 和 `Float` 是近似十进制数,`BigDecimal` 用于精确算术。
+
+Scala 还有 `String` 和 `Char` 数据类型:
+
+{% tabs var-express-11 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val name = "Bill" // String
+val c = 'a' // Char
+```
+
+{% endtab %}
+{% endtabs %}
+
+### 字符串
+
+Scala 字符串类似于 Java 字符串,但它们有两个很棒的附加特性:
+
+- 他们支持字符串插值
+- 创建多行字符串很容易
+
+#### 字符串插值
+
+字符串插值提供了一种非常易读的方式在字符串中使用变量。
+例如,给定这三个变量:
+
+{% tabs var-express-12 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val firstName = "John"
+val mi = 'C'
+val lastName = "Doe"
+```
+
+{% endtab %}
+{% endtabs %}
+
+您可以将这些变量组合在一个字符串中,如下所示:
+
+{% tabs var-express-13 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+println(s"Name: $firstName $mi $lastName") // "Name: John C Doe"
+```
+
+{% endtab %}
+{% endtabs %}
+
+只需在字符串前面加上字母 `s`,然后在字符串中的变量名之前放置一个 `$` 符号。
+
+要将任意表达式嵌入字符串中,请将它们括在花括号中:
+
+{% tabs var-express-14 %}
+{% tab 'Scala 2 and 3' %}
+
+``` scala
+println(s"2 + 2 = ${2 + 2}") // 打印 "2 + 2 = 4"
+
+val x = -1
+println(s"x.abs = ${x.abs}") // 打印 "x.abs = 1"
+```
+
+{% endtab %}
+{% endtabs %}
+
+放在字符串前面的 `s` 只是一种可能的插值器。
+如果使用 `f` 而不是 `s`,则可以在字符串中使用 `printf` 样式的格式化语法。
+此外,字符串插值器只是一种特殊方法,可以定义自己的方法。
+例如,有一些数据库方向的类库定义了非常强大的 `sql` 插值器。
+
+#### 多行字符串
+
+多行字符串是通过将字符串包含在三个双引号内来创建的:
+
+{% tabs var-express-15 %}
+{% tab 'Scala 2 and 3' %}
+
+```scala
+val quote = """The essence of Scala:
+ Fusion of functional and object-oriented
+ programming in a typed setting."""
+```
+
+{% endtab %}
+{% endtabs %}
+
+> 有关字符串插值器和多行字符串的更多详细信息,请参阅[“类型初探”章节][first-look]。
+
+[first-look]: {% link _zh-cn/overviews/scala3-book/first-look-at-types.md %}
diff --git a/_zh-cn/overviews/scala3-book/tools-sbt.md b/_zh-cn/overviews/scala3-book/tools-sbt.md
new file mode 100644
index 0000000000..2b1720c2c9
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/tools-sbt.md
@@ -0,0 +1,496 @@
+---
+title: 使用 sbt 构建和测试 Scala 项目
+type: section
+description: This section looks at a commonly-used build tool, sbt, and a testing library, ScalaTest.
+language: zh-cn
+num: 70
+previous-page: scala-tools
+next-page: tools-worksheets
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+---
+
+
+在本节中,您将看到 Scala 项目中常用的两个工具:
+
+- [sbt](https://www.scala-sbt.org) 构建工具
+- [ScalaTest](https://www.scalatest.org),一个源代码测试框架
+
+我们将首先展示如何使用 sbt 构建您的 Scala 项目,然后我们将展示如何一起使用 sbt 和 ScalaTest 来测试您的 Scala 项目。
+
+> 如果您想了解帮助您将 Scala 2 代码迁移到 Scala 3 的工具,请参阅我们的 [Scala 3 迁移指南](/scala3/guides/migration/compatibility-intro.html)。
+
+## 使用 sbt 构建 Scala 项目
+
+您可以使用多种不同的工具来构建您的 Scala 项目,包括 Ant、Maven、Gradle、Mill 等。
+但是名为 _sbt_ 的工具是第一个专门为 Scala 创建的构建工具。
+
+> 要安装 sbt,请参阅 [其下载页面](https://www.scala-sbt.org/download.html) 或我们的 [Getting Started][getting_started] 页面。
+
+### 创建一个 “Hello, world” 项目
+
+只需几个步骤,您就可以创建一个 sbt “Hello, world” 项目。
+首先,创建一个工作目录,然后进入该目录:
+
+```bash
+$ mkdir hello
+$ cd hello
+```
+
+在 `hello` 目录下,创建一个子目录 `project`:
+
+```bash
+$ mkdir project
+```
+
+在 `project` 目录中创建一个名为 _build.properties_ 的文件,其中
+以下内容:
+
+```text
+sbt.version=1.10.11
+```
+
+然后在包含此行的项目根目录中创建一个名为 _build.sbt_ 的文件:
+
+```scala
+scalaVersion := "{{ site.scala-3-version }}"
+```
+
+现在创建一个名为 _Hello.scala_ 的文件——名称的第一部分无关紧要——使用这一行:
+
+```scala
+@main def helloWorld = println("Hello, world")
+```
+
+这就是你所要做的。
+
+您应该具有如下的项目结构:
+
+~~~ bash
+$ tree
+.
+├── build.sbt
+├── Hello.scala
+└── project
+ └── build.properties
+~~~
+
+现在使用 `sbt` 命令运行项目:
+
+```bash
+$ sbt run
+```
+
+您应该会看到如下所示的输出,包括程序中的 `"Hello, world"`:
+
+```bash
+$ sbt run
+[info] welcome to sbt 1.5.4 (AdoptOpenJDK Java 11.x)
+[info] loading project definition from project ...
+[info] loading settings for project from build.sbt ...
+[info] compiling 1 Scala source to target/scala-3.0.0/classes ...
+[info] running helloWorld
+Hello, world
+[success] Total time: 2 s
+```
+
+sbt 启动器——`sbt` 命令行工具——加载文件 _project/build.properties_ 中设置的 sbt 版本,它加载文件 _build.sbt_ 中设置的 Scala 编译器版本,编译 _Hello.scala_ 文件中的代码,并运行生成的字节码。
+
+当你查看你的目录时,你会看到 sbt 有一个名为 _target_ 的目录。
+这些是 sbt 使用的工作目录。
+
+如您所见,使用 sbt 创建和运行一个小的 Scala 项目只需要几个简单的步骤。
+
+### 在大型项目中使用 sbt
+
+对于一个小项目,这就是 sbt 运行所需的全部内容。
+对于需要许多源代码文件、依赖项或 sbt 插件的大型项目,您需要创建一个有组织的目录结构。
+本节的其余部分演示了 sbt 使用的结构。
+
+### sbt 目录结构
+
+与 Maven 一样,sbt 使用标准的项目目录结构。
+这样做的一个很好的好处是,一旦你对它的结构感到满意,它就可以很容易地处理其他 Scala/sbt 项目。
+
+首先要知道的是,在项目的根目录下,sbt 需要一个如下所示的目录结构:
+
+```text
+.
+├── build.sbt
+├── project/
+│ └── build.properties
+├── src/
+│ ├── main/
+│ │ ├── java/
+│ │ ├── resources/
+│ │ └── scala/
+│ └── test/
+│ ├── java/
+│ ├── resources/
+│ └── scala/
+└── target/
+```
+
+如果您想将非托管依赖项---JAR 文件---添加到您的项目中,您还可以在根目录下添加一个 _lib_ 目录。
+
+如果您要创建一个包含 Scala 源代码文件和测试的项目,但不会使用任何 Java 源代码文件,并且不需要任何“资源”——例如嵌入式图像、配置文件、等等---这就是你在_src_目录下真正需要的:
+
+```text
+.
+└── src/
+ ├── main/
+ │ └── scala/
+ └── test/
+ └── scala/
+```
+
+### 带有 sbt 目录结构的 “Hello, world”
+
+{% comment %}
+LATER: using something like `sbt new scala/scala3.g8` may eventually
+ be preferable, but that seems to have a few bugs atm (creates
+ a 'target' directory above the root; renames the root dir;
+ uses 'dottyVersion'; 'name' doesn’t match the supplied name;
+ config syntax is a little hard for beginners.)
+{% endcomment %}
+
+创建这个目录结构很简单。
+有一些工具可以为你做到这一点,但假设你使用的是 Unix/Linux 系统,你可以使用这些命令来创建你的第一个 sbt 项目目录结构:
+
+```bash
+$ mkdir HelloWorld
+$ cd HelloWorld
+$ mkdir -p src/{main,test}/scala
+$ mkdir project target
+```
+
+在运行这些命令后运行 `find .` 命令时,您应该会看到以下结果:
+
+```bash
+$ find .
+.
+./project
+./src
+./src/main
+./src/main/scala
+./src/test
+./src/test/scala
+./target
+```
+
+如果你看到上面那样,那么没有问题,可以进行下一步了。
+
+> 还有其他方法可以为 sbt 项目创建文件和目录。
+> 一种方法是使用 `sbt new` 命令,[在 scala-sbt.org 上有文档](https://www.scala-sbt.org/1.x/docs/Hello.html)。
+> 该方法未在此处显示,因为它创建的某些文件比像这样的介绍所必需的要复杂。
+
+### 创建第一个 build.sbt 文件
+
+此时,您只需要另外两件事来运行 “Hello, world” 项目:
+
+- 一个 _build.sbt_ 文件
+- 一个 _Hello.scala_ 文件
+
+对于像这样的小项目,_build.sbt_ 文件只需要一个 `scalaVersion` 条目,但我们将添加您通常看到的三行:
+
+```scala
+name := "HelloWorld"
+version := "0.1"
+scalaVersion := "{{ site.scala-3-version }}"
+```
+
+因为 sbt 项目使用标准的目录结构,所以 sbt 可以找到它需要的所有其他内容。
+
+现在你只需要添加一个小小的“Hello, world”程序。
+
+### “Hello, world” 程序
+
+在大型项目中,您所有的 Scala 源代码文件都将放在 _src/main/scala_ 和 _src/test/scala_ 目录下,但是对于像这样的小示例项目,您可以将源代码文件放在您项目的根目录下。
+因此,在根目录中创建一个名为 _HelloWorld.scala_ 的文件,其中包含以下内容:
+
+```scala
+@main def helloWorld = println("Hello, world")
+```
+
+该代码定义了一个 Scala 3 “main” 方法,该方法在运行时打印 `"Hello, world"`。
+
+现在,使用 `sbt run` 命令编译并运行您的项目:
+
+```bash
+$ sbt run
+
+[info] welcome to sbt
+[info] loading settings for project ...
+[info] loading project definition
+[info] loading settings for project root from build.sbt ...
+[info] Compiling 1 Scala source ...
+[info] running helloWorld
+Hello, world
+[success] Total time: 4 s
+```
+
+第一次运行 `sbt` 时,它会下载所需的所有内容,这可能需要一些时间才能运行,但之后它会变得更快。
+
+此外,一旦你完成了这第一步,你会发现以交互方式运行 sbt 会快得多。
+为此,首先单独运行 `sbt` 命令:
+
+```bash
+$ sbt
+
+[info] welcome to sbt
+[info] loading settings for project ...
+[info] loading project definition ...
+[info] loading settings for project root from build.sbt ...
+[info] sbt server started at
+ local:///${HOME}/.sbt/1.0/server/7d26bae822c36a31071c/sock
+sbt:hello-world> _
+```
+
+然后在这个 sbt shell 中,执行它的 `run` 命令:
+
+````
+sbt:hello-world> run
+
+[info] running helloWorld
+Hello, world
+[success] Total time: 0 s
+````
+
+这要快得多。
+
+如果您在 sbt 命令提示符下键入 `help`,您将看到可以运行的其他命令的列表。
+但现在,只需键入 `exit`(或按 `CTRL-D`)离开 sbt shell。
+
+### 使用项目模板
+
+手动创建项目结构可能很乏味。谢天谢地,sbt 可以基于模板为你创建项目。
+
+要从模板创建 Scala 3 项目,请在 shell 中运行以下命令:
+
+~~~
+$ sbt new scala/scala3.g8
+~~~
+
+Sbt 将加载模板,提出一些问题,并在子目录中创建项目文件:
+
+~~~
+$ tree scala-3-project-template
+scala-3-project-template
+├── build.sbt
+├── project
+│ └── build.properties
+├── README.md
+└── src
+ ├── main
+ │ └── scala
+ │ └── Main.scala
+ └── test
+ └── scala
+ └── Test1.scala
+~~~
+
+> 如果要创建与 Scala 2 交叉编译的 Scala 3 项目,请使用模板 `scala/scala3-cross.g8`:
+>
+> ~~~
+> $ sbt new scala/scala3-cross.g8
+> ~~~
+
+在 [sbt 文档](https://www.scala-sbt.org/1.x/docs/sbt-new-and-Templates.html#sbt+new+) 中了解有关 `sbt new` 和项目模板的更多信息。
+
+### Scala 的其他构建工具
+
+虽然 sbt 被广泛使用,但您还可以使用其他工具来构建 Scala 项目:
+
+- [ant](https://ant.apache.org/)
+- [Gradle](https://gradle.org/)
+- [Maven](https://maven.apache.org/)
+- [mill](https://com-lihaoyi.github.io/mill/)
+
+#### Coursier
+
+在相关说明中,[Coursier](https://get-coursier.io/docs/overview) 是一个“依赖解析器”,在功能上类似于 Maven 和 Ivy。
+它是用 Scala 从头开始编写的,“包含函数式编程原则”,并且可以并行下载工件以实现快速下载。
+sbt 使用它来处理大多数依赖关系解析,并且作为一个命令行工具,它可以用于在您的系统上轻松安装 sbt、Java 和 Scala 等工具,如我们的 [Getting Started][getting_started] 页面所示。
+
+来自 `launch` 网页的这个示例显示了 `cs launch` 命令可用于从依赖项启动应用程序:
+
+```scala
+$ cs launch org.scalameta::scalafmt-cli:2.4.2 -- --help
+scalafmt 2.4.2
+Usage: scalafmt [options] [...]
+
+ -h, --help prints this usage text
+ -v, --version print version
+ more ...
+```
+
+有关详细信息,请参阅 Coursier 的 [启动页面](https://get-coursier.io/docs/cli-launch)。
+
+## 使用 sbt 和 ScalaTest
+
+[ScalaTest](https://www.scalatest.org) 是 Scala 项目的主要测试库之一。
+在本节中,您将看到创建使用 ScalaTest 的 Scala/sbt 项目所需的步骤。
+
+### 1) 创建项目目录结构
+
+与上一课一样,使用以下命令为名为 _HelloScalaTest_ 的项目创建一个 sbt 项目目录结构:
+
+```bash
+$ mkdir HelloScalaTest
+$ cd HelloScalaTest
+$ mkdir -p src/{main,test}/scala
+$ mkdir project
+```
+
+### 2) 创建 build.properties 和 build.sbt 文件
+
+接下来,把下面这行代码用于在项目的 _project/_ 子目录中创建一个 _build.properties_ 文件:
+
+```text
+sbt.version=1.10.11
+```
+
+接下来,在项目的根目录中创建一个 _build.sbt_ 文件,其中包含以下内容:
+
+```scala
+name := "HelloScalaTest"
+version := "0.1"
+scalaVersion := "{{site.scala-3-version}}"
+
+libraryDependencies ++= Seq(
+ "org.scalatest" %% "scalatest" % "3.2.19" % Test
+)
+```
+
+该文件的前三行与第一个示例基本相同。
+`libraryDependencies` 行告诉 sbt 包含包含 ScalaTest 所需的依赖项(JAR 文件)。
+
+> ScalaTest 文档一直很优秀,您始终可以在 [安装 ScalaTest](https://www.scalatest.org/install) 页面上找到有关这些行应该是什么样子的最新信息。
+
+### 3) 创建一个 Scala 源代码文件
+
+接下来,创建一个可用于演示 ScalaTest 的 Scala 程序。
+首先,在 _src/main/scala_ 下创建一个名为 _math_ 的目录:
+
+```bash
+$ mkdir src/main/scala/math
+ ----
+```
+
+然后,在该目录中,使用以下内容创建一个名为 _MathUtils.scala_ 的文件:
+
+```scala
+package math
+
+object MathUtils:
+ def double(i: Int) = i * 2
+```
+
+该方法提供了一种演示 ScalaTest 的简单方法。
+
+{% comment %}
+Because this project doesn’t have a `main` method, we don’t try to run it with `sbt run`; we just compile it with `sbt compile`:
+
+````
+$ sbt compile
+
+[info] welcome to sbt
+[info] loading settings for project ...
+[info] loading project definition ...
+[info] loading settings for project ...
+[info] Executing in batch mode. For better performance use sbt's shell
+[success] Total time: 1 s
+````
+
+With that compiled, let’s create a ScalaTest file to test the `double` method.
+{% endcomment %}
+
+### 4) 创建你的第一个 ScalaTest 测试
+
+ScalaTest 非常灵活,并提供了几种不同的方式来编写测试。
+一个简单的入门方法是使用 ScalaTest `AnyFunSuite` 编写测试。
+首先,在 _src/test/scala_ 目录下创建一个名为 _math_ 的目录:
+
+```bash
+$ mkdir src/test/scala/math
+ ----
+```
+
+接下来,在该目录中创建一个名为 _MathUtilsTests.scala_ 的文件,其内容如下:
+
+```scala
+package math
+
+import org.scalatest.funsuite.AnyFunSuite
+
+class MathUtilsTests extends AnyFunSuite:
+
+ // test 1
+ test("'double' should handle 0") {
+ val result = MathUtils.double(0)
+ assert(result == 0)
+ }
+
+ // test 2
+ test("'double' should handle 1") {
+ val result = MathUtils.double(1)
+ assert(result == 2)
+ }
+
+ test("test with Int.MaxValue") (pending)
+
+end MathUtilsTests
+```
+
+此代码演示了 ScalaTest `AnyFunSuite` 方法。
+几个重要的点:
+
+- 你的测试类应该继承 `AnyFunSuite`
+- 如图所示,您可以通过为每个 `test` 指定一个唯一的名称来创建测试
+- 在每个测试结束时,您应该调用 `assert` 来测试条件是否已满足
+- 当你知道你想写一个测试,但你现在不想写它时,将测试创建为“待定”,语法如上例所示
+
+像这样使用 ScalaTest 类似于 JUnit,所以如果你是从 Java 转到 Scala 的,希望这看起来相似。
+
+现在您可以使用 `sbt test` 命令运行这些测试。
+跳过前几行输出,结果如下所示:
+
+````
+sbt:HelloScalaTest> test
+
+[info] Compiling 1 Scala source ...
+[info] MathUtilsTests:
+[info] - 'double' should handle 0
+[info] - 'double' should handle 1
+[info] - test with Int.MaxValue (pending)
+[info] Total number of tests run: 2
+[info] Suites: completed 1, aborted 0
+[info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 1
+[info] All tests passed.
+[success] Total time: 1 s
+````
+
+如果一切正常,您将看到类似的输出。
+欢迎来到使用 sbt 和 ScalaTest 测试 Scala 应用程序的世界。
+
+### 支持多种类型的测试
+
+此示例演示了一种类似于 xUnit _测试驱动开发_(TDD) 样式测试的测试样式,并具有_行为驱动开发_(BDD) 样式的一些优点。
+
+如前所述,ScalaTest 很灵活,您还可以用其它风格来编写测试,例如类似于 Ruby 的 RSpec 的风格。
+您还可以使用伪对象、基于属性的测试,并使用 ScalaTest 来测试 Scala.js 代码。
+
+有关可用的不同测试风格的更多详细信息,请参阅 [ScalaTest 网站](https://www.scalatest.org) 上的用户指南。
+
+## 从这往哪儿走
+
+有关 sbt 和 ScalaTest 的更多信息,请参阅以下资源:
+
+- [sbt 文档](https://www.scala-sbt.org/1.x/docs/)
+- [ScalaTest 网站](https://www.scalatest.org/)
+
+
+[getting_started]: {{ site.baseurl }}/scala3/getting-started.html
diff --git a/_zh-cn/overviews/scala3-book/tools-worksheets.md b/_zh-cn/overviews/scala3-book/tools-worksheets.md
new file mode 100644
index 0000000000..214b744d8b
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/tools-worksheets.md
@@ -0,0 +1,65 @@
+---
+title: worksheet
+type: section
+description: This section looks at worksheets, an alternative to Scala projects.
+language: zh-cn
+num: 71
+previous-page: tools-sbt
+next-page: interacting-with-java
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+---
+
+
+工作表是在保存时评估的 Scala 文件,并把每个表达式的结果
+显示在程序右侧的列中。工作表就像是加了激素的[REPL 会话][REPL session],并且
+享受一流的编辑器支持:自动补全、超链接、交互式错误输入等。
+工作表使用扩展名 `.worksheet.sc` 。
+
+下面,我们将展示如何在 IntelliJ 和 VS Code(带有 Metals 扩展)中使用工作表。
+
+1. 打开一个 Scala 项目,或者创建一个。
+ - 要在 IntelliJ 中创建项目,选择“File”->“New”->“Project...”, 在左侧栏中选择“Scala”,
+ 单击“下一步”设置项目名称和位置。
+ - 要在 VS Code 中创建项目,请运行命令“Metals: New Scala project”,选择
+ 种子 `scala/scala3.g8`,设置项目位置,在新的 VS Code 窗口中打开它,然后
+ 导入其构建。
+1. 在 `src/main/scala/` 目录下创建一个名为 `hello.worksheet.sc` 的文件。
+ - 在 IntelliJ 中,右键单击目录 `src/main/scala/`,然后选择“New”,然后
+ 是“文件”。
+ - 在 VS Code 中,右键单击目录`src/main/scala/`,然后选择“New File”。
+1. 在编辑器中粘贴以下内容:
+ ~~~
+ println("Hello, world!")
+
+ val x = 1
+ x + x
+ ~~~
+
+1. 评估工作表。
+ - 在 IntelliJ 中,单击编辑器顶部的绿色箭头以评估工作表。
+ - 在 VS Code 中,保存文件。
+
+ 您应该在右侧面板 (IntelliJ) 上看到每一行的评估结果,或者
+ 作为注释(VS Code)。
+
+
+
+在 IntelliJ 中评估的工作表。
+
+
+
+在 VS Code 中评估的工作表(带有 Metals 扩展)。
+
+请注意,工作表将使用项目定义的 Scala 版本(通常在文件`build.sbt`中,
+设置 `scalaVersion` 键)。
+
+另请注意,工作表没有 [程序入口点][program entry point]。作为替代,顶级语句和表达式
+从上到下进行评估。
+
+
+[REPL session]: {% link _zh-cn/overviews/scala3-book/taste-repl.md %}
+[program entry point]: {% link _zh-cn/overviews/scala3-book/methods-main-methods.md %}
diff --git a/_zh-cn/overviews/scala3-book/types-adts-gadts.md b/_zh-cn/overviews/scala3-book/types-adts-gadts.md
new file mode 100644
index 0000000000..4d1604e187
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/types-adts-gadts.md
@@ -0,0 +1,213 @@
+---
+title: 代数数据类型
+type: section
+description: This section introduces and demonstrates algebraic data types (ADTs) in Scala 3.
+language: zh-cn
+num: 53
+previous-page: types-union
+next-page: types-variance
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+---
+
+
+代数数据类型 (ADT) 可以使用 `enum` 构造创建,因此我们将在查看 ADT 之前简要回顾一下枚举。
+
+## 枚举
+
+_enumeration_ 用于定义由一组命名值组成的类型:
+
+```scala
+enum Color:
+ case Red, Green, Blue
+```
+
+这可以看作是以下的简写:
+
+```scala
+enum Color:
+ case Red extends Color
+ case Green extends Color
+ case Blue extends Color
+```
+
+#### 参数
+
+枚举可以参数化:
+
+```scala
+enum Color(val rgb: Int):
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+```
+
+这样,每个不同的变体都有一个值成员 `rgb`,它被分配了相应的值:
+
+```scala
+println(Color.Green.rgb) // prints 65280
+```
+
+#### 自定义
+
+枚举也可以有自定义:
+
+```scala
+enum Planet(mass: Double, radius: Double):
+
+ private final val G = 6.67300E-11
+ def surfaceGravity = G * mass / (radius * radius)
+ def surfaceWeight(otherMass: Double) = otherMass * surfaceGravity
+
+ case Mercury extends Planet(3.303e+23, 2.4397e6)
+ case Venus extends Planet(4.869e+24, 6.0518e6)
+ case Earth extends Planet(5.976e+24, 6.37814e6)
+ // 5 or 6 more planets ...
+```
+
+像类和 `case` 类一样,你也可以为枚举定义一个伴生对象:
+
+```scala
+object Planet:
+ def main(args: Array[String]) =
+ val earthWeight = args(0).toDouble
+ val mass = earthWeight / Earth.surfaceGravity
+ for (p <- values)
+ println(s"Your weight on $p is ${p.surfaceWeight(mass)}")
+```
+
+## 代数数据类型 (ADTs)
+
+`enum` 概念足够通用,既支持_代数数据类型_(ADT)和它的通用版本(GADT)。
+本示例展示了如何将 `Option` 类型表示为 ADT:
+
+```scala
+enum Option[+T]:
+ case Some(x: T)
+ case None
+```
+
+这个例子创建了一个带有协变类型参数 `T` 的 `Option` 枚举,它由两种情况组成, `Some` 和 `None`。
+`Some` 是_参数化_的,它带有值参数 `x`;它是从 `Option` 继承的 `case` 类的简写。
+由于 `None` 没有参数化,它被视为普通的 `enum` 值。
+
+前面示例中省略的 `extends` 子句也可以显式给出:
+
+```scala
+enum Option[+T]:
+ case Some(x: T) extends Option[T]
+ case None extends Option[Nothing]
+```
+
+与普通的 `enum` 值一样,`enum` 的情况是在 `enum` 的伴生对象中定义的,因此它们被引用为 `Option.Some` 和 `Option.None`(除非定义是在导入时单独列出):
+
+```scala
+scala> Option.Some("hello")
+val res1: t2.Option[String] = Some(hello)
+
+scala> Option.None
+val res2: t2.Option[Nothing] = None
+```
+
+与其他枚举用途一样,ADT 可以定义更多的方法。
+例如,这里又是一个 `Option`,它的伴生对象中有一个 `isDefined` 方法和一个 `Option(...)` 构造函数:
+
+```scala
+enum Option[+T]:
+ case Some(x: T)
+ case None
+
+ def isDefined: Boolean = this match
+ case None => false
+ case Some(_) => true
+
+object Option:
+ def apply[T >: Null](x: T): Option[T] =
+ if (x == null) None else Some(x)
+```
+
+枚举和 ADT 共享相同的句法结构,因此它们可以
+被简单地视为光谱的两端,把二者混搭是完全可能的。
+例如,下面的代码给出了一个
+`Color` 的实现,可以使用三个枚举值或使用
+RGB 值的参数化情况:
+
+```scala
+enum Color(val rgb: Int):
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+ case Mix(mix: Int) extends Color(mix)
+```
+
+#### 递归枚举
+
+到目前为止,我们定义的所有枚举都由值或样例类的不同变体组成。
+枚举也可以是递归的,如下面的自然数编码示例所示:
+
+```scala
+enum Nat:
+ case Zero
+ case Succ(n: Nat)
+```
+
+例如,值 `Succ(Succ(Zero))` 表示一元编码中的数字 `2`。
+列表可以以非常相似的方式定义:
+
+```scala
+enum List[+A]:
+ case Nil
+ case Cons(head: A, tail: List[A])
+```
+
+## 广义代数数据类型 (GADT)
+
+上面的枚举表示法非常简洁,可以作为建模数据类型的完美起点。
+由于我们总是可以更明确,因此也可以表达更强大的类型:广义代数数据类型 (GADT)。
+
+这是一个 GADT 示例,其中类型参数 (`T`) 指定存储在框中的内容:
+
+```scala
+enum Box[T](contents: T):
+ case IntBox(n: Int) extends Box[Int](n)
+ case BoolBox(b: Boolean) extends Box[Boolean](b)
+```
+
+特定构造函数(`IntBox` 或 `BoolBox`)上的模式匹配可恢复类型信息:
+
+```scala
+def extract[T](b: Box[T]): T = b match
+ case IntBox(n) => n + 1
+ case BoolBox(b) => !b
+```
+
+只有在第一种情况下返回一个 `Int` 才是安全的,因为我们从 pattern 匹配输入是一个“IntBox”。
+
+## 去除语法糖的枚举
+
+_从概念上讲_,枚举可以被认为是定义一个密封类及其伴生对象。
+让我们看看上面的 `Color` 枚举的无语法糖版本:
+
+```scala
+sealed abstract class Color(val rgb: Int) extends scala.reflect.Enum
+object Color:
+ case object Red extends Color(0xFF0000) { def ordinal = 0 }
+ case object Green extends Color(0x00FF00) { def ordinal = 1 }
+ case object Blue extends Color(0x0000FF) { def ordinal = 2 }
+ case class Mix(mix: Int) extends Color(mix) { def ordinal = 3 }
+
+ def fromOrdinal(ordinal: Int): Color = ordinal match
+ case 0 => Red
+ case 1 => Green
+ case 2 => Blue
+ case _ => throw new NoSuchElementException(ordinal.toString)
+```
+
+请注意,上面的去除语法糖被简化了,我们故意省略了[一些细节][desugar-enums]。
+
+虽然枚举可以使用其他构造手动编码,但使用枚举更简洁,并且还附带了一些额外的实用程序(例如 `fromOrdinal` 方法)。
+
+[desugar-enums]: {{ site.scala3ref }}/enums/desugarEnums.html
diff --git a/_zh-cn/overviews/scala3-book/types-dependent-function.md b/_zh-cn/overviews/scala3-book/types-dependent-function.md
new file mode 100644
index 0000000000..37084f1647
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/types-dependent-function.md
@@ -0,0 +1,175 @@
+---
+title: 依赖函数类型
+type: section
+description: This section introduces and demonstrates dependent function types in Scala 3.
+language: zh-cn
+num: 57
+previous-page: types-structural
+next-page: types-others
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+---
+
+
+*依赖函数类型*描述函数类型,其中结果类型可能取决于函数的参数值。
+依赖类型和依赖函数类型的概念更高级,您通常只会在设计自己的库或使用高级库时遇到它。
+
+## 依赖方法类型
+
+让我们考虑以下可以存储不同类型值的异构数据库示例。
+键包含有关相应值的类型的信息:
+
+```scala
+trait Key { type Value }
+
+trait DB {
+ def get(k: Key): Option[k.Value] // a dependent method
+}
+```
+
+给定一个键,`get` 方法允许我们访问地图并可能返回类型为 `k.Value` 的存储值。
+我们可以将这个_路径依赖类型_解读为:“根据参数 `k` 的具体类型,我们返回一个匹配值”。
+
+例如,我们可以有以下键:
+
+```scala
+object Name extends Key { type Value = String }
+object Age extends Key { type Value = Int }
+```
+
+以下对方法 `get` 的调用现在将键入检查:
+
+```scala
+val db: DB = ...
+val res1: Option[String] = db.get(Name)
+val res2: Option[Int] = db.get(Age)
+```
+
+调用方法 `db.get(Name)` 返回一个 `Option[String]` 类型的值,而调用 `db.get(Age)` 返回一个 `Option[Int]` 类型的值。
+返回类型_依赖_于传递给 `get` 的参数的具体类型---因此名称为_依赖类型_。
+
+## 依赖函数类型
+
+如上所示,Scala 2 已经支持依赖方法类型。
+但是,创建 `DB` 类型的值非常麻烦:
+
+```scala
+// a user of a DB
+def user(db: DB): Unit =
+ db.get(Name) ... db.get(Age)
+
+// creating an instance of the DB and passing it to `user`
+user(new DB {
+ def get(k: Key): Option[k.Value] = ... // implementation of DB
+})
+```
+
+我们需要手动创建一个匿名的 `DB` 内部类,实现 `get` 方法。
+对于依赖于创建许多不同的 `DB` 实例的代码,这是非常乏味的。
+
+ `DB` 只有一个抽象方法 `get` 。
+如果我们可以使用 lambda 语法,那不是很好吗?
+
+```scala
+user { k =>
+ ... // implementation of DB
+```
+
+事实上,现在这在 Scala 3 中是可能的!我们可以将 `DB` 定义为_依赖函数类型_:
+
+```scala
+type DB = (k: Key) => Option[k.Value]
+// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// A dependent function type
+```
+
+鉴于 `DB` 的这个定义,上面对 `user` 类型的调用按原样检查。
+
+您可以在 [参考文档][ref] 中阅读有关依赖函数类型内部结构的更多信息。
+
+## 案例研究:数值表达式
+
+假设我们要定义一个抽象数字内部表示的模块。
+例如,这对于实现用于自动派生的库很有用。
+
+我们首先为数字定义我们的模块:
+
+```scala
+trait Nums:
+ // the type of numbers is left abstract
+ type Num
+
+ // some operations on numbers
+ def lit(d: Double): Num
+ def add(l: Num, r: Num): Num
+ def mul(l: Num, r: Num): Num
+```
+
+> 我们省略了 `Nums` 的具体实现,但作为练习,您可以通过分配 `type Num = Double` 来实现 `Nums` 并相应地实现方法。
+
+使用我们的数字抽象的程序现在具有以下类型:
+
+```scala
+type Prog = (n: Nums) => n.Num => n.Num
+
+val ex: Prog = nums => x => nums.add(nums.lit(0.8), x)
+```
+
+计算诸如 `ex` 之类的程序的导数的函数的类型是:
+
+```scala
+def derivative(input: Prog): Double
+```
+
+鉴于依赖函数类型的便利,用不同的程序调用这个函数非常方便:
+
+```scala
+derivative { nums => x => x }
+derivative { nums => x => nums.add(nums.lit(0.8), x) }
+// ...
+```
+
+回想一下,上面编码中的相同程序将是:
+
+```scala
+derivative(new Prog {
+ def apply(nums: Nums)(x: nums.Num): nums.Num = x
+})
+derivative(new Prog {
+ def apply(nums: Nums)(x: nums.Num): nums.Num = nums.add(nums.lit(0.8), x)
+})
+// ...
+```
+
+#### 上下文组合函数
+
+扩展方法、[上下文函数][ctx-fun]和依赖函数的组合为库设计者提供了强大的工具。
+例如,我们可以从上面优化我们的库,如下所示:
+
+```scala
+trait NumsDSL extends Nums:
+ extension (x: Num)
+ def +(y: Num) = add(x, y)
+ def *(y: Num) = mul(x, y)
+
+def const(d: Double)(using n: Nums): n.Num = n.lit(d)
+
+type Prog = (n: NumsDSL) ?=> n.Num => n.Num
+// ^^^
+// prog is now a context function that implicitly
+// assumes a NumsDSL in the calling context
+
+def derivative(input: Prog): Double = ...
+
+// notice how we do not need to mention Nums in the examples below?
+derivative { x => const(1.0) + x }
+derivative { x => x * x + const(2.0) }
+// ...
+```
+
+
+[ref]: {{ site.scala3ref }}/new-types/dependent-function-types.html
+[ctx-fun]: {{ site.scala3ref }}/contextual/context-functions.html
diff --git a/_zh-cn/overviews/scala3-book/types-generics.md b/_zh-cn/overviews/scala3-book/types-generics.md
new file mode 100644
index 0000000000..cdea2a2c4c
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/types-generics.md
@@ -0,0 +1,91 @@
+---
+title: 泛型
+type: section
+description: This section introduces and demonstrates generics in Scala 3.
+language: zh-cn
+num: 50
+previous-page: types-inferred
+next-page: types-intersection
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+---
+
+
+泛型类(或 traits)把在方括号 `[...]` 中的类型作为_参数_进行调用。
+Scala 约定是使用单个字母(如 `A`)来命名这些类型参数。
+然后当需要时,该类型可以在类中用于方法实例参数,或返回类型:
+
+{% tabs stack class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+// here we declare the type parameter A
+// v
+class Stack[A] {
+ private var elements: List[A] = Nil
+ // ^
+ // Here we refer to the type parameter
+ // v
+ def push(x: A): Unit =
+ elements = elements.prepended(x)
+ def peek: A = elements.head
+ def pop(): A = {
+ val currentTop = peek
+ elements = elements.tail
+ currentTop
+ }
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+// here we declare the type parameter A
+// v
+class Stack[A]:
+ private var elements: List[A] = Nil
+ // ^
+ // Here we refer to the type parameter
+ // v
+ def push(x: A): Unit = { elements = elements.prepended(x) }
+ def peek: A = elements.head
+ def pop(): A =
+ val currentTop = peek
+ elements = elements.tail
+ currentTop
+```
+{% endtab %}
+{% endtabs %}
+
+`Stack` 类的这个实现采用任何类型作为参数。
+泛型的美妙之处在于您现在可以创建一个 `Stack[Int]`、`Stack[String]` 等,允许您将 `Stack` 的实现重复用于任意元素类型。
+
+这是创建和使用 `Stack[Int]` 的方式:
+
+{% tabs stack-usage class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+val stack = new Stack[Int]
+stack.push(1)
+stack.push(2)
+println(stack.pop()) // prints 2
+println(stack.pop()) // prints 1
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val stack = Stack[Int]
+stack.push(1)
+stack.push(2)
+println(stack.pop()) // prints 2
+println(stack.pop()) // prints 1
+```
+{% endtab %}
+{% endtabs %}
+
+> 有关如何用泛型类型表达可变的详细信息,请参阅[型变(Variance)部分][variance]。
+
+[variance]: {% link _zh-cn/overviews/scala3-book/types-variance.md %}
diff --git a/_zh-cn/overviews/scala3-book/types-inferred.md b/_zh-cn/overviews/scala3-book/types-inferred.md
new file mode 100644
index 0000000000..aa6d3faf18
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/types-inferred.md
@@ -0,0 +1,58 @@
+---
+title: 类型推断
+type: section
+description: This section introduces and demonstrates inferred types in Scala 3
+language: zh-cn
+num: 49
+previous-page: types-introduction
+next-page: types-generics
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+---
+
+
+与其他静态类型编程语言一样,在 Scala 中,您可以在创建新变量时_声明_类型:
+
+{% tabs xy %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val x: Int = 1
+val y: Double = 1
+```
+{% endtab %}
+{% endtabs %}
+
+在这些示例中,类型分别_明确地_声明为 `Int` 和 `Double` 。
+但是,在 Scala 中,您通常不必在定义值绑定器时声明类型:
+
+{% tabs abm %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = 1
+val b = List(1, 2, 3)
+val m = Map(1 -> "one", 2 -> "two")
+```
+{% endtab %}
+{% endtabs %}
+
+当你这样做时,Scala _推断_类型,如下面的 REPL 交互所示:
+
+{% tabs abm2 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+scala> val a = 1
+val a: Int = 1
+
+scala> val b = List(1, 2, 3)
+val b: List[Int] = List(1, 2, 3)
+
+scala> val m = Map(1 -> "one", 2 -> "two")
+val m: Map[Int, String] = Map(1 -> one, 2 -> two)
+```
+{% endtab %}
+{% endtabs %}
+
+事实上,大多数变量都是这样定义的,而 Scala 自动推断类型的能力是使它_感觉_像一种动态类型语言的一个特性。
diff --git a/_zh-cn/overviews/scala3-book/types-intersection.md b/_zh-cn/overviews/scala3-book/types-intersection.md
new file mode 100644
index 0000000000..db1d250a4c
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/types-intersection.md
@@ -0,0 +1,64 @@
+---
+title: 相交类型
+type: section
+description: This section introduces and demonstrates intersection types in Scala 3.
+language: zh-cn
+num: 51
+previous-page: types-generics
+next-page: types-union
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+---
+Scala 3 only
+
+用于类型,`&` 运算符创建一个所谓的_相交类型_。
+`A & B` 类型表示同时是 `A` 类型和 `B` 类型**两者**的值。
+例如,以下示例使用相交类型 `Resettable & Growable[String]`:
+
+{% tabs intersection-reset-grow %}
+{% tab 'Scala 3 Only' %}
+```scala
+trait Resettable:
+ def reset(): Unit
+
+trait Growable[A]:
+ def add(a: A): Unit
+
+def f(x: Resettable & Growable[String]): Unit =
+ x.reset()
+ x.add("first")
+```
+{% endtab %}
+{% endtabs %}
+
+在本例中的方法 `f` 中,参数 `x` 必须*同时*既是 `Resettable` 也是 `Growable[String]`。
+
+相交类型 `A & B` 的_成员_既有 `A` 的所有成员,也有 `B` 的所有成员。
+因此,如图所示,`Resettable & Growable[String]` 具有成员方法 `reset` 和 `add`。
+
+相交类型可用于_结构性_地描述需求。
+也就是说,在我们的示例 `f` 中,我们直接表示只要 `x` 是 `Resettable` 和 `Growable` 的子类型的任意值, 我们就感到满意。
+我们**不**需要创建一个_通用_的辅助 trait,如下所示:
+
+{% tabs normal-trait class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+trait Both[A] extends Resettable with Growable[A]
+def f(x: Both[String]): Unit
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+trait Both[A] extends Resettable, Growable[A]
+def f(x: Both[String]): Unit
+```
+{% endtab %}
+{% endtabs %}
+
+定义 `f` 的两种选择之间有一个重要区别:虽然两者都允许使用 `Both` 的实例调用 `f`,但只有前者允许传递属于 `Resettable` 和 `Growable[String]` 子类型的实例,后者 `Both[String]` _不允许_。
+
+> 请注意,`&` 是_可交换的_:`A & B` 与 `B & A` 的类型相同。
diff --git a/_zh-cn/overviews/scala3-book/types-introduction.md b/_zh-cn/overviews/scala3-book/types-introduction.md
new file mode 100644
index 0000000000..dfe1b6b790
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/types-introduction.md
@@ -0,0 +1,61 @@
+---
+title: 类型和类型系统
+type: chapter
+description: This chapter provides an introduction to Scala 3 types and the type system.
+language: zh-cn
+num: 48
+previous-page: fp-summary
+next-page: types-inferred
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+---
+
+
+Scala 是一种独特的语言,因为它是静态类型的,但通常_感觉_它灵活和动态。
+例如,由于类型推断,您可以编写这样的代码而无需显式指定变量类型:
+
+{% tabs hi %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = 1
+val b = 2.0
+val c = "Hi!"
+```
+{% endtab %}
+{% endtabs %}
+
+这使代码感觉是动态类型的。
+并且由于新特性,例如 Scala 3 中的 [联合类型][union-types],您还可以编写如下代码,非常简洁地表达出期望哪些值作为参数,哪些值作为返回的类型:
+
+{% tabs union-example %}
+{% tab 'Scala 3 Only' %}
+```scala
+def isTruthy(a: Boolean | Int | String): Boolean = ???
+def dogCatOrWhatever(): Dog | Plant | Car | Sun = ???
+```
+{% endtab %}
+{% endtabs %}
+
+正如例子所暗示的,当使用联合类型时,这些类型不必共享一个公共层次结构,您仍然可以接受它们作为参数或从方法中返回它们。
+
+如果您是应用程序开发人员,您将每天使用类型推断和每周使用泛型等功能。
+当您阅读 Scaladoc 中的类和方法时,您还需要对_可变的(variance)_有所了解。
+希望您会发现使用类型可以相当简单,而且使用类型可以为库开发人员提供了很多表达能力、灵活性和控制力。
+
+## 类型的好处
+
+静态类型的编程语言提供了许多好处,包括:
+
+- 帮助提供强大的 IDE 支持
+- 在编译时消除许多类的潜在错误
+- 协助重构
+- 提供强大的文档,因为它经过类型检查,所以不会过时
+
+## Scala 类型系统的特性介绍
+
+鉴于此简要介绍,以下部分将概述 Scala 类型系统的特性。
+
+[union-types]: {% link _zh-cn/overviews/scala3-book/types-union.md %}
diff --git a/_zh-cn/overviews/scala3-book/types-opaque-types.md b/_zh-cn/overviews/scala3-book/types-opaque-types.md
new file mode 100644
index 0000000000..c8ba8405f5
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/types-opaque-types.md
@@ -0,0 +1,160 @@
+---
+title: 不透明类型
+type: section
+description: This section introduces and demonstrates opaque types in Scala 3.
+language: zh-cn
+num: 55
+previous-page: types-variance
+next-page: types-structural
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+---
+
+
+Scala 3 _不透明类型别名_提供没有任何**开销**的类型抽象。
+
+## 抽象开销
+
+假设我们要定义一个提供数字算术运算的模块,这些数字由它们的对数表示。
+当涉及的数值非常大或接近于零时,使用对数有利于提高精度。
+
+把“常规”双精度值与存储为对数的值区分开来很重要,我们引入了一个类 `Logarithm`:
+
+```scala
+class Logarithm(protected val underlying: Double):
+ def toDouble: Double = math.exp(underlying)
+ def + (that: Logarithm): Logarithm =
+ // here we use the apply method on the companion
+ Logarithm(this.toDouble + that.toDouble)
+ def * (that: Logarithm): Logarithm =
+ new Logarithm(this.underlying + that.underlying)
+
+object Logarithm:
+ def apply(d: Double): Logarithm = new Logarithm(math.log(d))
+```
+
+伴生对象上的 apply 方法让我们可以创建 `Logarithm` 类型的值,我们可用如下方式使用:
+
+```scala
+val l2 = Logarithm(2.0)
+val l3 = Logarithm(3.0)
+println((l2 * l3).toDouble) // prints 6.0
+println((l2 + l3).toDouble) // prints 4.999...
+```
+
+虽然 `Logarithm` 类为以这种特殊对数形式存储的 `Double` 值提供了一个很好的抽象,但它带来了严重的性能开销:对于每一个数学运算,我们需要提取基础值,然后将其再次包装在一个 `Logarithm` 的新实例中。
+
+## 模块抽象
+
+让我们考虑另一种实现相同库的方法。
+这次我们没有将 `Logarithm` 定义为一个类,而是使用_类型别名_来定义它。
+首先,我们定义模块的抽象接口:
+
+```scala
+trait Logarithms:
+
+ type Logarithm
+
+ // operations on Logarithm
+ def add(x: Logarithm, y: Logarithm): Logarithm
+ def mul(x: Logarithm, y: Logarithm): Logarithm
+
+ // functions to convert between Double and Logarithm
+ def make(d: Double): Logarithm
+ def extract(x: Logarithm): Double
+
+ // extension methods to use `add` and `mul` as "methods" on Logarithm
+ extension (x: Logarithm)
+ def toDouble: Double = extract(x)
+ def + (y: Logarithm): Logarithm = add(x, y)
+ def * (y: Logarithm): Logarithm = mul(x, y)
+```
+
+现在,让我们通过说类型 `Logarithm` 等于 `Double` 来实现这个抽象接口:
+
+```scala
+object LogarithmsImpl extends Logarithms:
+
+ type Logarithm = Double
+
+ // operations on Logarithm
+ def add(x: Logarithm, y: Logarithm): Logarithm = make(x.toDouble + y.toDouble)
+ def mul(x: Logarithm, y: Logarithm): Logarithm = x + y
+
+ // functions to convert between Double and Logarithm
+ def make(d: Double): Logarithm = math.log(d)
+ def extract(x: Logarithm): Double = math.exp(x)
+```
+
+在 `LogarithmsImpl` 的实现中,等式 `Logarithm = Double` 允许我们实现各种方法。
+
+#### 暴露抽象
+
+但是,这种抽象有点暴露。
+我们必须确保_只_针对抽象接口 `Logarithms` 进行编程,并且永远不要直接使用 `LogarithmsImpl`。
+直接使用 `LogarithmsImpl` 会使等式 `Logarithm = Double` 对用户可见,用户可能会意外使用 `Double`,而实际上是需要 对数双精度。
+例如:
+
+```scala
+import LogarithmsImpl.*
+val l: Logarithm = make(1.0)
+val d: Double = l // type checks AND leaks the equality!
+```
+
+必须将模块分离为抽象接口和实现可能很有用,但只为了隐藏 `Logarithm` 的实现细节,就需要付出很多努力。
+针对抽象模块 `Logarithm` 进行编程可能非常乏味,并且通常需要使用像路径依赖类型这样的高级特性,如下例所示:
+
+```scala
+def someComputation(L: Logarithms)(init: L.Logarithm): L.Logarithm = ...
+```
+
+#### 装箱的开销
+
+类型抽象,例如 `type Logarithm` [抹去](https://www.scala-lang.org/files/archive/spec/2.13/03-types.html#type-erasure) 到它们的界限(在我们的例子中是 `Any`)。
+也就是说,虽然我们不需要手动包装和解包 `Double` 值,但仍然会有一些与装箱原始类型 `Double` 相关的装箱开销。
+
+## 不透明类型
+
+我们可以简单地使用 Scala 3 中的不透明类型来实现类似的效果,而不是手动将我们的 `Logarithms` 组件拆分为抽象部分和具体实现:
+
+```scala
+object Logarithms:
+//vvvvvv this is the important difference!
+ opaque type Logarithm = Double
+
+ object Logarithm:
+ def apply(d: Double): Logarithm = math.log(d)
+
+ extension (x: Logarithm)
+ def toDouble: Double = math.exp(x)
+ def + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y))
+ def * (y: Logarithm): Logarithm = x + y
+```
+
+`Logarithm` 与 `Double` 相同的事实仅在定义 `Logarithm` 的范围内已知,在上面的示例中对应于对象 `Logarithms`。
+类型相等 `Logarithm = Double` 可用于实现方法(如 `*` 和 `toDouble`)。
+
+然而,在模块之外, `Logarithm` 类型是完全封装的,或者说是“不透明的”。 对于 `Logarithm` 的用户来说,不可能发现 `Logarithm` 实际上是作为 `Double` 实现的:
+
+```scala
+import Logarithms.*
+val l2 = Logarithm(2.0)
+val l3 = Logarithm(3.0)
+println((l2 * l3).toDouble) // prints 6.0
+println((l2 + l3).toDouble) // prints 4.999...
+
+val d: Double = l2 // ERROR: Found Logarithm required Double
+```
+
+尽管我们抽象了 `Logarithm`,但抽象是免费的:
+由于只有一种实现,在运行时对于像 `Double` 这样的原始类型将_没有装箱开销_。
+
+### 不透明类型总结
+
+不透明类型提供了对实现细节的合理抽象,而不会增加性能开销。
+如上图所示,不透明类型使用起来很方便,并且与 [扩展方法][extension] 功能很好地集成在一起。
+
+[extension]: {% link _zh-cn/overviews/scala3-book/ca-extension-methods.md %}
diff --git a/_zh-cn/overviews/scala3-book/types-others.md b/_zh-cn/overviews/scala3-book/types-others.md
new file mode 100644
index 0000000000..eec6faada8
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/types-others.md
@@ -0,0 +1,32 @@
+---
+title: 其他类型
+type: section
+description: This section mentions other advanced types in Scala 3.
+language: zh-cn
+num: 58
+previous-page: types-dependent-function
+next-page: ca-contextual-abstractions-intro
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+---
+
+
+Scala还有其他几种高级类型,本书中没有介绍,包括:
+
+- 类型 lambdas
+- 匹配类型
+- 存在类型
+- 高等类型
+- 单例类型
+- 细化类型
+- 种类多态性
+
+有关这些类型的更多详细信息,请参阅[参考文档][reference]。
+有关单例类型参见 Scala 3 规格中的[字面量类型](https://scala-lang.org/files/archive/spec/3.4/03-types.html#literal-types) 一节,
+细化类型参见[细化类型](https://scala-lang.org/files/archive/spec/3.4/03-types.html) 一节。
+
+
+[reference]: {{ site.scala3ref }}/overview.html
diff --git a/_zh-cn/overviews/scala3-book/types-structural.md b/_zh-cn/overviews/scala3-book/types-structural.md
new file mode 100644
index 0000000000..4c12a87901
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/types-structural.md
@@ -0,0 +1,110 @@
+---
+title: 结构化类型
+type: section
+description: This section introduces and demonstrates structural types in Scala 3.
+language: zh-cn
+num: 56
+previous-page: types-opaque-types
+next-page: types-dependent-function
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+---
+
+
+{% comment %}
+NOTE: It would be nice to simplify this more.
+{% endcomment %}
+
+
+一些用例,例如建模数据库访问,在静态类型语言中比在动态类型语言中更尴尬。
+使用动态类型语言,很自然地将行建模为记录或对象,并使用简单的点表示法选择条目,例如 `row.columnName`。
+
+要在静态类型语言中获得相同的体验,需要为数据库操作产生的每个可能的行定义一个类——包括连接和投影产生的行——并设置一个方案以在行和代表它的类之间进行映射。
+
+这需要大量样板文件,这导致开发人员将静态类型的优势换成更简单的方案,其中列名表示为字符串并传递给其他运算符,例如 `row.select("columnName")`。
+这种方法即便放弃了静态类型的优点,也仍然不如动态类型的版本自然。
+
+在您希望在动态上下文中支持简单的点表示法而又不失静态类型优势的情况下,结构化类型会有所帮助。
+它们允许开发人员使用点表示法并配置应如何解析字段和方法。
+
+## 例子
+
+这是一个结构化类型 `Person` 的示例:
+
+```scala
+class Record(elems: (String, Any)*) extends Selectable:
+ private val fields = elems.toMap
+ def selectDynamic(name: String): Any = fields(name)
+
+type Person = Record {
+ val name: String
+ val age: Int
+}
+```
+
+`Person` 类型在其父类型 `Record` 中添加了一个_精细的改进_,它定义了 `name` 和 `age` 字段。
+我们精细的改进是_构造的_,因为 `name` 和 `age` 没有在父类型中定义。
+但是它们仍然作为 `Person` 类的成员存在。
+例如,以下程序将打印 `"Emma is 42 years old."`:
+
+```scala
+val person = Record(
+ "name" -> "Emma",
+ "age" -> 42
+).asInstanceOf[Person]
+
+println(s"${person.name} is ${person.age} years old.")
+```
+
+本例中的父类型 `Record` 是一个通用类,可以在其 `elems` 参数中表示任意记录。
+该参数是一个序列,该序列的元素是 `String` 类型的标签和 `Any` 类型的值组成的对。
+当您将 `Person` 创建为 `Record` 时,您必须使用类型转换断言该记录定义了正确类型的正确字段。
+`Record` 本身的类型太弱了,所以编译器在没有用户帮助的情况下无法知道这一点。
+实际上,结构化类型与其底层通用表示之间的连接很可能由数据库层完成,因此最终用户没必要关注。
+
+`Record` 扩展了标记 trait `scala.Selectable` 并定义了一个方法 `selectDynamic`,它将字段名称映射到其值。
+通过调用此方法来选择结构化类型成员。
+Scala 编译器把选择 `person.name` 和 `person.age` 翻译成:
+
+```scala
+person.selectDynamic("name").asInstanceOf[String]
+person.selectDynamic("age").asInstanceOf[Int]
+```
+
+## 第二个例子
+
+为了强化您刚刚看到的内容,这里有另一个名为 `Book` 的结构化类型,它表示您可能从数据库中读取的一本书:
+
+```scala
+type Book = Record {
+ val title: String
+ val author: String
+ val year: Int
+ val rating: Double
+}
+```
+
+与 `Person` 一样,这是创建 `Book` 实例的方式:
+
+```scala
+val book = Record(
+ "title" -> "The Catcher in the Rye",
+ "author" -> "J. D. Salinger",
+ "year" -> 1951,
+ "rating" -> 4.5
+).asInstanceOf[Book]
+```
+
+## 可选类
+
+除了 `selectDynamic` 之外,`Selectable`类有时还会定义 `applyDynamic` 方法。
+然后可以使用它来翻译是函数调用的结构成员。
+因此,如果 `a` 是 `Selectable` 的一个实例,则像 `a.f(b, c)` 这样的结构调用将转换为:
+
+```scala
+a.applyDynamic("f")(b, c)
+```
+
diff --git a/_zh-cn/overviews/scala3-book/types-union.md b/_zh-cn/overviews/scala3-book/types-union.md
new file mode 100644
index 0000000000..4e1ca79242
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/types-union.md
@@ -0,0 +1,111 @@
+---
+title: 联合类型
+type: section
+description: This section introduces and demonstrates union types in Scala 3.
+language: zh-cn
+num: 52
+previous-page: types-intersection
+next-page: types-adts-gadts
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+scala3: true
+versionSpecific: true
+---
+
+
+用于类型,`|` 操作符创建一个所谓的_联合类型_。
+类型 `A | B` 表示**要么是** `A` 类型的值,**要么是** `B` 类型的值。
+
+在下面的例子中,`help` 方法接受一个名为 `id` 的联合类型 `Username | Password`,可以是 `Useername` 或 `Password`:
+
+```scala
+case class Username(name: String)
+case class Password(hash: Hash)
+
+def help(id: Username | Password) =
+ val user = id match
+ case Username(name) => lookupName(name)
+ case Password(hash) => lookupPassword(hash)
+ // more code here ...
+```
+
+我们通过使用模式匹配区分二者,从而实现 `help` 方法。
+
+此代码是一种灵活且类型安全的解决方案。
+如果您尝试传入`Useername` 或 `Password` 以外的类型,编译器会将其标记为错误:
+
+```scala
+help("hi") // error: Found: ("hi" : String)
+ // Required: Username | Password
+```
+
+如果您尝试将 `case` 添加到与 `Username` 或 `Password` 类型不匹配的 `match` 表达式中,也会出现错误:
+
+```scala
+case 1.0 => ??? // ERROR: this line won’t compile
+```
+
+### 联合类型的替代方案
+
+如图所示,联合类型可用于替代几种不同的类型,而不要求这些类型是定制类层次结构的一部分,也不需要显式包装。
+
+#### 预先规划类层次结构
+
+其他语言需要预先规划类层次结构,如下例所示:
+
+{% tabs pre-planning %}
+{% tab 'Scala 2 and 3' %}
+```scala
+trait UsernameOrPassword
+case class Username(name: String) extends UsernameOrPassword
+case class Password(hash: Hash) extends UsernameOrPassword
+def help(id: UsernameOrPassword) = ...
+```
+{% endtab %}
+{% endtabs %}
+
+预先计划不能很好地扩展,例如,API 用户的需求可能无法预见。
+此外,使用诸如 `UsernameOrPassword` 之类的标记 trait 使类型层次结构混乱也会使代码更难阅读。
+
+#### 标记联合
+
+另一种选择是定义一个单独的枚举类型,如:
+
+```scala
+enum UsernameOrPassword:
+ case IsUsername(u: Username)
+ case IsPassword(p: Password)
+```
+
+枚举 `UsernameOrPassword` 表示 `Username` 和 `Password` 的 _标记_联合。
+但是,这种联合建模方式需要_显式包装和展开_,例如,`Username` **不是** `UsernameOrPassword` 的子类型。
+
+### 联合类型推断
+
+_仅当_明确给出这种类型时,编译器才会将联合类型分配给表达式。
+例如,给定这些值:
+
+```scala
+val name = Username("Eve") // name: Username = Username(Eve)
+val password = Password(123) // password: Password = Password(123)
+```
+
+这个 REPL 示例展示了在将变量绑定到 `if`/`else` 表达式的结果时如何使用联合类型:
+
+````
+scala> val a = if (true) name else password
+val a: Object = Username(Eve)
+
+scala> val b: Password | Username = if (true) name else password
+val b: Password | Username = Username(Eve)
+````
+
+`a` 的类型是 `Object`,它是 `Username` 和 `Password` 的超类型,但不是二者*最小*的超类型 `Password | Username`。
+如果你想要最小的超类型,你必须明确地给出它,就像对 `b` 所做的那样。
+
+> 联合类型是交集类型的对偶。
+> 和具有交集类型的 `&` 一样,`|` 也是可交换的:`A | B` 与 `B | A` 是同一类型。
+
diff --git a/_zh-cn/overviews/scala3-book/types-variance.md b/_zh-cn/overviews/scala3-book/types-variance.md
new file mode 100644
index 0000000000..3c774c1d52
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/types-variance.md
@@ -0,0 +1,250 @@
+---
+title: 型变
+type: section
+description: This section introduces and demonstrates variance in Scala 3.
+language: zh-cn
+num: 54
+previous-page: types-adts-gadts
+next-page: types-opaque-types
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+---
+
+
+类型参数_型变_控制参数化类型(如类或 traits)的子类型。
+
+为了解释型变,让我们假设以下类型定义:
+
+{% tabs types-variance-1 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+trait Item { def productNumber: String }
+trait Buyable extends Item { def price: Int }
+trait Book extends Buyable { def isbn: String }
+```
+{% endtab %}
+{% endtabs %}
+
+我们还假设以下参数化类型:
+
+{% tabs types-variance-2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=types-variance-2 %}
+```scala
+// an example of an invariant type
+trait Pipeline[T] {
+ def process(t: T): T
+}
+
+// an example of a covariant type
+trait Producer[+T] {
+ def make: T
+}
+
+// an example of a contravariant type
+trait Consumer[-T] {
+ def take(t: T): Unit
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=types-variance-2 %}
+```scala
+// an example of an invariant type
+trait Pipeline[T]:
+ def process(t: T): T
+
+// an example of a covariant type
+trait Producer[+T]:
+ def make: T
+
+// an example of a contravariant type
+trait Consumer[-T]:
+ def take(t: T): Unit
+```
+{% endtab %}
+{% endtabs %}
+
+一般来说,型变有三种模式:
+
+- **不变的**---默认值,写成 `Pipeline[T]`
+- **协变**---用`+`注释,例如 `Producer[+T]`
+- **逆变**---用`-`注释,如 `Consumer[-T]`
+
+我们现在将详细介绍此注释的含义以及我们使用它的原因。
+
+### 不变类型
+
+默认情况下,像 `Pipeline` 这样的类型在它们的类型参数中是不变的(本例中是 `T`)。
+这意味着像 `Pipeline[Item]`、`Pipeline[Buyable]` 和 `Pipeline[Book]` 这样的类型彼此之间_没有子类型关系_。
+
+理所当然地!假设以下方法使用两个类型为`Pipeline[Buyable]` 的值,并根据价格将其参数 `b` 传递给其中一个:
+
+{% tabs types-variance-3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=types-variance-3 %}
+```scala
+def oneOf(
+ p1: Pipeline[Buyable],
+ p2: Pipeline[Buyable],
+ b: Buyable
+): Buyable = {
+ val b1 = p1.process(b)
+ val b2 = p2.process(b)
+ if (b1.price < b2.price)
+ b1
+ else
+ b2
+ }
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=types-variance-3 %}
+```scala
+def oneOf(
+ p1: Pipeline[Buyable],
+ p2: Pipeline[Buyable],
+ b: Buyable
+): Buyable =
+ val b1 = p1.process(b)
+ val b2 = p2.process(b)
+ if b1.price < b2.price then b1 else b2
+```
+{% endtab %}
+{% endtabs %}
+
+现在,回想一下,我们的类型之间存在以下_子类型关系_:
+
+{% tabs types-variance-4 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+Book <: Buyable <: Item
+```
+{% endtab %}
+{% endtabs %}
+
+我们不能将 `Pipeline[Book]` 传递给 `oneOf` 方法,因为在其实现中,我们调用的 `p1` 和 `p2` 是 `Buyable` 类型的值。
+`Pipeline[Book]` 需要的是 `Book`,这可能会导致运行时错误。
+
+我们不能传递一个 `Pipeline[Item]` 因为在它上面调用 `process` 只会保证返回一个 `Item`;但是,我们应该返回一个 `Buyable` 。
+
+#### 为什么是不变的?
+
+事实上,`Pipeline` 类型需要是不变的,因为它使用它的类型参数 `T` _既_作为参数类型,_又_作为返回类型。
+出于同样的原因,Scala 集合库中的某些类型——例如 `Array` 或 `Set` —— 也是_不变的_。
+
+### 协变类型
+
+与不变的 `Pipeline` 相比,`Producer` 类型通过在类型参数前面加上 `+` 前缀被标记为 **协变**。
+这是有效的,因为类型参数仅用于_返回的位置_。
+
+将其标记为协变意味着当需要 `Producer[Buyable]` 时,我们可以传递(或返回)一个 `Producer[Book]`。
+事实上,这是合理的。 `Producer[Buyable].make` 的类型只承诺_返回_ `Buyable`。
+作为 `make` 的调用者,我们乐意接受作为 `Buyable` 的子类型的 `Book` 类型,---也就是说,它_至少_是一个 `Buyable`。
+
+以下示例说明了这一点,其中函数 `makeTwo` 需要一个 `Producer[Buyable]`:
+
+{% tabs types-variance-5 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def makeTwo(p: Producer[Buyable]): Int =
+ p.make.price + p.make.price
+```
+{% endtab %}
+{% endtabs %}
+
+通过书籍制作人是完全可以的:
+
+{% tabs types-variance-6 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val bookProducer: Producer[Book] = ???
+makeTwo(bookProducer)
+```
+{% endtab %}
+{% endtabs %}
+
+在 `makeTwo` 中调用 `price` 对书籍仍然有效。
+
+#### 不可变容器的协变类型
+
+在处理不可变容器时,您会经常遇到协变类型,例如可以在标准库中找到的那些(例如 `List`、`Seq`、`Vector` 等)。
+
+例如,`List` 和 `Vector` 大致定义为:
+
+{% tabs types-variance-7 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+class List[+A] ...
+class Vector[+A] ...
+```
+{% endtab %}
+{% endtabs %}
+
+这样,您可以在需要 `List[Buyable]` 的地方使用 `List[Book]`。
+这在直觉上也是有道理的:如果您期望收藏可以购买的东西,那么给您收藏书籍应该没问题。
+在我们的示例中,它们有一个额外的 ISBN 方法,但您可以随意忽略这些额外的功能。
+
+### 逆变类型
+
+与标记为协变的类型 `Producer` 相比,类型 `Consumer` 通过在类型参数前加上 `-` 来标记为**逆变**。
+这是有效的,因为类型参数仅用于_参数位置_。
+
+将其标记为逆变意味着如果我们想要 `Consumer[Buyable]` 时,可以传递(或返回) `Consumer[Item]`。
+也就是说,我们有子类型关系`Consumer[Item] <: Consumer[Buyable]`。
+请记住,对于类型 `Producer`,情况正好相反,我们有 `Producer[Buyable] <: Producer[Item]`。
+
+事实上,这是合理的。 `Consumer[Item].take` 方法接受一个 `Item`。
+作为 `take` 的调用者,我们还可以提供 `Buyable`,它会被 `Consumer[Item]` 愉快地接受,因为 `Buyable` 是 `Item` 的一个子类型——也就是说,它_至少_是 `Item` 。
+
+#### 消费者的逆变类型
+
+逆变类型比协变类型少得多。
+在我们的示例中,您可以将它们视为“消费者”。你可能来的最重要的类型标记为逆变的 cross 是函数之一:
+
+{% tabs types-variance-8 class=tabs-scala-version %}
+{% tab 'Scala 2' for=types-variance-8 %}
+```scala
+trait Function[-A, +B] {
+ def apply(a: A): B
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' for=types-variance-8 %}
+```scala
+trait Function[-A, +B]:
+ def apply(a: A): B
+```
+{% endtab %}
+{% endtabs %}
+
+它的参数类型 `A` 被标记为逆变的 `A` ——它消费 `A` 类型的值。
+相反,它的结果类型 `B` 被标记为协变——它产生 `B` 类型的值。
+
+以下是一些示例,这些示例说明了由函数上可变注释引起的子类型关系:
+
+{% tabs types-variance-9 %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val f: Function[Buyable, Buyable] = b => b
+
+// OK to return a Buyable where a Item is expected
+val g: Function[Buyable, Item] = f
+
+// OK to provide a Book where a Buyable is expected
+val h: Function[Book, Buyable] = f
+```
+{% endtab %}
+{% endtabs %}
+
+## 概括
+
+在本节中,我们遇到了三种不同的方差:
+
+- **生产者**通常是协变的,并用 `+` 标记它们的类型参数。
+ 这也适用于不可变集合。
+- **消费者**通常是逆变的,并用 `-` 标记他们的类型参数。
+- **既是**生产者**又**是消费者的类型必须是不变的,并且不需要在其类型参数上进行任何标记。
+ 像 `Array` 这样的可变集合就属于这一类。
diff --git a/_zh-cn/overviews/scala3-book/where-next.md b/_zh-cn/overviews/scala3-book/where-next.md
new file mode 100644
index 0000000000..66c3afe639
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/where-next.md
@@ -0,0 +1,20 @@
+---
+title: 下一步去哪
+type: chapter
+description: Where to go next after reading the Scala Book
+language: zh-cn
+num: 76
+previous-page: scala-for-python-devs
+next-page:
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+---
+
+我们希望你能喜欢 Scala 编程语言的介绍,我们也希望你能分享一些这门语言的美丽之处。
+
+如果你继续用 Scala 工作,你可以在我们[引导和概览部分][overviews]发现更多细节。
+
+[overviews]: {% link _overviews/index.md %}
diff --git a/_zh-cn/overviews/scala3-book/why-scala-3.md b/_zh-cn/overviews/scala3-book/why-scala-3.md
new file mode 100644
index 0000000000..b07b567fe7
--- /dev/null
+++ b/_zh-cn/overviews/scala3-book/why-scala-3.md
@@ -0,0 +1,504 @@
+---
+title: 为什么是 Scala 3 ?
+type: chapter
+description: This page describes the benefits of the Scala 3 programming language.
+language: zh-cn
+num: 3
+previous-page: scala-features
+next-page: taste-intro
+
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+layout: multipage-overview
+permalink: "/zh-cn/scala3/book/:title.html"
+---
+
+{% comment %}
+TODO: Is “Scala 3 Benefits” a better title?
+NOTE: Could mention “grammar” as a way of showing that Scala isn’t a large language; see this slide: https://www.slideshare.net/Odersky/preparing-for-scala-3#13
+{% endcomment %}
+
+使用 Scala 有很多好处,特别是 Scala 3。
+很难列出 Scala 的每一个好处,但“前十名”列表可能看起来像这样:
+
+1. Scala 融合了函数式编程(FP)和面向对象编程(OOP)
+2. Scala 是静态类型的语言,但通常感觉像一种动态类型语言。
+3. Scala 的语法简洁,但仍然可读;它通常被称为 _易于表达_
+4. Scala 2 中的 _Implicits_ 是一个定义特性,它们在 Scala 3 中得到了改进和简化。
+5. Scala 与 Java 无缝集成,因此您可以创建混合了 Scala 和 Java 代码的项目,Scala 代码可以轻松使用成千上万个现有的 Java 库
+6. Scala 可以在服务器上使用,通过 [Scala.js](https://www.scala-js.org), Scala 也可以在浏览器中使用
+7. Scala 标准库具有数十种预构建的函数式方法,可节省您的时间,并大大减少编写自定义 `for` 循环和算法的需要
+8. Scala 内置了“最佳实践”,它支持不可变性,匿名函数,高阶函数,模式匹配,默认情况下无法扩展的类等
+9. Scala 生态系统提供世界上最现代化的 FP 库
+10. 强类型式系统
+
+## 1) FP/OOP 融合
+
+Scala 比任何其他语言都更支持 FP 和 OOP 范式的融合。
+正如 Martin Odersky 所说,Scala 的本质是在类型化环境中融合了函数式和面向对象编程,具有:
+
+- 函数用于编写逻辑 (局部)
+- 对象用于构建模块化 (整体)
+
+模块化的一些最佳示例可能是标准库中的类。
+例如,`List` 被定义为一个类---从技术上讲,它是一个抽象类---并且像这样创建了一个新实例:
+
+{% tabs list %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val x = List(1, 2, 3)
+```
+{% endtab %}
+{% endtabs %}
+
+但是,在程序员看来是一个简单的 `List` 实际上是由几种特殊类型的组合构建的,包括名为`Iterable`, `Seq`, 和 `LinearSeq` 的 traits。
+这些类型同样由其他小型的模块化代码单元组成。
+
+除了从一系列模块化 traits 构建/cases像 `List` 这样的类型之外,`List` API还包含数十种其他方法,其中许多是高阶函数:
+
+{% tabs list-methods %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val xs = List(1, 2, 3, 4, 5)
+
+xs.map(_ + 1) // List(2, 3, 4, 5, 6)
+xs.filter(_ < 3) // List(1, 2)
+xs.find(_ > 3) // Some(4)
+xs.takeWhile(_ < 3) // List(1, 2)
+```
+{% endtab %}
+{% endtabs %}
+
+在这些示例中,无法修改列表中的值。
+`List` 类是不可变的,因此所有这些方法都返回新值,如每个注释中的数据所示。
+
+## 2) 动态的感觉
+
+Scala的 _类型推断_ 经常使语言感觉是动态类型的,即使它是静态类型的。
+对于变量声明,情况确实如此:
+
+{% tabs dynamic %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = 1
+val b = "Hello, world"
+val c = List(1,2,3,4,5)
+val stuff = ("fish", 42, 1_234.5)
+```
+{% endtab %}
+{% endtabs %}
+
+当把匿名函数传递给高阶函数时,情况也是如此:
+
+{% tabs dynamic-hof %}
+{% tab 'Scala 2 and 3' %}
+```scala
+list.filter(_ < 4)
+list.map(_ * 2)
+list.filter(_ < 4)
+ .map(_ * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+还有定义方法的时候:
+
+{% tabs list-method %}
+{% tab 'Scala 2 and 3' %}
+```scala
+def add(a: Int, b: Int) = a + b
+```
+{% endtab %}
+{% endtabs %}
+
+这在Scala 3中比以往任何时候都更加真实,例如在使用[union types][union-types] 时:
+
+{% tabs union %}
+{% tab 'Scala 3 Only' %}
+```scala
+// union type parameter
+def help(id: Username | Password) =
+ val user = id match
+ case Username(name) => lookupName(name)
+ case Password(hash) => lookupPassword(hash)
+ // more code here ...
+
+// union type value
+val b: Password | Username = if (true) name else password
+```
+{% endtab %}
+{% endtabs %}
+
+## 3) 简洁的语法
+
+Scala是一种 low ceremony,“简洁但仍然可读”的语言。例如,变量声明是简洁的:
+
+{% tabs concise %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = 1
+val b = "Hello, world"
+val c = List(1,2,3)
+```
+{% endtab %}
+{% endtabs %}
+
+创建类型如traits, 类和枚举都很简洁:
+
+{% tabs enum %}
+{% tab 'Scala 3 Only' %}
+```scala
+trait Tail:
+ def wagTail(): Unit
+ def stopTail(): Unit
+
+enum Topping:
+ case Cheese, Pepperoni, Sausage, Mushrooms, Onions
+
+class Dog extends Animal, Tail, Legs, RubberyNose
+
+case class Person(
+ firstName: String,
+ lastName: String,
+ age: Int
+)
+```
+{% endtab %}
+{% endtabs %}
+
+简洁的高阶函数:
+
+{% tabs list-hof %}
+{% tab 'Scala 2 and 3' %}
+```scala
+list.filter(_ < 4)
+list.map(_ * 2)
+```
+{% endtab %}
+{% endtabs %}
+
+所有这些表达方式以及更多表达方式都很简洁,并且仍然非常易读:我们称之为 _富有表现力_。
+
+## 4) 隐式,简化
+
+Scala 2 中的隐式是一个主要明显的设计特征。
+它们代表了抽象上下文的基本方式,具有服务于各种用例的统一范式,其中包括:
+
+- 实现 [type classes]({% link _zh-cn/overviews/scala3-book/ca-type-classes.md %})
+- 建立背景
+- 依赖注入
+- 表达能力
+
+从那以后,其他语言也采用了类似的概念,所有这些都是 _术语推断_ 核心思想的变体:给定一个类型,编译器合成一个具有该类型的“规范”术语。
+
+虽然隐式是 Scala 2 中的一个定义特性,但它们的设计在 Scala 3 中得到了极大的改进:
+
+- 定义“given”值的方法只有一种
+- 只有一种方法可以引入隐式参数和参数
+- 有一种单独的方式来导入 givens,不允许它们隐藏在正常导入的海洋中
+- 只有一种定义隐式转换的方法,它被清楚地标记为这样,并且不需要特殊的语法
+
+这些变化的好处包括:
+
+- 新设计避免了特性交叉,使语言更加一致
+- 它使隐式更容易学习和不容易滥用
+- 它极大地提高了 95% 使用隐式的 Scala 程序的清晰度
+- 它有可能以一种易于理解和友好的原则方式进行术语推断
+
+这些功能在其他部分有详细描述,因此请参阅 [上下文抽象介绍][context] 和 [`given` 和 `using` 子句][given] 部分了解更多详细信息。
+
+## 5) 与 Java 无缝集成
+
+Scala/Java 交互在许多方面都是无缝的。
+例如:
+
+- 您可以使用 Scala 项目中可用的所有数千个 Java 库
+- Scala `String` 本质上是 Java `String`,添加了附加功能
+- Scala 无缝使用 Java 中 *java.time._* 包中的日期/时间类
+
+您还可以在 Scala 中使用 Java 集合类,并为它们提供更多功能,Scala 包含方法,因此您可以将它们转换为 Scala 集合。
+
+虽然几乎所有交互都是无缝的,但[“与 Java 交互”一章][java] 演示了如何更好地结合使用某些功能,包括如何使用:
+
+- Scala 中的 Java 集合
+- Scala 中的 Java `Optional`
+- Scala 中的 Java 接口
+- Java 中的 Scala 集合
+- Java 中的 Scala `Option`
+- Java 中的 Scala traits
+- 在 Java 代码中引发异常的 Scala 方法
+- Java 中的 Scala 可变参数
+
+有关这些功能的更多详细信息,请参见该章。
+
+## 6) 客户 &服务器
+
+Scala 可以通过非常棒的框架在服务器端使用:
+
+- [Play Framework](https://www.playframework.com) 可让您构建高度可扩展的服务器端应用程序和微服务
+- [Akka Actors](https://akka.io) 让你使用actor模型大大简化分布式和并发软件应用程序
+
+Scala 也可以通过 [Scala.js 项目](https://www.scala-js.org) 在浏览器中使用,它是 JavaScript 的类型安全替代品。
+Scala.js 生态系统 [有几十个库](https://www.scala-js.org/libraries) 让您可以在浏览器中使用 React、Angular、jQuery 和许多其他 JavaScript 和 Scala 库。
+
+除了这些工具之外,[Scala Native](https://github.com/scala-native/scala-native) 项目“是一个优化的提前编译器和专为 Scala 设计的轻量级托管运行时”。它允许您使用纯 Scala 代码构建“系统”风格的二进制可执行应用程序,还允许您使用较低级别的原语。
+
+## 7) 标准库方法
+
+您将很少需要再次编写自定义的 `for` 循环,因为 Scala 标准库中的数十种预构建函数方法既可以节省您的时间,又有助于使代码在不同应用程序之间更加一致。
+
+下面的例子展示了一些内置的集合方法,除此之外还有很多。
+虽然这些都使用 `List` 类,但相同的方法适用于其他集合类,例如 `Seq`、`Vector`、`LazyList`、`Set`、`Map`、`Array` 和 `ArrayBuffer`。
+
+这里有些例子:
+
+{% tabs list-more %}
+{% tab 'Scala 2 and 3' %}
+```scala
+List.range(1, 3) // List(1, 2)
+List.range(start = 1, end = 6, step = 2) // List(1, 3, 5)
+List.fill(3)("foo") // List(foo, foo, foo)
+List.tabulate(3)(n => n * n) // List(0, 1, 4)
+List.tabulate(4)(n => n * n) // List(0, 1, 4, 9)
+
+val a = List(10, 20, 30, 40, 10) // List(10, 20, 30, 40, 10)
+a.distinct // List(10, 20, 30, 40)
+a.drop(2) // List(30, 40, 10)
+a.dropRight(2) // List(10, 20, 30)
+a.dropWhile(_ < 25) // List(30, 40, 10)
+a.filter(_ < 25) // List(10, 20, 10)
+a.filter(_ > 100) // List()
+a.find(_ > 20) // Some(30)
+a.head // 10
+a.headOption // Some(10)
+a.init // List(10, 20, 30, 40)
+a.intersect(List(19,20,21)) // List(20)
+a.last // 10
+a.lastOption // Some(10)
+a.map(_ * 2) // List(20, 40, 60, 80, 20)
+a.slice(2, 4) // List(30, 40)
+a.tail // List(20, 30, 40, 10)
+a.take(3) // List(10, 20, 30)
+a.takeRight(2) // List(40, 10)
+a.takeWhile(_ < 30) // List(10, 20)
+a.filter(_ < 30).map(_ * 10) // List(100, 200, 100)
+
+val fruits = List("apple", "pear")
+fruits.map(_.toUpperCase) // List(APPLE, PEAR)
+fruits.flatMap(_.toUpperCase) // List(A, P, P, L, E, P, E, A, R)
+
+val nums = List(10, 5, 8, 1, 7)
+nums.sorted // List(1, 5, 7, 8, 10)
+nums.sortWith(_ < _) // List(1, 5, 7, 8, 10)
+nums.sortWith(_ > _) // List(10, 8, 7, 5, 1)
+```
+{% endtab %}
+{% endtabs %}
+
+## 8) 内置最佳实践
+
+Scala 习语以多种方式鼓励最佳实践。
+对于不可变性,我们鼓励您创建不可变的 `val` 声明:
+
+{% tabs val %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val a = 1 // 不可变变量
+```
+{% endtab %}
+{% endtabs %}
+
+还鼓励您使用不可变集合类,例如 `List` 和 `Map`:
+
+{% tabs list-map %}
+{% tab 'Scala 2 and 3' %}
+```scala
+val b = List(1,2,3) // List 是不可变的
+val c = Map(1 -> "one") // Map 是不可变的
+```
+{% endtab %}
+{% endtabs %}
+
+样例类主要用于 [领域建模]({% link _zh-cn/overviews/scala3-book/domain-modeling-intro.md %}),它们的参数是不可变的:
+
+{% tabs case-class %}
+{% tab 'Scala 2 and 3' %}
+```scala
+case class Person(name: String)
+val p = Person("Michael Scott")
+p.name // Michael Scott
+p.name = "Joe" // 编译器错误(重新分配给 val 名称)
+```
+{% endtab %}
+{% endtabs %}
+
+如上一节所示,Scala 集合类支持高阶函数,您可以将方法(未显示)和匿名函数传递给它们:
+
+{% tabs higher-order %}
+{% tab 'Scala 2 and 3' %}
+```scala
+a.dropWhile(_ < 25)
+a.filter(_ < 25)
+a.takeWhile(_ < 30)
+a.filter(_ < 30).map(_ * 10)
+nums.sortWith(_ < _)
+nums.sortWith(_ > _)
+```
+{% endtab %}
+{% endtabs %}
+
+`match` 表达式让您可以使用模式匹配,它们确实是返回值的 _表达式_:
+
+{% tabs match class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+val numAsString = i match {
+ case 1 | 3 | 5 | 7 | 9 => "odd"
+ case 2 | 4 | 6 | 8 | 10 => "even"
+ case _ => "too big"
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+val numAsString = i match
+ case 1 | 3 | 5 | 7 | 9 => "odd"
+ case 2 | 4 | 6 | 8 | 10 => "even"
+ case _ => "too big"
+```
+{% endtab %}
+{% endtabs %}
+
+因为它们可以返回值,所以它们经常被用作方法的主体:
+
+{% tabs match-body class=tabs-scala-version %}
+{% tab 'Scala 2' %}
+```scala
+def isTruthy(a: Matchable) = a match {
+ case 0 | "" => false
+ case _ => true
+}
+```
+{% endtab %}
+
+{% tab 'Scala 3' %}
+```scala
+def isTruthy(a: Matchable) = a match
+ case 0 | "" => false
+ case _ => true
+```
+{% endtab %}
+{% endtabs %}
+
+## 9) 生态系统库
+
+用于函数式编程的 Scala 库,如 [Cats](https://typelevel.org/cats) 和 [Zio](https://zio.dev) 是 FP 社区中的前沿库。
+所有流行语,如高性能、类型安全、并发、异步、资源安全、可测试、函数式、模块化、二进制兼容、高效、副作用/有副作用等,都可以用于这些库。
+
+我们可以在这里列出数百个库,但幸运的是它们都列在另一个位置:有关这些详细信息,请参阅 [“Awesome Scala” 列表](https://github.com/lauris/awesome-scala)。
+
+## 10) 强类型系统
+
+Scala 有一个强大的类型系统,它在 Scala 3 中得到了更多的改进。
+Scala 3 的目标很早就定义了,与类型系统相关的目标包括:
+
+- 简化
+- 消除不一致
+- 安全
+- 人体工程学
+- 性能
+
+_简化_ 来自数十个更改和删除的特性。
+例如,从 Scala 2 中重载的 `implicit` 关键字到 Scala 3 中的术语 `given` 和 `using` 的变化使语言更加清晰,尤其是对于初学者来说。
+
+_消除不一致_ 与Scala 3中的几十个[删除的特性][dropped]、[改变的特性][changed]和[增加的特性][add]有关。
+此类别中一些最重要的功能是:
+
+- 交集类型
+- 并集类型
+- 隐式函数类型
+- 依赖函数类型
+- trait 参数
+- 通用元组
+
+{% comment %}
+A list of types from the Dotty documentation:
+
+- Inferred types
+- Generics
+- Intersection types
+- Union types
+- Structural types
+- Dependent function types
+- Type classes
+- Opaque types
+- Variance
+- Algebraic Data Types
+- Wildcard arguments in types: ? replacing _
+- Type lambdas
+- Match types
+- Existential types
+- Higher-kinded types
+- Singleton types
+- Refinement types
+- Kind polymorphism
+- Abstract type members and path-dependent types
+- Dependent function types
+- Bounds
+{% endcomment %}
+
+_安全_ 与几个新的和改变的特性有关:
+
+- Multiversal equality
+- Restricting implicit conversions
+- Null safety
+- Safe initialization
+
+_人体工程学_ 的好例子是枚举和扩展方法,它们以非常易读的方式添加到 Scala 3 中:
+
+{% tabs extension %}
+{% tab 'Scala 3 Only' %}
+```scala
+// 枚举
+enum Color:
+ case Red, Green, Blue
+
+// 扩展方法
+extension (c: Circle)
+ def circumference: Double = c.radius * math.Pi * 2
+ def diameter: Double = c.radius * 2
+ def area: Double = math.Pi * c.radius * c.radius
+```
+{% endtab %}
+{% endtabs %}
+
+_性能_ 涉及几个方面。
+其中之一是 [不透明类型][opaque-types]。
+在 Scala 2 中,有几次尝试创建解决方案以与域驱动设计 (DDD) 实践相一致,即赋予值更有意义的类型。
+这些尝试包括:
+
+- 类型别名
+- 值类
+- 样例类
+
+不幸的是,所有这些方法都有弱点,如 [_Opaque Types_ SIP](https://docs.scala-lang.org/sips/opaque-types.html) 中所述。
+相反,如 SIP 中所述,不透明类型的目标是“对这些包装器类型的操作不得在运行时产生任何额外开销,同时在编译时仍提供类型安全使用。”
+
+有关更多类型系统的详细信息,请参阅 [参考文档][reference]。
+
+## 其他很棒的功能
+
+Scala 有许多很棒的特性,选择十大列表可能是主观的。
+多项调查表明,不同的开发人员群体喜欢不同的特性。
+
+[java]: {% link _zh-cn/overviews/scala3-book/interacting-with-java.md %}
+[given]: {% link _zh-cn/overviews/scala3-book/ca-context-parameters.md %}
+[contextual]: {% link _zh-cn/overviews/scala3-book/ca-contextual-abstractions-intro.md %}
+[reference]: {{ site.scala3ref }}
+[dropped]: {{ site.scala3ref }}/dropped-features
+[changed]: {{ site.scala3ref }}/changed-features
+[added]:{{ site.scala3ref }}/other-new-features
+
+[union-types]: {% link _zh-cn/overviews/scala3-book/types-union.md %}
+[opaque-types]: {% link _zh-cn/overviews/scala3-book/types-opaque-types.md %}
diff --git a/_zh-cn/overviews/thanks.md b/_zh-cn/overviews/thanks.md
index e1429b74f0..e2fac4be7a 100644
--- a/_zh-cn/overviews/thanks.md
+++ b/_zh-cn/overviews/thanks.md
@@ -1,7 +1,8 @@
---
-layout: inner-page-no-masthead
+layout: singlepage-overview
language: zh-cn
title: 致谢名单
+orphanTranslation: true
---
2013年10月份起,CSDN CODE开始组织志愿者翻译Scala官方文档。计划翻译的文档主要为Scala官网上overview部分的内容,包含以下部分:
diff --git a/_zh-cn/scala3/guides/tasty-overview.md b/_zh-cn/scala3/guides/tasty-overview.md
new file mode 100644
index 0000000000..9ab7cc3124
--- /dev/null
+++ b/_zh-cn/scala3/guides/tasty-overview.md
@@ -0,0 +1,146 @@
+---
+layout: singlepage-overview
+title: TASTy 概览
+---
+假定你创建了一个 Scala 3 源代码文件叫 _Hello.scala_:
+
+```scala
+@main def hello = println("Hello, world")
+```
+
+然后用 `scalac` 编译了该文件:
+
+```bash
+$ scalac Hello.scala
+```
+
+你会发现在 `scalac` 生成的其它文件结果中,有些文件是以 _.tasty_ 为扩展名:
+
+```bash
+$ ls -1
+Hello$package$.class
+Hello$package.class
+Hello$package.tasty
+Hello.scala
+hello.class
+hello.tasty
+```
+
+这自然地会引出一个问题,“什么是 tasty?”
+
+## 什么是 TASTy?
+
+TASTy 是从 _Typed Abstract Syntax Trees_ 这个术语的首字母缩写来的。它是 Scala 3 的高级交换格式,在本文档中,我们将它称为 _Tasty_ 。
+
+首先要知道的是,Tasty 文件是由 `scalac` 编译器生成的,并且包含 _所有_ 有关源代码的信息,这些信息包括程序的语法结构,以及有关类型,位置甚至文档的 _所有_ 信息。Tasty 文件包含的信息比 _.class_ 文件多得多,后者是为在 JVM 上运行而生成的。(后面有详细介绍)。
+
+在 Scala 3 中,编译流程像这样:
+
+```text
+ +-------------+ +-------------+ +-------------+
+$ scalac | Hello.scala | -> | Hello.tasty | -> | Hello.class |
+ +-------------+ +-------------+ +-------------+
+ ^ ^ ^
+ | | |
+ 你的代码 TASTy 文件 Class 文件
+ 用于 scalac 用于 JVM
+ (包括完整信息) (不完整信息)
+```
+
+您可以通过使用 `-print-tasty` 标志在 _.tasty_ 文件上运行编译器,以人类可读的形式查看 _.tasty_ 文件的内容。
+您还可以使用 `-decompile` 标志以类似于 Scala 源代码的形式查看反编译的内容。
+
+```bash
+$ scalac -print-tasty hello.tasty
+$ scalac -decompile hello.tasty
+```
+
+### The issue with _.class_ files
+
+由于象 [类型擦除][erasure] 等问题,_.class_ 文件实际上是代码的不完整表示形式。
+演示这一点的一种简单方法是使用 `List` 示例。
+
+_类型擦除_ 意味着当你编写这样的Scala代码,并假定它是在JVM上运行时:
+
+```scala
+val xs: List[Int] = List(1, 2, 3)
+```
+
+该代码被编译为需要与 JVM 兼容的 _.class_ 文件。由于该兼容性要求,该类文件中的代码 --- 您可以使用 `javap` 命令看到它,--- 最终看起来像这样:
+
+```java
+public scala.collection.immutable.List xs();
+```
+
+该 `javap` 命令输出显示了类文件中包含的内容,该内容是 Java 的表示形式。请注意,在此输出中,`xs` _不是_ 定义为 `List[Int]` ;它真正表示的是 `List[java.lang.Object]` 。为了使您的 Scala 代码与 JVM 配合使用,`Int` 类型已被擦除。
+
+稍后,当您在 Scala 代码中访问 `List[Int]` 的元素时,像这样:
+
+```scala
+val x = xs(0)
+```
+
+生成的类文件对此行代码进行强制转换操作,您可以将其想象成:
+
+```
+int x = (Int) xs.get(0) // Java-ish
+val x = xs.get(0).asInstanceOf[Int] // more Scala-like
+```
+
+同样,这样做是为了兼容性,因此您的 Scala 代码可以在 JVM 上运行。但是,我们已经有的整数列表的信息在类文件中丢失了。
+当尝试使用已编译的库来编译 Scala 程序时,会带来问题。为此,我们需要的信息比类文件中通常可用的信息更多。
+
+此讨论仅涵盖类型擦除的主题。对于 JVM 没有意识到的所有其他 Scala 结构,也存在类似的问题,包括 unions, intersections, 带有参数的 traits 以及更多 Scala 3 特性。
+
+### TASTy to the Rescue
+
+因此,TASTy 格式不是像 _.class_ 文件那样没有原始类型的信息,或者只有公共 API(如Scala 2.13 “Pickle” 格式),而是在类型检查后存储完整的抽象语法树(AST)。存储整个 AST 有很多优点:它支持单独编译,针对不同的 JVM 版本重新编译,程序的静态分析等等。
+
+### 重点
+
+因此,这是本节的第一个要点:您在 Scala 代码中指定的类型在 _.class_ 文件中没有完全准确地表示。
+
+第二个关键点是要了解 _编译时_ 和 _运行时_ 提供的信息之间存在差异:
+
+- 在**编译时**,当 `scalac` 读取和分析你的代码时,它知道 `xs` 是一个 `List[Int]`
+- 当编译器将你的代码写入类文件时,它会写 `xs` 是 `List[Object]` ,并在访问 `xs` 的任何地方添加转换信息
+- 然后在**运行时** --- 你的代码在 JVM 中运行,--- JVM 不知道你的列表是一个 `List[Int]`
+
+对于 Scala 3 和 Tasty,这里有一个关于编译时的重要说明:
+
+- 当您编写使用其他 Scala 3 库的 Scala 3 代码时,`scalac` 不必再读取其 _.class_ 文件;它可以读取其 _.tasty_ 文件,如前所述,这些文件是代码的 _准确_ 表示形式。这对于在 Scala 2.13 和 Scala 3 之间实现单独编译和兼容性非常重要。
+
+## Tasty 的好处
+
+可以想象,拥有代码的完整表示形式具有[许多好处][benefits]:
+
+- 编译器使用它来支持单独的编译。
+- Scala 基于 _Language Server Protocol_ 的语言服务器使用它来支持超链接、命令补全、文档以及全局操作,如查找引用和重命名。
+- Tasty 为新一代[基于反射的宏][macros]奠定了良好的基础。
+- 优化器和分析器可以使用它进行深度代码分析和高级代码生成。
+
+在相关的说明中,Scala 2.13.6 有一个 TASTy 读取器,Scala 3 编译器也可以读取2.13“Pickle”格式。Scala 3 迁移指南中的 [类路径兼容性页面][compatibility-ref] 解释了此交叉编译功能的好处。
+
+## 更多信息
+
+总之,Tasty 是 Scala 3 的高级交换格式,_.tasty_ 文件包含源代码的完整表示形式,从而带来了上一节中概述的好处。
+
+有关更多详细信息,请参阅以下资源:
+
+- 在 [此视频](https://www.youtube.com/watch?v=YQmVrUdx8TU) 中,Scala 中心的Jamie Thompson 对 Tasty 的工作原理及其优势进行了详尽的讨论
+- [库作者的二进制兼容性][binary] 讨论二进制兼容性、源代码兼容性和 JVM 执行模型
+- [Scala 3 Transition 的前向兼容性](https://www.scala-lang.org/blog/2020/11/19/scala-3-forward-compat.html) 演示了在同一项目中使用 Scala 2.13 和 Scala 3 的技术
+
+这些文章提供了有关 Scala 3 宏的更多信息:
+
+- [Scala 宏库](https://scalacenter.github.io/scala-3-migration-guide/docs/macros/macro-libraries.html)
+- [宏:Scala 3 的计划](https://www.scala-lang.org/blog/2018/04/30/in-a-nutshell.html)
+- [Quotes Reflect 的参考文档][quotes-reflect]
+- [宏的参考文档][macros]
+
+[benefits]: https://www.scala-lang.org/blog/2018/04/30/in-a-nutshell.html
+[erasure]: https://www.scala-lang.org/files/archive/spec/2.13/03-types.html#type-erasure
+[binary]: {% link _overviews/tutorials/binary-compatibility-for-library-authors.md %}
+[compatibility-ref]: {% link _overviews/scala3-migration/compatibility-classpath.md %}
+[quotes-reflect]: {{ site.scala3ref }}/metaprogramming/reflection.html
+[macros]: {{ site.scala3ref }}/metaprogramming/macros.html
diff --git a/_zh-cn/scala3/new-in-scala3.md b/_zh-cn/scala3/new-in-scala3.md
new file mode 100644
index 0000000000..5f82276635
--- /dev/null
+++ b/_zh-cn/scala3/new-in-scala3.md
@@ -0,0 +1,122 @@
+---
+layout: singlepage-overview
+title: Scala 3 里的新东西
+scala3: true
+---
+令人振奋的新版 Scala 3 带来了许多改进和新功能。在这里,我们为你提供最重要的变更的快速概述。如果你想深入挖掘,还有一些参考资料供你使用:
+
+- [Scala 3 Book]({% link _overviews/scala3-book/introduction.md %}) 面向刚接触 Scala 语言的开发人员。
+- [Syntax Summary][syntax-summary] 为您提供了新语法的正式描述。
+- [Language Reference][reference] 对 Scala 2 到 Scala 3 的变化做了详细说明。
+- [Migration Guide][migration] 为你提供了从 Scala 2 迁移到 Scala 3 的所有必要信息。
+- [Scala 3 Contributing Guide][contribution] Scala 3 贡献指南,更深入地探讨了编译器,包括修复问题的指南。
+
+## Scala 3 里有什么新东西
+Scala 3 是对 Scala 语言的一次彻底改造。在其核心部分,类型系统的许多方面都被改变了,变得更有原则性。虽然这也带来了令人兴奋的新功能(比如联合类型),但首先意味着类型系统变得(甚至)不那么碍事了,例如[类型推断][type-inference]和 overload resolution 都得到了很大的改善。
+
+### 新的和闪亮的:语法
+除了许多(小的)清理工作,Scala 3 的语法还提供了以下改进:
+
+- 用于控制结构的新“quiet”语法,如 `if`、`while` 和 `for` 。 ([new control syntax][syntax-control])
+- `new` 关键字是可选的 (_aka_ [creator applications][creator])
+- [Optional braces][syntax-indentation]:可选的大括号,支持不受干扰、缩进敏感的编程风格
+- [类型级通配符][syntax-wildcard] 从 `_` 更改为 `?`。
+- implicit(和它们的语法)已被[大量修订][implicits]。
+
+### Opinionated: 上下文抽象
+Scala的一个基本核心概念是(在某种程度上仍然是)为用户提供一小部分强大的功能,这些功能可以被组合成巨大的(有时甚至是不可预见的)表达能力。例如,_implicit_ 的特性被用来模拟上下文抽象、表达类型级计算、模拟类型类、执行隐式强制、编码扩展方法等等。从这些用例中学习,Scala 3 采取了一种略微不同的方法,专注于 **意图** 而非 **机制**。Scala 3 没有提供一个非常强大的功能,而是提供了多个定制的语言功能,让程序员直接表达他们的意图。
+
+- **Abtracting over contextual information**. [Using clauses][contextual-using] 允许程序员对调用上下文中的信息进行抽象,这些信息应该以隐式方式传递。作为对 Scala 2 implicits 的改进,可以按类型指定 using 子句,从而将函数签名从从未显式引用的术语变量名中解放出来。
+
+- **Providing Type-class instances**. [Given instances][contextual-givens] 允许程序员定义某个类型的 _规范值_ 。这使得使用类型类的编程更加简单,而不会泄露实现细节。
+
+- **Retroactively extending classes**. 在 Scala 2 中,扩展方法必须使用隐式转换或隐式类进行编码。相比之下,在 Scala 3 中,[extension methods][contextual-extension]现在直接内置于语言中,从而产生更好的错误消息和改进的类型推断。
+
+- **Viewing one type as another**. [隐式转换][contextual-conversions]已经被重新设计为类型类`Conversion`的实例。
+
+- **Higher-order contextual abstractions**. [context functions][contextual-functions]的 _全新_ 功能使上下文抽象成为第一等公民。它们是库开发人员的一个重要工具,允许表达简洁的特定领域语言。
+
+- **Actionable feedback from the compiler**. 如果一个隐式参数不能被编译器解决,它现在提供了可能解决这个问题的[import suggestions](https://www.scala-lang.org/blog/2020/05/05/scala-3-import-suggestions.html)。
+
+### 表达真正的意思: 类型系统改进
+除了极大地改进了类型推断,Scala 3 类型系统还提供了许多新的功能,还为你提供了强大的工具来静态地表达类型中的不变量:
+
+- **Enumerations**. [枚举][enums]已经被重新设计,以便与样例类很好地融合,并形成表达[代数数据类型][enums-adts]的新标准。
+
+- **Opaque Types**. 将实现细节隐藏在[opaque type aliases][types-opaque]的别名后面,而不需要在性能上付出代价! Opaque types 取代了值类,并允许你建立一个抽象的屏障,而不会造成额外的装箱开销。
+
+- **Intersection and union types**. 将类型系统建立在新的基础上,引入了新的类型系统特性:[intersection types][types-intersection]的实例,如`A & B`,既是`A`的实例,也是`B`的实例;[union types][types-union]的实例,如`A | B`,是`A`或`B`的实例。这两种结构都允许程序员在继承层次结构之外灵活地表达类型约束。
+
+- **Dependent function types**. Scala 2 已经允许返回类型依赖于(值)参数。在 Scala 3 中,现在可以对这种模式进行抽象,表达[dependent function types][types-dependent]。在类型`F = (e: Entry) => e.Key`中,结果类型取决于参数。
+
+- **Polymorphic function types**. 与 dependent function types 一样,Scala 2 支持拥有类型参数的方法,但不允许程序员对这些方法进行抽象。在 Scala 3 中,像`[A] => List[A] => List[A]`这样的[polymorphic function types][types-polymorphic]可以抽象出除值参数外还接受 _类型参数_ 的函数。
+
+- **Type lambdas**. 在 Scala 2 中需要用[编译器插件](https://github.com/typelevel/kind-projector)来表达的东西,现在在 Scala 3 中是原生支持的功能:类型lambdas是类型级别的函数,可以作为(高等类型的)类型参数传递,而不需要辅助类型定义。
+
+- **Match types**. Scala 3 提供了对[matching on types][types-match]的直接支持,而不是使用隐式解析对类型级别的计算进行编码。将类型级计算整合到类型检查器中,可以改进错误信息,并消除对复杂编码的需求。
+
+### Re-envisioned:面向对象的编程
+Scala 一直处于函数式编程和面向对象编程的前沿 -- 而 Scala 3 在这两个方向上都推动了边界的发展! 上述类型系统的变化和上下文抽象的重新设计使得 _函数式编程_ 比以前更容易。同时,以下的新特性使结构良好的 _面向对象设计_ 成为可能,并支持最佳实践。
+
+- **Pass it on**. Trait 更接近于 class,现在也可以接受[参数][oo-trait-parameters],使其作为模块化软件分解的工具更加强大。
+
+- **Plan for extension**. 在面向对象的设计中,扩展那些不打算扩展的类是一个长期存在的问题。为了解决这个问题,[open classes][oo-open]要求库设计者 _明确地_ 将类标记为 open(开放的)。
+
+- **Hide implementation details**. 实现功能的工具性的traits有时不应该是推断类型的一部分。在 Scala 3 中,这些traits可以被标记为[transparent][oo-transparent],(在推断类型中)向用户隐藏继承信息。
+
+- **Composition over inheritance**. 这句话经常被引用,但实现起来却很繁琐。Scala 3 的[export clauses][oo-export]则不然:与imports对应,export clauses 允许用户为对象的选定成员定义别名。
+
+- **No more NPEs**. Scala 3 比以往任何时候都更安全:[explicit null][oo-explicit-null]将`null`移出了类型层次结构,帮助你静态地捕捉错误;[safe initialization][oo-safe-init]的额外检查可以检测对未初始化对象的访问。
+
+### Batteries Included: 元编程
+Scala 2 中的宏只是一个实验性的功能,而 Scala 3 则为元编程提供了强大的工具库。[宏教程]({% link _overviews/scala3-macros/tutorial/index.md %})中包含了关于不同设施的详细信息。特别是,Scala 3 为元编程提供了以下功能:
+
+- **Inline**. [inline feature][meta-inline]允许在编译时化简值和方法。这个简单的功能已经涵盖了许多使用情况,同时也为更高级的功能提供了入口。
+- **Compile-time operations**. 包[`scala.compiletime`][meta-compiletime]中包含了额外的功能,可以用来实现内联方法。
+- **Quoted code blocks**. Scala 3为代码增加了[quasi-quotation][meta-quotes]的新功能,这为构建和分析代码提供了方便的高级接口。构建加一加一的代码就像`'{ 1 + 1 }`一样简单。
+- **Reflection API**. 对于更高级的用例,[quotes.reflect][meta-reflection]提供了更详细的控制来检查和生成程序树。
+
+如果你想进一步了解 Scala 3 中的元编程,我们邀请你参阅我们的[教程][meta-tutorial]。
+
+[enums]: {{ site.scala3ref }}/enums/enums.html
+[enums-adts]: {{ site.scala3ref }}/enums/adts.html
+
+[types-intersection]: {{ site.scala3ref }}/new-types/intersection-types.html
+[types-union]: {{ site.scala3ref }}/new-types/union-types.html
+[types-dependent]: {{ site.scala3ref }}/new-types/dependent-function-types.html
+[types-lambdas]: {{ site.scala3ref }}/new-types/type-lambdas.html
+[types-polymorphic]: {{ site.scala3ref }}/new-types/polymorphic-function-types.html
+[types-match]: {{ site.scala3ref }}/new-types/match-types.html
+[types-opaque]: {{ site.scala3ref }}/other-new-features/opaques.html
+
+[type-inference]: {{ site.scala3ref }}/changed-features/type-inference.html
+[overload-resolution]: {{ site.scala3ref }}/changed-features/overload-resolution.html
+[reference]: {{ site.scala3ref }}/overview.html
+[creator]: {{ site.scala3ref }}/other-new-features/creator-applications.html
+[migration]: {% link _overviews/scala3-migration/compatibility-intro.md %}
+[contribution]: {% link _overviews/scala3-contribution/contribution-intro.md %}
+
+[implicits]: {{ site.scala3ref }}/contextual
+[contextual-using]: {{ site.scala3ref }}/contextual/using-clauses.html
+[contextual-givens]: {{ site.scala3ref }}/contextual/givens.html
+[contextual-extension]: {{ site.scala3ref }}/contextual/extension-methods.html
+[contextual-conversions]: {{ site.scala3ref }}/contextual/conversions.html
+[contextual-functions]: {{ site.scala3ref }}/contextual/context-functions.html
+
+[syntax-summary]: {{ site.scala3ref }}/syntax.html
+[syntax-control]: {{ site.scala3ref }}/other-new-features/control-syntax.html
+[syntax-indentation]: {{ site.scala3ref }}/other-new-features/indentation.html
+[syntax-wildcard]: {{ site.scala3ref }}/changed-features/wildcards.html
+
+[meta-tutorial]: {% link _overviews/scala3-macros/tutorial/index.md %}
+[meta-inline]: {% link _overviews/scala3-macros/tutorial/inline.md %}
+[meta-compiletime]: {% link _overviews/scala3-macros/tutorial/compiletime.md %}
+[meta-quotes]: {% link _overviews/scala3-macros/tutorial/quotes.md %}
+[meta-reflection]: {% link _overviews/scala3-macros/tutorial/reflection.md %}
+
+[oo-explicit-null]: {{ site.scala3ref }}/experimental/explicit-nulls.html
+[oo-safe-init]: {{ site.scala3ref }}/other-new-features/safe-initialization.html
+[oo-trait-parameters]: {{ site.scala3ref }}/other-new-features/trait-parameters.html
+[oo-open]: {{ site.scala3ref }}/other-new-features/open-classes.html
+[oo-transparent]: {{ site.scala3ref }}/other-new-features/transparent-traits.html
+[oo-export]: {{ site.scala3ref }}/other-new-features/export.html
diff --git a/_zh-cn/scala3/reference/README.md b/_zh-cn/scala3/reference/README.md
new file mode 100644
index 0000000000..960554be5f
--- /dev/null
+++ b/_zh-cn/scala3/reference/README.md
@@ -0,0 +1,5 @@
+https://docs.scala-lang.org/scala3/reference 的页面内容是从 [Scala 3 编译器库](https://github.com/scala/scala3) 生成的。
+
+请到这里为 Scala 3 参考文档做贡献:
+
+https://github.com/scala/scala3/tree/main/docs/_docs
diff --git a/_zh-cn/thanks.md b/_zh-cn/thanks.md
index e1429b74f0..e2fac4be7a 100644
--- a/_zh-cn/thanks.md
+++ b/_zh-cn/thanks.md
@@ -1,7 +1,8 @@
---
-layout: inner-page-no-masthead
+layout: singlepage-overview
language: zh-cn
title: 致谢名单
+orphanTranslation: true
---
2013年10月份起,CSDN CODE开始组织志愿者翻译Scala官方文档。计划翻译的文档主要为Scala官网上overview部分的内容,包含以下部分:
diff --git a/_zh-cn/tour/abstract-type-members.md b/_zh-cn/tour/abstract-type-members.md
index 4ef5e918d4..3fbbb8a487 100644
--- a/_zh-cn/tour/abstract-type-members.md
+++ b/_zh-cn/tour/abstract-type-members.md
@@ -13,7 +13,7 @@ previous-page: inner-classes
特质和抽象类可以包含一个抽象类型成员,意味着实际类型可由具体实现来确定。例如:
-```tut
+```scala mdoc
trait Buffer {
type T
val element: T
@@ -21,7 +21,7 @@ trait Buffer {
```
这里定义的抽象类型`T`是用来描述成员`element`的类型的。通过抽象类来扩展这个特质后,就可以添加一个类型上边界来让抽象类型`T`变得更加具体。
-```tut
+```scala mdoc
abstract class SeqBuffer extends Buffer {
type U
type T <: Seq[U]
@@ -32,7 +32,7 @@ abstract class SeqBuffer extends Buffer {
含有抽象类型成员的特质或类([classes](classes.html))经常和匿名类的初始化一起使用。为了能够阐明问题,下面看一段程序,它处理一个涉及整型列表的序列缓冲区。
-```tut
+```scala mdoc
abstract class IntSeqBuffer extends SeqBuffer {
type U = Int
}
@@ -51,7 +51,7 @@ println("content = " + buf.element)
把抽象类型成员转成类的类型参数或者反过来,也是可行的。如下面这个版本只用了类的类型参数来转换上面的代码:
-```tut
+```scala mdoc:nest
abstract class Buffer[+T] {
val element: T
}
diff --git a/_zh-cn/tour/annotations.md b/_zh-cn/tour/annotations.md
index 8d340efe08..56992045d6 100644
--- a/_zh-cn/tour/annotations.md
+++ b/_zh-cn/tour/annotations.md
@@ -7,7 +7,7 @@ num: 30
language: zh-cn
-next-page: default-parameter-values
+next-page: packages-and-imports
previous-page: by-name-parameters
---
@@ -26,7 +26,7 @@ object DeprecationDemo extends App {
## 确保编码正确性的注解
如果不满足条件,某些注解实际上会导致编译失败。 例如,注解 `@tailrec` 确保方法是 [尾递归](https://en.wikipedia.org/wiki/Tail_call)。 尾递归可以保持内存需求不变。 以下是它在计算阶乘的方法中的用法:
-```tut
+```scala mdoc
import scala.annotation.tailrec
def factorial(x: Int): Int = {
diff --git a/_zh-cn/tour/automatic-closures.md b/_zh-cn/tour/automatic-closures.md
deleted file mode 100644
index b51652c94e..0000000000
--- a/_zh-cn/tour/automatic-closures.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-layout: tour
-title: Automatic Closures
-partof: scala-tour
-
-language: zh-cn
----
diff --git a/_zh-cn/tour/basics.md b/_zh-cn/tour/basics.md
index 70d7b1992c..a7f9c3bf0a 100644
--- a/_zh-cn/tour/basics.md
+++ b/_zh-cn/tour/basics.md
@@ -14,38 +14,34 @@ previous-page: tour-of-scala
## 在浏览器上尝试Scala
-你可以在浏览器上使用ScalaFiddle运行Scala。
+你可以在浏览器上使用Scastie运行Scala。
-1. 打开[https://scalafiddle.io](https://scalafiddle.io);
+1. 打开[Scastie](https://scastie.scala-lang.org/);
2. 在左侧窗格中粘贴`println("Hello, world!")`;
3. 点击"Run"按钮,输出将展现在右侧窗格中。
这是一种简单的、零设置的方法来实践Scala的代码片段。
-这篇文档中的大部分代码示例与 ScalaFiddle 进行了集成,可以通过点击 “Run” 按钮即来直接运行 Scala 代码。
-
## 表达式
表达式是可计算的语句。
-```
+```scala mdoc
1 + 1
```
你可以使用`println`来输出表达式的结果。
-{% scalafiddle %}
-```tut
+```scala mdoc
println(1) // 1
println(1 + 1) // 2
println("Hello!") // Hello!
println("Hello," + " world!") // Hello, world!
```
-{% endscalafiddle %}
### 常量(`Values`)
你可以使用`val`关键字来给表达式的结果命名。
-```tut
+```scala mdoc
val x = 1 + 1
println(x) // 2
```
@@ -54,13 +50,13 @@ println(x) // 2
常量(`values`)不能重新被赋值。
-```tut:fail
+```scala mdoc:fail
x = 3 // This does not compile.
```
-常量(`values`)的类型可以被推断,或者你也可以显示地声明类型,例如:
+常量(`values`)的类型可以被推断,或者你也可以显式地声明类型,例如:
-```tut
+```scala mdoc:nest
val x: Int = 1 + 1
```
@@ -70,15 +66,15 @@ val x: Int = 1 + 1
除了可以重新赋值,变量和常量类似。你可以使用`var`关键字来定义一个变量。
-```tut
+```scala mdoc:nest
var x = 1 + 1
x = 3 // This compiles because "x" is declared with the "var" keyword.
println(x * x) // 9
```
-和常量一样,你可以显示地声明类型:
+和常量一样,你可以显式地声明类型:
-```tut
+```scala mdoc:nest
var x: Int = 1 + 1
```
@@ -89,7 +85,7 @@ var x: Int = 1 + 1
代码块中最后一个表达式的结果,也正是整个块的结果。
-```tut
+```scala mdoc
println({
val x = 1 + 1
x + 1
@@ -102,7 +98,7 @@ println({
你可以定义一个匿名函数(即没有名字),来返回一个给定整数加一的结果。
-```tut
+```scala mdoc
(x: Int) => x + 1
```
@@ -110,25 +106,21 @@ println({
你也可以给函数命名。
-{% scalafiddle %}
-```tut
+```scala mdoc
val addOne = (x: Int) => x + 1
println(addOne(1)) // 2
```
-{% endscalafiddle %}
函数可带有多个参数。
-{% scalafiddle %}
-```tut
+```scala mdoc
val add = (x: Int, y: Int) => x + y
println(add(1, 2)) // 3
```
-{% endscalafiddle %}
或者不带参数。
-```tut
+```scala mdoc
val getTheAnswer = () => 42
println(getTheAnswer()) // 42
```
@@ -139,27 +131,23 @@ println(getTheAnswer()) // 42
方法由`def`关键字定义。`def`后面跟着一个名字、参数列表、返回类型和方法体。
-{% scalafiddle %}
-```tut
+```scala mdoc:nest
def add(x: Int, y: Int): Int = x + y
println(add(1, 2)) // 3
```
-{% endscalafiddle %}
注意返回类型是怎么在函数列表和一个冒号`: Int`之后声明的。
方法可以接受多个参数列表。
-{% scalafiddle %}
-```tut
+```scala mdoc
def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier
println(addThenMultiply(1, 2)(3)) // 9
```
-{% endscalafiddle %}
或者没有参数列表。
-```tut
+```scala mdoc
def name: String = System.getProperty("user.name")
println("Hello, " + name + "!")
```
@@ -168,15 +156,13 @@ println("Hello, " + name + "!")
方法也可以有多行的表达式。
-{% scalafiddle %}
-```tut
+```scala mdoc
def getSquareString(input: Double): String = {
val square = input * input
square.toString
}
println(getSquareString(2.5)) // 6.25
```
-{% endscalafiddle %}
方法体的最后一个表达式就是方法的返回值。(Scala中也有一个`return`关键字,但是很少使用)
@@ -184,7 +170,7 @@ println(getSquareString(2.5)) // 6.25
你可以使用`class`关键字定义一个类,后面跟着它的名字和构造参数。
-```tut
+```scala mdoc
class Greeter(prefix: String, suffix: String) {
def greet(name: String): Unit =
println(prefix + name + suffix)
@@ -194,7 +180,7 @@ class Greeter(prefix: String, suffix: String) {
你可以使用`new`关键字创建一个类的实例。
-```tut
+```scala mdoc
val greeter = new Greeter("Hello, ", "!")
greeter.greet("Scala developer") // Hello, Scala developer!
```
@@ -205,13 +191,13 @@ greeter.greet("Scala developer") // Hello, Scala developer!
Scala有一种特殊的类叫做样例类(case class)。默认情况下,样例类一般用于不可变对象,并且可作值比较。你可以使用`case class`关键字来定义样例类。
-```tut
+```scala mdoc
case class Point(x: Int, y: Int)
```
你可以不用`new`关键字来实例化样例类。
-```tut
+```scala mdoc
val point = Point(1, 2)
val anotherPoint = Point(1, 2)
val yetAnotherPoint = Point(2, 2)
@@ -219,17 +205,17 @@ val yetAnotherPoint = Point(2, 2)
并且它们的值可以进行比较。
-```tut
+```scala mdoc
if (point == anotherPoint) {
- println(point + " and " + anotherPoint + " are the same.")
+ println(s"$point and $anotherPoint are the same.")
} else {
- println(point + " and " + anotherPoint + " are different.")
+ println(s"$point and $anotherPoint are different.")
} // Point(1,2) and Point(1,2) are the same.
if (point == yetAnotherPoint) {
- println(point + " and " + yetAnotherPoint + " are the same.")
+ println(s"$point and $yetAnotherPoint are the same.")
} else {
- println(point + " and " + yetAnotherPoint + " are different.")
+ println(s"$point and $yetAnotherPoint are different.")
} // Point(1,2) and Point(2,2) are different.
```
@@ -241,7 +227,7 @@ if (point == yetAnotherPoint) {
你可以使用`object`关键字定义对象。
-```tut
+```scala mdoc
object IdFactory {
private var counter = 0
def create(): Int = {
@@ -253,7 +239,7 @@ object IdFactory {
你可以通过引用它的名字来访问一个对象。
-```tut
+```scala mdoc
val newId: Int = IdFactory.create()
println(newId) // 1
val newerId: Int = IdFactory.create()
@@ -268,7 +254,7 @@ println(newerId) // 2
你可以使用`trait`关键字定义特质。
-```tut
+```scala mdoc:nest
trait Greeter {
def greet(name: String): Unit
}
@@ -276,8 +262,7 @@ trait Greeter {
特质也可以有默认的实现。
-{% scalafiddle %}
-```tut
+```scala mdoc:reset
trait Greeter {
def greet(name: String): Unit =
println("Hello, " + name + "!")
@@ -286,7 +271,7 @@ trait Greeter {
你可以使用`extends`关键字来继承特质,使用`override`关键字来覆盖默认的实现。
-```tut
+```scala mdoc
class DefaultGreeter extends Greeter
class CustomizableGreeter(prefix: String, postfix: String) extends Greeter {
@@ -301,7 +286,6 @@ greeter.greet("Scala developer") // Hello, Scala developer!
val customGreeter = new CustomizableGreeter("How are you, ", "?")
customGreeter.greet("Scala developer") // How are you, Scala developer?
```
-{% endscalafiddle %}
这里,`DefaultGreeter`仅仅继承了一个特质,它还可以继承多个特质。
@@ -313,7 +297,7 @@ customGreeter.greet("Scala developer") // How are you, Scala developer?
通过使用对象,你可以如下所示来定义一个主方法。
-```tut
+```scala mdoc
object Main {
def main(args: Array[String]): Unit =
println("Hello, Scala developer!")
diff --git a/_zh-cn/tour/by-name-parameters.md b/_zh-cn/tour/by-name-parameters.md
index 31eae14e22..ce3ad1f726 100644
--- a/_zh-cn/tour/by-name-parameters.md
+++ b/_zh-cn/tour/by-name-parameters.md
@@ -12,13 +12,13 @@ previous-page: operators
---
_传名参数_ 仅在被使用时触发实际参数的求值运算。 它们与 _传值参数_ 正好相反。 要将一个参数变为传名参数,只需在它的类型前加上 `=>`。
-```tut
+```scala mdoc
def calculate(input: => Int) = input * 37
```
传名参数的优点是,如果它们在函数体中未被使用,则不会对它们进行求值。 另一方面,传值参数的优点是它们仅被计算一次。
以下是我们如何实现一个 while 循环的例子:
-```tut
+```scala mdoc
def whileLoop(condition: => Boolean)(body: => Unit): Unit =
if (condition) {
body
diff --git a/_zh-cn/tour/case-classes.md b/_zh-cn/tour/case-classes.md
index b9346c1b4b..15a2dbf4cb 100644
--- a/_zh-cn/tour/case-classes.md
+++ b/_zh-cn/tour/case-classes.md
@@ -1,6 +1,6 @@
---
layout: tour
-title: 案例类(Case Classes)
+title: 样例类(Case Classes)
partof: scala-tour
num: 10
@@ -11,18 +11,18 @@ next-page: pattern-matching
previous-page: multiple-parameter-lists
---
-案例类(Case classes)和普通类差不多,只有几点关键差别,接下来的介绍将会涵盖这些差别。案例类非常适合用于不可变的数据。下一节将会介绍他们在[模式匹配](pattern-matching.html)中的应用。
+样例类(Case classes)和普通类差不多,只有几点关键差别,接下来的介绍将会涵盖这些差别。样例类非常适合用于不可变的数据。下一节将会介绍他们在[模式匹配](pattern-matching.html)中的应用。
-## 定义一个案例类
-一个最简单的案例类定义由关键字`case class`,类名,参数列表(可为空)组成:
-```tut
+## 定义一个样例类
+一个最简单的样例类定义由关键字`case class`,类名,参数列表(可为空)组成:
+```scala mdoc
case class Book(isbn: String)
val frankenstein = Book("978-0486282114")
```
-注意在实例化案例类`Book`时,并没有使用关键字`new`,这是因为案例类有一个默认的`apply`方法来负责对象的创建。
+注意在实例化样例类`Book`时,并没有使用关键字`new`,这是因为样例类有一个默认的`apply`方法来负责对象的创建。
-当你创建包含参数的案例类时,这些参数是公开(public)的`val`
+当你创建包含参数的样例类时,这些参数是公开(public)的`val`
```
case class Message(sender: String, recipient: String, body: String)
val message1 = Message("guillaume@quebec.ca", "jorge@catalonia.es", "Ça va ?")
@@ -30,10 +30,10 @@ val message1 = Message("guillaume@quebec.ca", "jorge@catalonia.es", "Ça va ?")
println(message1.sender) // prints guillaume@quebec.ca
message1.sender = "travis@washington.us" // this line does not compile
```
-你不能给`message1.sender`重新赋值,因为它是一个`val`(不可变)。在案例类中使用`var`也是可以的,但并不推荐这样。
+你不能给`message1.sender`重新赋值,因为它是一个`val`(不可变)。在样例类中使用`var`也是可以的,但并不推荐这样。
## 比较
-案例类在比较的时候是按值比较而非按引用比较:
+样例类在比较的时候是按值比较而非按引用比较:
```
case class Message(sender: String, recipient: String, body: String)
@@ -44,7 +44,7 @@ val messagesAreTheSame = message2 == message3 // true
尽管`message2`和`message3`引用不同的对象,但是他们的值是相等的,所以`message2 == message3`为`true`。
## 拷贝
-你可以通过`copy`方法创建一个案例类实例的浅拷贝,同时可以指定构造参数来做一些改变。
+你可以通过`copy`方法创建一个样例类实例的浅拷贝,同时可以指定构造参数来做一些改变。
```
case class Message(sender: String, recipient: String, body: String)
val message4 = Message("julien@bretagne.fr", "travis@washington.us", "Me zo o komz gant ma amezeg")
diff --git a/_zh-cn/tour/classes.md b/_zh-cn/tour/classes.md
index 58acc8fc2a..e01dece08f 100644
--- a/_zh-cn/tour/classes.md
+++ b/_zh-cn/tour/classes.md
@@ -17,14 +17,14 @@ Scala中的类是用于创建对象的蓝图,其中包含了方法、常量、
## 类定义
一个最简的类的定义就是关键字`class`+标识符,类名首字母应大写。
-```tut
+```scala mdoc
class User
val user1 = new User
```
关键字`new`被用于创建类的实例。`User`由于没有定义任何构造器,因而只有一个不带任何参数的默认构造器。然而,你通常需要一个构造器和类体。下面是类定义的一个例子:
-```tut
+```scala mdoc
class Point(var x: Int, var y: Int) {
def move(dx: Int, dy: Int): Unit = {
@@ -47,7 +47,7 @@ println(point1) // prints (2, 3)
构造器可以通过提供一个默认值来拥有可选参数:
-```tut
+```scala mdoc:nest
class Point(var x: Int = 0, var y: Int = 0)
val origin = new Point // x and y are both set to 0
@@ -57,7 +57,7 @@ println(point1.x) // prints 1
```
在这个版本的`Point`类中,`x`和`y`拥有默认值`0`所以没有必传参数。然而,因为构造器是从左往右读取参数,所以如果仅仅要传个`y`的值,你需要带名传参。
-```
+```scala mdoc:nest
class Point(var x: Int = 0, var y: Int = 0)
val point2 = new Point(y=2)
println(point2.y) // prints 2
@@ -67,7 +67,7 @@ println(point2.y) // prints 2
## 私有成员和Getter/Setter语法
成员默认是公有(`public`)的。使用`private`访问修饰符可以在类外部隐藏它们。
-```tut
+```scala mdoc:nest
class Point {
private var _x = 0
private var _y = 0
@@ -93,14 +93,14 @@ point1.y = 101 // prints the warning
在这个版本的`Point`类中,数据存在私有变量`_x`和`_y`中。`def x`和`def y`方法用于访问私有数据。`def x_=`和`def y_=`是为了验证和给`_x`和`_y`赋值。注意下对于setter方法的特殊语法:这个方法在getter方法的后面加上`_=`,后面跟着参数。
主构造方法中带有`val`和`var`的参数是公有的。然而由于`val`是不可变的,所以不能像下面这样去使用。
-```
+```scala mdoc:fail
class Point(val x: Int, val y: Int)
val point = new Point(1, 2)
point.x = 3 // <-- does not compile
```
不带`val`或`var`的参数是私有的,仅在类中可见。
-```
+```scala mdoc:fail
class Point(x: Int, y: Int)
val point = new Point(1, 2)
point.x // <-- does not compile
diff --git a/_zh-cn/tour/compound-types.md b/_zh-cn/tour/compound-types.md
index 467f0738c0..9c36707c67 100644
--- a/_zh-cn/tour/compound-types.md
+++ b/_zh-cn/tour/compound-types.md
@@ -15,7 +15,7 @@ previous-page: abstract-type-members
假设我们有两个特质 `Cloneable` 和 `Resetable`:
-```tut
+```scala mdoc
trait Cloneable extends java.lang.Cloneable {
override def clone(): Cloneable = {
super.clone().asInstanceOf[Cloneable]
diff --git a/_zh-cn/tour/default-parameter-values.md b/_zh-cn/tour/default-parameter-values.md
index 7860abca4c..67db867770 100644
--- a/_zh-cn/tour/default-parameter-values.md
+++ b/_zh-cn/tour/default-parameter-values.md
@@ -13,7 +13,7 @@ previous-page: annotations
Scala具备给参数提供默认值的能力,这样调用者就可以忽略这些具有默认值的参数。
-```tut
+```scala mdoc
def log(message: String, level: String = "INFO") = println(s"$level: $message")
log("System starting") // prints INFO: System starting
@@ -22,7 +22,7 @@ log("User not found", "WARNING") // prints WARNING: User not found
上面的参数level有默认值,所以是可选的。最后一行中传入的参数`"WARNING"`重写了默认值`"INFO"`。在Java中,我们可以通过带有可选参数的重载方法达到同样的效果。不过,只要调用方忽略了一个参数,其他参数就必须要带名传入。
-```tut
+```scala mdoc
class Point(val x: Double = 0, val y: Double = 0)
val point1 = new Point(y = 1)
@@ -31,7 +31,7 @@ val point1 = new Point(y = 1)
注意从Java代码中调用时,Scala中的默认参数则是必填的(非可选),如:
-```tut
+```scala mdoc:nest
// Point.scala
class Point(val x: Double = 0, val y: Double = 0)
```
diff --git a/_zh-cn/tour/extractor-objects.md b/_zh-cn/tour/extractor-objects.md
index f61d64f91a..c74d946482 100644
--- a/_zh-cn/tour/extractor-objects.md
+++ b/_zh-cn/tour/extractor-objects.md
@@ -13,12 +13,12 @@ previous-page: regular-expression-patterns
提取器对象是一个包含有 `unapply` 方法的单例对象。`apply` 方法就像一个构造器,接受参数然后创建一个实例对象,反之 `unapply` 方法接受一个实例对象然后返回最初创建它所用的参数。提取器常用在模式匹配和偏函数中。
-```tut
+```scala mdoc
import scala.util.Random
object CustomerID {
- def apply(name: String) = s"$name--${Random.nextLong}"
+ def apply(name: String) = s"$name--${Random.nextLong()}"
def unapply(customerID: String): Option[String] = {
val stringArray: Array[String] = customerID.split("--")
@@ -37,7 +37,7 @@ customer1ID match {
因为变量定义可以使用模式引入变量,提取器可以用来初始化这个变量,使用 unapply 方法来生成值。
-```tut
+```scala mdoc
val customer2ID = CustomerID("Nico")
val CustomerID(name) = customer2ID
println(name) // prints Nico
@@ -45,13 +45,13 @@ println(name) // prints Nico
上面的代码等价于 `val name = CustomerID.unapply(customer2ID).get`。
-```tut
+```scala mdoc
val CustomerID(name2) = "--asdfasdfasdf"
```
如果没有匹配的值,会抛出 `scala.MatchError`:
-```tut:fail
+```scala
val CustomerID(name3) = "-asdfasdfasdf"
```
diff --git a/_zh-cn/tour/for-comprehensions.md b/_zh-cn/tour/for-comprehensions.md
index 6c0ebfee41..1c3f823fa8 100644
--- a/_zh-cn/tour/for-comprehensions.md
+++ b/_zh-cn/tour/for-comprehensions.md
@@ -15,7 +15,7 @@ Scala 提供一个轻量级的标记方式用来表示 *序列推导*。推导
看下例:
-```tut
+```scala mdoc
case class User(name: String, age: Int)
val userBase = List(User("Travis", 28),
@@ -32,7 +32,7 @@ twentySomethings.foreach(name => println(name)) // prints Travis Dennis
下面这个例子复杂一些,使用了两个生成器。它计算了 `0` 到 `n-1` 的所有两两求和为 `v` 的数字的组合:
-```tut
+```scala mdoc
def foo(n: Int, v: Int) =
for (i <- 0 until n;
j <- i until n if i + j == v)
@@ -45,16 +45,15 @@ foo(10, 10) foreach {
```
这里 `n == 10` 和 `v == 10`。在第一次迭代时,`i == 0` 并且 `j == 0` 所以 `i + j != v` 因此没有返回值被生成。在 `i` 的值递增到 `1` 之前,`j` 的值又递增了 9 次。如果没有 `if` 语句过滤,上面的例子只会打印出如下的结果:
-```
-
-(0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (0, 5) (0, 6) (0, 7) (0, 8) (0, 9) (1, 1) ...
+```scala
+(0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (0, 5) (0, 6) (0, 7) (0, 8) (0, 9) (1, 0) ...
```
注意 for 表达式并不局限于使用列表。任何数据类型只要支持 `withFilter`,`map`,和 `flatMap` 操作(不同数据类型可能支持不同的操作)都可以用来做序列推导。
你可以在使用 for 表达式时省略 `yield` 语句。此时会返回 `Unit`。当你想要执行一些副作用的时候这很有用。下面的例子输出和上面相同的结果,但是没有使用 `yield`:
-```tut
+```scala mdoc:nest
def foo(n: Int, v: Int) =
for (i <- 0 until n;
j <- i until n if i + j == v)
diff --git a/_zh-cn/tour/generic-classes.md b/_zh-cn/tour/generic-classes.md
index 944105906c..fed6f8d629 100644
--- a/_zh-cn/tour/generic-classes.md
+++ b/_zh-cn/tour/generic-classes.md
@@ -14,10 +14,11 @@ previous-page: extractor-objects
## 定义一个泛型类
泛型类使用方括号 `[]` 来接受类型参数。一个惯例是使用字母 `A` 作为参数标识符,当然你可以使用任何参数名称。
-```tut
+```scala mdoc
class Stack[A] {
private var elements: List[A] = Nil
- def push(x: A) { elements = x :: elements }
+ def push(x: A): Unit =
+ elements = x :: elements
def peek: A = elements.head
def pop(): A = {
val currentTop = peek
diff --git a/_zh-cn/tour/higher-order-functions.md b/_zh-cn/tour/higher-order-functions.md
index 5002faf72f..c5112c1805 100644
--- a/_zh-cn/tour/higher-order-functions.md
+++ b/_zh-cn/tour/higher-order-functions.md
@@ -27,7 +27,7 @@ val salaries = Seq(20000, 70000, 40000)
val newSalaries = salaries.map(x => x * 2) // List(40000, 140000, 80000)
```
注意在上述示例中`x`没有被显式声明为Int类型,这是因为编译器能够根据map函数期望的类型推断出`x`的类型。对于上述代码,一种更惯用的写法为:
-```tut
+```scala mdoc
val salaries = Seq(20000, 70000, 40000)
val newSalaries = salaries.map(_ * 2)
```
@@ -47,7 +47,7 @@ case class WeeklyWeatherForecast(temperatures: Seq[Double]) {
## 接收函数作为参数的函数
使用高阶函数的一个原因是减少冗余的代码。比方说需要写几个方法以通过不同方式来提升员工工资,若不使用高阶函数,代码可能像这样:
-```tut
+```scala mdoc
object SalaryRaiser {
def smallPromotion(salaries: List[Double]): List[Double] =
@@ -63,7 +63,7 @@ object SalaryRaiser {
注意这三个方法的差异仅仅是提升的比例不同,为了简化代码,其实可以把重复的代码提到一个高阶函数中:
-```tut
+```scala mdoc:nest
object SalaryRaiser {
private def promotion(salaries: List[Double], promotionFunction: Double => Double): List[Double] =
@@ -86,7 +86,7 @@ object SalaryRaiser {
有一些情况你希望生成一个函数, 比如:
-```tut
+```scala mdoc
def urlBuilder(ssl: Boolean, domainName: String): (String, String) => String = {
val schema = if (ssl) "https://" else "http://"
(endpoint: String, query: String) => s"$schema$domainName/$endpoint?$query"
diff --git a/_zh-cn/tour/implicit-conversions.md b/_zh-cn/tour/implicit-conversions.md
index dc52248ffd..4c2d94cc0b 100644
--- a/_zh-cn/tour/implicit-conversions.md
+++ b/_zh-cn/tour/implicit-conversions.md
@@ -29,7 +29,7 @@ List(1, 2, 3) <= List(4, 5)
在 `scala.Predef.intWrapper` 已经自动提供了一个隐式方法 `Int => Ordered[Int]`。下面提供了一个隐式方法 `List[A] => Ordered[List[A]]` 的例子。
-```tut
+```scala mdoc
import scala.language.implicitConversions
implicit def list2ordered[A](x: List[A])
@@ -44,11 +44,11 @@ implicit def list2ordered[A](x: List[A])
例如,当调用一个接受 `java.lang.Integer` 作为参数的 Java 方法时,你完全可以传入一个 `scala.Int`。那是因为 Predef 包含了以下的隐式转换:
-```tut
+```scala mdoc
import scala.language.implicitConversions
-implicit def int2Integer(x: Int) =
- java.lang.Integer.valueOf(x)
+implicit def int2Integer(x: Int): Integer =
+ Integer.valueOf(x)
```
因为如果不加选择地使用隐式转换可能会导致陷阱,编译器会在编译隐式转换定义时发出警告。
diff --git a/_zh-cn/tour/implicit-parameters.md b/_zh-cn/tour/implicit-parameters.md
index 6e2c235baf..e8e89451e6 100644
--- a/_zh-cn/tour/implicit-parameters.md
+++ b/_zh-cn/tour/implicit-parameters.md
@@ -18,11 +18,11 @@ Scala 将查找这些参数的位置分为两类:
* Scala 在调用包含有隐式参数块的方法时,将首先查找可以直接访问的隐式定义和隐式参数 (无前缀)。
* 然后,它在所有伴生对象中查找与隐式候选类型相关的有隐式标记的成员。
-更加详细的关于 Scala 到哪里查找隐式参数的指南请参考 [常见问题](//docs.scala-lang.org/tutorials/FAQ/finding-implicits.html)
+更加详细的关于 Scala 到哪里查找隐式参数的指南请参考 [常见问题](/tutorials/FAQ/finding-implicits.html)
在下面的例子中,我们定义了一个方法 `sum`,它使用 Monoid 类的 `add` 和 `unit` 方法计算一个列表中元素的总和。 请注意,隐式值不能是顶级值。
-```tut
+```scala mdoc
abstract class Monoid[A] {
def add(x: A, y: A): A
def unit: A
diff --git a/_zh-cn/tour/inner-classes.md b/_zh-cn/tour/inner-classes.md
index 499dd26b19..a390c0b340 100644
--- a/_zh-cn/tour/inner-classes.md
+++ b/_zh-cn/tour/inner-classes.md
@@ -15,11 +15,11 @@ previous-page: lower-type-bounds
为了说明差异,我们简单描述了一个图形数据类型的实现:
-```tut
+```scala mdoc
class Graph {
class Node {
var connectedNodes: List[Node] = Nil
- def connectTo(node: Node) {
+ def connectTo(node: Node): Unit = {
if (!connectedNodes.exists(node.equals)) {
connectedNodes = node :: connectedNodes
}
@@ -35,7 +35,7 @@ class Graph {
```
该程序将图形表示为节点列表 (`List[Node]`)。 每个节点都有一个用来存储与其相连的其他节点的列表 (`connectedNodes`)。 类 `Node` 是一个 _路径依赖类型_,因为它嵌套在类 `Graph` 中。 因此,`connectedNodes` 中存储的所有节点必须使用同一个 `Graph` 的实例对象的 `newNode` 方法来创建。
-```tut
+```scala mdoc
val graph1: Graph = new Graph
val node1: graph1.Node = graph1.newNode
val node2: graph1.Node = graph1.newNode
@@ -48,7 +48,7 @@ node3.connectTo(node1)
如果我们现在有两个图形,Scala 的类型系统不允许我们将一个图形中定义的节点与另一个图形的节点混合,因为另一个图形的节点具有不同的类型。
下例是一个非法的程序:
-```
+```scala mdoc:fail
val graph1: Graph = new Graph
val node1: graph1.Node = graph1.newNode
val node2: graph1.Node = graph1.newNode
@@ -59,11 +59,11 @@ node1.connectTo(node3) // illegal!
```
类型 `graph1.Node` 与类型 `graph2.Node` 完全不同。 在 Java 中,上一个示例程序中的最后一行是正确的。 对于两个图形的节点,Java 将分配相同的类型 `Graph.Node`; 即 `Node` 以类 `Graph` 为前缀。 在Scala中也可以表示出这种类型,它写成了 `Graph#Node`。 如果我们希望能够连接不同图形的节点,我们必须通过以下方式更改图形类的初始实现的定义:
-```tut
+```scala mdoc:nest
class Graph {
class Node {
var connectedNodes: List[Graph#Node] = Nil
- def connectTo(node: Graph#Node) {
+ def connectTo(node: Graph#Node): Unit = {
if (!connectedNodes.exists(node.equals)) {
connectedNodes = node :: connectedNodes
}
@@ -77,4 +77,3 @@ class Graph {
}
}
```
-
\ No newline at end of file
diff --git a/_zh-cn/tour/lower-type-bounds.md b/_zh-cn/tour/lower-type-bounds.md
index 26c1bfba81..b511f52cf7 100644
--- a/_zh-cn/tour/lower-type-bounds.md
+++ b/_zh-cn/tour/lower-type-bounds.md
@@ -15,7 +15,7 @@ previous-page: upper-type-bounds
下面看一个适合用类型下界的例子:
-```tut:fail
+```scala mdoc:fail
trait Node[+B] {
def prepend(elem: B): Node[B]
}
@@ -37,7 +37,7 @@ case class Nil[+B]() extends Node[B] {
要解决这个问题,我们需要将方法 `prepend` 的参数 `elem` 的型变翻转。 我们通过引入一个新的类型参数 `U` 来实现这一点,该参数具有 `B` 作为类型下界。
-```tut
+```scala mdoc
trait Node[+B] {
def prepend[U >: B](elem: U): Node[U]
}
@@ -54,7 +54,7 @@ case class Nil[+B]() extends Node[B] {
```
现在我们像下面这么做:
-```tut
+```scala mdoc
trait Bird
case class AfricanSwallow() extends Bird
case class EuropeanSwallow() extends Bird
diff --git a/_zh-cn/tour/mixin-class-composition.md b/_zh-cn/tour/mixin-class-composition.md
index f51354554c..1b4c6bab36 100644
--- a/_zh-cn/tour/mixin-class-composition.md
+++ b/_zh-cn/tour/mixin-class-composition.md
@@ -13,7 +13,7 @@ previous-page: tuples
当某个特质被用于组合类时,被称为混入。
-```tut
+```scala mdoc
abstract class A {
val message: String
}
@@ -30,11 +30,11 @@ println(d.message) // I'm an instance of class B
println(d.loudMessage) // I'M AN INSTANCE OF CLASS B
```
-类`D`有一个父类`B`和一个混入`C`。一个类只能有一个父类但是可以有多个混入(分别使用关键字`extend`和`with`)。混入和某个父类可能有相同的父类。
+类`D`有一个父类`B`和一个混入`C`。一个类只能有一个父类但是可以有多个混入(分别使用关键字`extends`和`with`)。混入和某个父类可能有相同的父类。
现在,让我们看一个更有趣的例子,其中使用了抽象类:
-```tut
+```scala mdoc
abstract class AbsIterator {
type T
def hasNext: Boolean
@@ -46,7 +46,7 @@ abstract class AbsIterator {
接下来,我们将实现一个具体的类(所有的抽象成员`T`、`hasNext`和`next`都会被实现):
-```tut
+```scala mdoc
class StringIterator(s: String) extends AbsIterator {
type T = Char
private var i = 0
@@ -63,7 +63,7 @@ class StringIterator(s: String) extends AbsIterator {
现在我们创建一个特质,也继承于`AbsIterator`。
-```tut
+```scala mdoc
trait RichIterator extends AbsIterator {
def foreach(f: T => Unit): Unit = while (hasNext) f(next())
}
@@ -73,7 +73,7 @@ trait RichIterator extends AbsIterator {
下面我们要把`StringIterator`和`RichIterator` 中的功能组合成一个类。
-```tut
+```scala mdoc
object StringIteratorTest extends App {
class RichStringIter extends StringIterator("Scala") with RichIterator
val richStringIter = new RichStringIter
@@ -81,4 +81,4 @@ object StringIteratorTest extends App {
}
```
-新的类`RichStringIter`有一个父类`StringIterator`和一个混入`RichIterator`。如果是单一继承,我们将不会达到这样的灵活性。
\ No newline at end of file
+新的类`RichStringIter`有一个父类`StringIterator`和一个混入`RichIterator`。如果是单一继承,我们将不会达到这样的灵活性。
diff --git a/_zh-cn/tour/multiple-parameter-lists.md b/_zh-cn/tour/multiple-parameter-lists.md
index 6237d1fc37..d0c16aebb1 100644
--- a/_zh-cn/tour/multiple-parameter-lists.md
+++ b/_zh-cn/tour/multiple-parameter-lists.md
@@ -15,7 +15,7 @@ previous-page: nested-functions
下面是一个例子,在Scala集合 `trait TraversableOnce` 定义了 `foldLeft`
-```
+```scala mdoc:fail
def foldLeft[B](z: B)(op: (B, A) => B): B
```
@@ -23,7 +23,7 @@ def foldLeft[B](z: B)(op: (B, A) => B): B
从初值0开始, 这里 `foldLeft` 将函数 `(m, n) => m + n` 依次应用到列表中的每一个元素和之前累积的值上。
-```tut
+```scala mdoc
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val res = numbers.foldLeft(0)((m, n) => m + n)
print(res) // 55
@@ -34,18 +34,18 @@ print(res) // 55
#### 单一的函数参数
在某些情况下存在单一的函数参数时,例如上述例子`foldLeft`中的`op`,多参数列表可以使得传递匿名函数作为参数的语法更为简洁。如果不使用多参数列表,代码可能像这样:
-```
+```scala
numbers.foldLeft(0, {(m: Int, n: Int) => m + n})
```
注意使用多参数列表时,我们还可以利用Scala的类型推断来让代码更加简洁(如下所示),而如果没有多参数列表,这是不可能的。
-
-```
+
+```scala mdoc
numbers.foldLeft(0)(_ + _)
```
像上述语句这样,我们可以给定多参数列表的一部分参数列表(如上述的`z`)来形成一个新的函数(partially applied function),达到复用的目的,如下所示:
-```tut
+```scala mdoc:nest
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val numberFunc = numbers.foldLeft(List[Int]())_
@@ -57,7 +57,7 @@ print(cubes.toString()) // List(1, 8, 27, 64, 125, 216, 343, 512, 729, 1000)
```
最后,`foldLeft` 和 `foldRight` 可以按以下任意一种形式使用,
-```tut
+```scala mdoc:nest
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
numbers.foldLeft(0)((sum, item) => sum + item) // Generic Form
@@ -71,7 +71,7 @@ numbers.foldRight(0)(_+_) // Curried Form
#### 隐式(implicit)参数
如果要指定参数列表中的某些参数为隐式(implicit),应该使用多参数列表。例如:
-```
+```scala
def execute(arg: Int)(implicit ec: ExecutionContext) = ???
```
diff --git a/_zh-cn/tour/named-arguments.md b/_zh-cn/tour/named-arguments.md
index 16fa1f0e12..2a25884bec 100644
--- a/_zh-cn/tour/named-arguments.md
+++ b/_zh-cn/tour/named-arguments.md
@@ -13,7 +13,7 @@ previous-page: default-parameter-values
当调用方法时,实际参数可以通过其对应的形式参数的名称来标记:
-```tut
+```scala mdoc
def printName(first: String, last: String): Unit = {
println(first + " " + last)
}
@@ -24,7 +24,7 @@ printName(last = "Smith", first = "John") // Prints "John Smith"
```
注意使用命名参数时,顺序是可以重新排列的。 但是,如果某些参数被命名了,而其他参数没有,则未命名的参数要按照其方法签名中的参数顺序放在前面。
-```tut:fail
+```scala mdoc:fail
printName(last = "Smith", "john") // error: positional after named argument
```
diff --git a/_zh-cn/tour/nested-functions.md b/_zh-cn/tour/nested-functions.md
index 60d9f1c9ac..388c04503f 100644
--- a/_zh-cn/tour/nested-functions.md
+++ b/_zh-cn/tour/nested-functions.md
@@ -13,7 +13,7 @@ previous-page: higher-order-functions
在Scala中可以嵌套定义方法。例如以下对象提供了一个`factorial`方法来计算给定数值的阶乘:
-```tut
+```scala mdoc
def factorial(x: Int): Int = {
def fact(x: Int, accumulator: Int): Int = {
if (x <= 1) accumulator
diff --git a/_zh-cn/tour/operators.md b/_zh-cn/tour/operators.md
index 18b5283eaa..9bca79a928 100644
--- a/_zh-cn/tour/operators.md
+++ b/_zh-cn/tour/operators.md
@@ -22,7 +22,7 @@ previous-page: type-inference
## 定义和使用运算符
你可以使用任何合法标识符作为运算符。 包括像 `add` 这样的名字或像 `+` 这样的符号。
-```tut
+```scala mdoc
case class Vec(x: Double, y: Double) {
def +(that: Vec) = Vec(this.x + that.x, this.y + that.y)
}
@@ -36,7 +36,7 @@ vector3.y // 3.0
```
类 Vec 有一个方法 `+`,我们用它来使 `vector1` 和 `vector2` 相加。 使用圆括号,你可以使用易读的语法来构建复杂表达式。 这是 `MyBool` 类的定义,其中有方法 `and` 和 `or`:
-```tut
+```scala mdoc
case class MyBool(x: Boolean) {
def and(that: MyBool): MyBool = if (x) that else this
def or(that: MyBool): MyBool = if (x) this else that
@@ -46,7 +46,7 @@ case class MyBool(x: Boolean) {
现在可以使用 `and` 和 `or` 作为中缀运算符:
-```tut
+```scala mdoc
def not(x: MyBool) = x.negate
def xor(x: MyBool, y: MyBool) = (x or y) and not(x and y)
```
@@ -65,7 +65,7 @@ def xor(x: MyBool, y: MyBool) = (x or y) and not(x and y)
&
^
|
-(all letters)
+(all letters, $, _)
```
这也适用于你自定义的方法。 例如,以下表达式:
```
diff --git a/_zh-cn/tour/packages-and-imports.md b/_zh-cn/tour/packages-and-imports.md
index 412e1029b7..883c961345 100644
--- a/_zh-cn/tour/packages-and-imports.md
+++ b/_zh-cn/tour/packages-and-imports.md
@@ -68,7 +68,7 @@ import users.{UserPreferences => UPrefs} // 导入类并且设置别名
Scala 不同于 Java 的一点是 Scala 可以在任何地方使用导入:
-```tut
+```scala mdoc
def sqrtplus1(x: Int) = {
import scala.math.sqrt
sqrt(x) + 1.0
diff --git a/_zh-cn/tour/pattern-matching.md b/_zh-cn/tour/pattern-matching.md
index 0666957531..36ad508a7c 100644
--- a/_zh-cn/tour/pattern-matching.md
+++ b/_zh-cn/tour/pattern-matching.md
@@ -16,7 +16,7 @@ previous-page: case-classes
## 语法
一个模式匹配语句包括一个待匹配的值,`match`关键字,以及至少一个`case`语句。
-```tut
+```scala mdoc
import scala.util.Random
val x: Int = Random.nextInt(10)
@@ -31,7 +31,7 @@ x match {
上述代码中的`val x`是一个0到10之间的随机整数,将它放在`match`运算符的左侧对其进行模式匹配,`match`的右侧是包含4条`case`的表达式,其中最后一个`case _`表示匹配其余所有情况,在这里就是其他可能的整型值。
`match`表达式具有一个结果值
-```tut
+```scala mdoc
def matchTest(x: Int): String = x match {
case 1 => "one"
case 2 => "two"
@@ -42,11 +42,11 @@ matchTest(1) // one
```
这个`match`表达式是String类型的,因为所有的情况(case)均返回String,所以`matchTest`函数的返回值是String类型。
-## 案例类(case classes)的匹配
+## 样例类(case classes)的匹配
-案例类非常适合用于模式匹配。
+样例类非常适合用于模式匹配。
-```tut
+```scala mdoc
abstract class Notification
case class Email(sender: String, title: String, body: String) extends Notification
@@ -58,7 +58,7 @@ case class VoiceRecording(contactName: String, link: String) extends Notificatio
```
-`Notification` 是一个虚基类,它有三个具体的子类`Email`, `SMS`和`VoiceRecording`,我们可以在这些案例类(Case Class)上像这样使用模式匹配:
+`Notification` 是一个虚基类,它有三个具体的子类`Email`, `SMS`和`VoiceRecording`,我们可以在这些样例类(Case Class)上像这样使用模式匹配:
```
def showNotification(notification: Notification): String = {
@@ -80,7 +80,7 @@ println(showNotification(someVoiceRecording)) // you received a Voice Recording
```
`showNotification`函数接受一个抽象类`Notification`对象作为输入参数,然后匹配其具体类型。(也就是判断它是一个`Email`,`SMS`,还是`VoiceRecording`)。在`case Email(sender, title, _)`中,对象的`sender`和`title`属性在返回值中被使用,而`body`属性则被忽略,故使用`_`代替。
-## 模式守卫(Pattern gaurds)
+## 模式守卫(Pattern guards)
为了让匹配更加具体,可以使用模式守卫,也就是在模式后面加上`if `。
```
@@ -113,7 +113,7 @@ println(showImportantNotification(importantSms, importantPeopleInfo))
## 仅匹配类型
也可以仅匹配类型,如下所示:
-```tut
+```scala mdoc
abstract class Device
case class Phone(model: String) extends Device {
def screenOff = "Turning screen off"
@@ -133,7 +133,7 @@ def goIdle(device: Device) = device match {
特质(trait)和类(class)可以用`sealed`标记为密封的,这意味着其所有子类都必须与之定义在相同文件中,从而保证所有子类型都是已知的。
-```tut
+```scala mdoc
sealed abstract class Furniture
case class Couch() extends Furniture
case class Chair() extends Furniture
@@ -147,5 +147,5 @@ def findPlaceToSit(piece: Furniture): String = piece match {
## 备注
-Scala的模式匹配语句对于使用[案例类(case classes)](case-classes.html)表示的类型非常有用,同时也可以利用[提取器对象(extractor objects)](extractor-objects.html)中的`unapply`方法来定义非案例类对象的匹配。
+Scala的模式匹配语句对于使用[样例类(case classes)](case-classes.html)表示的类型非常有用,同时也可以利用[提取器对象(extractor objects)](extractor-objects.html)中的`unapply`方法来定义非样例类对象的匹配。
diff --git a/_zh-cn/tour/polymorphic-methods.md b/_zh-cn/tour/polymorphic-methods.md
index 2b1a102b96..8b195febc5 100644
--- a/_zh-cn/tour/polymorphic-methods.md
+++ b/_zh-cn/tour/polymorphic-methods.md
@@ -15,7 +15,7 @@ Scala 中的方法可以按类型和值进行参数化。 语法和泛型类类
看下面的例子:
-```tut
+```scala mdoc
def listOfDuplicates[A](x: A, length: Int): List[A] = {
if (length < 1)
Nil
diff --git a/_zh-cn/tour/regular-expression-patterns.md b/_zh-cn/tour/regular-expression-patterns.md
index 856ce7de4c..9709c0ade8 100644
--- a/_zh-cn/tour/regular-expression-patterns.md
+++ b/_zh-cn/tour/regular-expression-patterns.md
@@ -14,7 +14,7 @@ previous-page: singleton-objects
正则表达式是用来找出数据中的指定模式(或缺少该模式)的字符串。`.r`方法可使任意字符串变成一个正则表达式。
-```tut
+```scala mdoc
import scala.util.matching.Regex
val numberPattern: Regex = "[0-9]".r
@@ -29,7 +29,7 @@ numberPattern.findFirstMatchIn("awesomepassword") match {
你还可以使用括号来同时匹配多组正则表达式。
-```tut
+```scala mdoc
import scala.util.matching.Regex
val keyValPattern: Regex = "([0-9a-zA-Z-#() ]+): ([0-9a-zA-Z-#() ]+)".r
diff --git a/_zh-cn/tour/self-types.md b/_zh-cn/tour/self-types.md
index 061cb4e986..c30e900480 100644
--- a/_zh-cn/tour/self-types.md
+++ b/_zh-cn/tour/self-types.md
@@ -15,7 +15,7 @@ previous-page: compound-types
自类型是一种细化 `this` 或 `this` 别名之类型的方法。 语法看起来像普通函数语法,但是意义完全不一样。
要在特质中使用自类型,写一个标识符,跟上要混入的另一个特质,以及 `=>`(例如 `someIdentifier: SomeOtherTrait =>`)。
-```tut
+```scala mdoc
trait User {
def username: String
}
diff --git a/_zh-cn/tour/singleton-objects.md b/_zh-cn/tour/singleton-objects.md
index f970a7ed24..1177e92d49 100644
--- a/_zh-cn/tour/singleton-objects.md
+++ b/_zh-cn/tour/singleton-objects.md
@@ -19,7 +19,7 @@ previous-page: pattern-matching
# 定义一个单例对象
一个单例对象是就是一个值。单例对象的定义方式很像类,但是使用关键字 `object`:
-```tut
+```scala mdoc
object Box
```
@@ -76,7 +76,7 @@ circle1.area
这里的 `class Circle` 有一个成员 `area` 是和具体的实例化对象相关的,单例对象 `object Circle` 包含一个方法 `calculateArea` ,它在每一个实例化对象中都是可见的。
伴生对象也可以包含工厂方法:
-```tut
+```scala mdoc
class Email(val username: String, val domainName: String)
object Email {
diff --git a/_zh-cn/tour/tour-of-scala.md b/_zh-cn/tour/tour-of-scala.md
index 387eff8c14..78b70dd115 100644
--- a/_zh-cn/tour/tour-of-scala.md
+++ b/_zh-cn/tour/tour-of-scala.md
@@ -13,7 +13,7 @@ next-page: basics
## 欢迎来到Scala之旅
本次 Scala 之旅教程包含了对于大多数 Scala 特性的简单介绍。主要针对 Scala 这门语言的初学者。
-这是个简化的教程,如果希望得到完整的话,可以考虑购买[书籍](/books.html)或者参考[其他资源](/learn.html)。
+这是个简化的教程,如果希望得到完整的话,可以考虑购买[书籍](/books.html)或者参考[其他资源](/online-courses.html)。
## Scala是什么?
Scala是一门现代的多范式语言,志在以简洁、优雅及类型安全的方式来表达常用的编程模型。它平滑地集成了面向对象和函数式语言的特性。
@@ -58,4 +58,4 @@ Scala设计的目标是与流行的Java运行环境(JRE)进行良好的互
## 尽享学习之乐
-请点击菜单上的[下一页](basics.html)继续阅读。
\ No newline at end of file
+请点击菜单上的[下一页](basics.html)继续阅读。
diff --git a/_zh-cn/tour/traits.md b/_zh-cn/tour/traits.md
index 7e37bf5d23..83b7a39633 100644
--- a/_zh-cn/tour/traits.md
+++ b/_zh-cn/tour/traits.md
@@ -20,12 +20,12 @@ prerequisite-knowledge: expressions, classes, generics, objects, companion-objec
## 定义一个特质
最简化的特质就是关键字trait+标识符:
-```tut
+```scala mdoc
trait HairColor
```
特征作为泛型类型和抽象方法非常有用。
-```tut
+```scala mdoc
trait Iterator[A] {
def hasNext: Boolean
def next(): A
@@ -37,7 +37,7 @@ trait Iterator[A] {
## 使用特质
使用 `extends` 关键字来扩展特征。然后使用 `override` 关键字来实现trait里面的任何抽象成员:
-```tut
+```scala mdoc:nest
trait Iterator[A] {
def hasNext: Boolean
def next(): A
@@ -64,7 +64,7 @@ iterator.next() // returns 1
## 子类型
凡是需要特质的地方,都可以由该特质的子类型来替换。
-```tut
+```scala mdoc
import scala.collection.mutable.ArrayBuffer
trait Pet {
diff --git a/_zh-cn/tour/tuples.md b/_zh-cn/tour/tuples.md
index 97f083a98e..871c70c3b5 100644
--- a/_zh-cn/tour/tuples.md
+++ b/_zh-cn/tour/tuples.md
@@ -19,7 +19,7 @@ topics: tuples
元组可以创建如下:
-```tut
+```scala mdoc
val ingredient = ("Sugar" , 25):Tuple2[String, Int]
```
这将创建一个包含一个 String 元素和一个 Int 元素的元组。
@@ -34,7 +34,7 @@ Scala 中的元组包含一系列类:Tuple2,Tuple3等,直到 Tuple22。
使用下划线语法来访问元组中的元素。
'tuple._n' 取出了第 n 个元素(假设有足够多元素)。
-```tut
+```scala mdoc
println(ingredient._1) // Sugar
println(ingredient._2) // 25
@@ -44,7 +44,7 @@ println(ingredient._2) // 25
Scala 元组也支持解构。
-```tut
+```scala mdoc
val (name, quantity) = ingredient
println(name) // Sugar
@@ -54,7 +54,7 @@ println(quantity) // 25
元组解构也可用于模式匹配。
-```tut
+```scala mdoc
val planetDistanceFromSun = List(("Mercury", 57.9), ("Venus", 108.2), ("Earth", 149.6 ), ("Mars", 227.9), ("Jupiter", 778.3))
planetDistanceFromSun.foreach{ tuple => {
@@ -78,7 +78,7 @@ planetDistanceFromSun.foreach{ tuple => {
或者,在 'for' 表达式中。
-```tut
+```scala mdoc
val numPairs = List((2, 5), (3, -7), (20, 56))
for ((a, b) <- numPairs) {
diff --git a/_zh-cn/tour/type-inference.md b/_zh-cn/tour/type-inference.md
index e3dd33a0c8..3b50faf3a4 100644
--- a/_zh-cn/tour/type-inference.md
+++ b/_zh-cn/tour/type-inference.md
@@ -15,19 +15,19 @@ Scala 编译器通常可以推断出表达式的类型,因此你不必显式
## 省略类型
-```tut
+```scala mdoc
val businessName = "Montreux Jazz Café"
```
编译器可以发现 `businessName` 是 String 类型。 它的工作原理和方法类似:
-```tut
+```scala mdoc
def squareOf(x: Int) = x * x
```
编译器可以推断出方法的返回类型为 `Int`,因此不需要明确地声明返回类型。
对于递归方法,编译器无法推断出结果类型。 下面这个程序就是由于这个原因而编译失败:
-```tut:fail
+```scala mdoc:fail
def fac(n: Int) = if (n == 0) 1 else n * fac(n - 1)
```
@@ -35,7 +35,7 @@ def fac(n: Int) = if (n == 0) 1 else n * fac(n - 1)
看下面两个例子:
-```tut
+```scala mdoc
case class MyPair[A, B](x: A, y: B)
val p = MyPair(1, "scala") // type: MyPair[Int, String]
@@ -49,7 +49,7 @@ val q = id(1) // type: Int
编译器从不推断方法形式参数的类型。 但是,在某些情况下,当函数作为参数传递时,编译器可以推断出匿名函数形式参数的类型。
-```tut
+```scala mdoc
Seq(1, 3, 4).map(x => x * 2) // List(2, 6, 8)
```
@@ -61,13 +61,13 @@ Seq(1, 3, 4).map(x => x * 2) // List(2, 6, 8)
此外,类型推断有时会推断出太具体的类型。 假设我们这么写:
-```tut
+```scala
var obj = null
```
我们就不能进行重新赋值:
-```tut:fail
+```scala mdoc:fail
obj = new AnyRef
```
diff --git a/_zh-cn/tour/unified-types.md b/_zh-cn/tour/unified-types.md
index 47e9db8f3f..904684e4dc 100644
--- a/_zh-cn/tour/unified-types.md
+++ b/_zh-cn/tour/unified-types.md
@@ -27,7 +27,7 @@ prerequisite-knowledge: classes, basics
这里有一个例子,说明了字符串、整型、布尔值和函数都是对象,这一点和其他对象一样:
-```tut
+```scala mdoc
val list: List[Any] = List(
"a string",
732, // an integer
@@ -57,9 +57,9 @@ true
例如:
-```tut
+```scala mdoc
val x: Long = 987654321
-val y: Float = x // 9.8765434E8 (note that some precision is lost in this case)
+val y: Float = x.toFloat // 9.8765434E8 (note that some precision is lost in this case)
val face: Char = '☺'
val number: Int = face // 9786
@@ -69,7 +69,7 @@ val number: Int = face // 9786
```
val x: Long = 987654321
-val y: Float = x // 9.8765434E8
+val y: Float = x.toFloat // 9.8765434E8
val z: Long = y // Does not conform
```
diff --git a/_zh-cn/tour/upper-type-bounds.md b/_zh-cn/tour/upper-type-bounds.md
index 6baf50b6ab..917bc3e2e4 100644
--- a/_zh-cn/tour/upper-type-bounds.md
+++ b/_zh-cn/tour/upper-type-bounds.md
@@ -13,7 +13,7 @@ previous-page: variances
在Scala中,[类型参数](generic-classes.html)和[抽象类型](abstract-type-members.html)都可以有一个类型边界约束。这种类型边界在限制类型变量实际取值的同时还能展露类型成员的更多信息。比如像`T <: A`这样声明的类型上界表示类型变量`T`应该是类型`A`的子类。下面的例子展示了类`PetContainer`的一个类型参数的类型上界。
-```tut
+```scala mdoc
abstract class Animal {
def name: String
}
@@ -40,7 +40,7 @@ val dogContainer = new PetContainer[Dog](new Dog)
val catContainer = new PetContainer[Cat](new Cat)
```
-```tut:fail
+```scala mdoc:fail
// this would not compile
val lionContainer = new PetContainer[Lion](new Lion)
```
diff --git a/_zh-cn/tour/variances.md b/_zh-cn/tour/variances.md
index 257c1a78d6..ecd5249a35 100644
--- a/_zh-cn/tour/variances.md
+++ b/_zh-cn/tour/variances.md
@@ -13,7 +13,7 @@ previous-page: generic-classes
型变是复杂类型的子类型关系与其组件类型的子类型关系的相关性。 Scala支持 [泛型类](generic-classes.html) 的类型参数的型变注释,允许它们是协变的,逆变的,或在没有使用注释的情况下是不变的。 在类型系统中使用型变允许我们在复杂类型之间建立直观的连接,而缺乏型变则会限制类抽象的重用性。
-```tut
+```scala mdoc
class Foo[+A] // A covariant class
class Bar[-A] // A contravariant class
class Baz[A] // An invariant class
@@ -25,7 +25,7 @@ class Baz[A] // An invariant class
考虑以下简单的类结构:
-```tut
+```scala mdoc
abstract class Animal {
def name: String
}
@@ -37,7 +37,7 @@ case class Dog(name: String) extends Animal
在下例中,方法 `printAnimalNames` 将接受动物列表作为参数,并且逐行打印出它们的名称。 如果 `List[A]` 不是协变的,最后两个方法调用将不能编译,这将严重限制 `printAnimalNames` 方法的适用性。
-```tut
+```scala mdoc
object CovarianceTest extends App {
def printAnimalNames(animals: List[Animal]): Unit = {
animals.foreach { animal =>
@@ -64,7 +64,7 @@ object CovarianceTest extends App {
考虑在下例中使用上面定义的类 `Cat`,`Dog` 和 `Animal` :
-```tut
+```scala mdoc
abstract class Printer[-A] {
def print(value: A): Unit
}
@@ -72,7 +72,7 @@ abstract class Printer[-A] {
这里 `Printer[A]` 是一个简单的类,用来打印出某种类型的 `A`。 让我们定义一些特定的子类:
-```tut
+```scala mdoc
class AnimalPrinter extends Printer[Animal] {
def print(animal: Animal): Unit =
println("The animal's name is: " + animal.name)
@@ -86,7 +86,7 @@ class CatPrinter extends Printer[Cat] {
如果 `Printer[Cat]` 知道如何在控制台打印出任意 `Cat`,并且 `Printer[Animal]` 知道如何在控制台打印出任意 `Animal`,那么 `Printer[Animal]` 也应该知道如何打印出 `Cat` 就是合理的。 反向关系不适用,因为 `Printer[Cat]` 并不知道如何在控制台打印出任意 `Animal`。 因此,如果我们愿意,我们应该能够用 `Printer[Animal]` 替换 `Printer[Cat]`,而使 `Printer[A]` 逆变允许我们做到这一点。
-```tut
+```scala mdoc
object ContravarianceTest extends App {
val myCat: Cat = Cat("Boots")
@@ -113,7 +113,7 @@ The animal's name is: Boots
默认情况下,Scala中的泛型类是不变的。 这意味着它们既不是协变的也不是逆变的。 在下例中,类 `Container` 是不变的。 `Container[Cat]` _不是_ `Container[Animal]`,反之亦然。
-```tut
+```scala mdoc
class Container[A](value: A) {
private var _value: A = value
def getValue: A = _value
@@ -140,7 +140,7 @@ val cat: Cat = catContainer.getValue // 糟糕,我们最终会将一只狗作
假设前面使用过的类似 `Cat`,`Dog`,`Animal` 的继承关系,加上以下内容:
-```tut
+```scala mdoc
abstract class SmallAnimal extends Animal
case class Mouse(name: String) extends SmallAnimal
```
diff --git a/_zh-cn/tutorials/scala-for-java-programmers.md b/_zh-cn/tutorials/scala-for-java-programmers.md
index 9ee8838b4d..a3327a1963 100644
--- a/_zh-cn/tutorials/scala-for-java-programmers.md
+++ b/_zh-cn/tutorials/scala-for-java-programmers.md
@@ -18,7 +18,7 @@ Lightsing 译
这里用标准的 *Hello world* 程序作为第一个例子。虽然它很无趣,但让我们可以用少量语言特质来演示 Scala 工具。程序如下:
object HelloWorld {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
println("Hello, world!")
}
}
@@ -60,7 +60,7 @@ Java 的标准函数库定义了一些有用的工具类,如 `Date` 跟 `DateF
import java.text.DateFormat._
object FrenchDate {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val now = new Date
val df = getDateInstance(LONG, Locale.FRANCE)
println(df format now)
@@ -114,7 +114,7 @@ Scala 中的函数也是对象,所以将函数当做对象传递、把它们
def timeFlies() {
println("time flies like an arrow...")
}
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
oncePerSecond(timeFlies)
}
}
@@ -129,7 +129,7 @@ Scala 中的函数也是对象,所以将函数当做对象传递、把它们
def oncePerSecond(callback: () => Unit) {
while (true) { callback(); Thread sleep 1000 }
}
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
oncePerSecond(() =>
println("time flies like an arrow..."))
}
@@ -157,7 +157,7 @@ Scala 中的函数也是对象,所以将函数当做对象传递、把它们
函数 `re`、`im` 有个小问题,为了调用函数,我们必须在函数名称后面加上一对空括号,如这个例子:
object ComplexNumbers {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val c = new Complex(1.2, 3.4)
println("imaginary part: " + c.im())
}
@@ -261,7 +261,7 @@ Java 中我们会将这个树用一个抽象父类表示,然后每种节点跟
我们还没有探讨完模式匹配的全部功能,不过为了让这份文件保持简短,先就此打住。我们还是希望能看到这两个函数在真正的示例如何作用。因此让我们写一个简单的 `main` 函数,对表达式 `(x+x)+(7+y)` 做一些操作:先在环境 `{ x -> 5, y -> 7 }` 下计算结果,然后在对 `x` 接着对 `y` 取导数。
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val exp: Tree = Sum(Sum(Var("x"),Var("x")),Sum(Const(7),Var("y")))
val env: Environment = { case "x" => 5 case "y" => 7 }
println("Expression: " + exp)
@@ -308,7 +308,7 @@ Java 中我们会将这个树用一个抽象父类表示,然后每种节点跟
def year = y
def month = m
def day = d
- override def toString(): String = year + "-" + month + "-" + day
+ override def toString(): String = s"$year-$month-$day"
这边要注意的是声明在类名称跟参数之后的 `extends Ord`。这个语法声明了 `Date` 继承 `Ord` 特质。
@@ -361,7 +361,7 @@ Scala 借由可定义泛型类 (跟函数) 来解决这问题。让我们借由
为了使用 `Reference` 类型,我们必须指定 `T`,也就是这容器所包容的元素类型。举例来说,创造并使用该容器来容纳整数,我们可以这样写:
object IntegerReference {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val cell = new Reference[Int]
cell.set(13)
println("Reference contains the half of " + (cell.get * 2))
diff --git a/_zh-tw/tutorials/scala-for-java-programmers.md b/_zh-tw/tutorials/scala-for-java-programmers.md
index 290ee22ac3..333744ecea 100755
--- a/_zh-tw/tutorials/scala-for-java-programmers.md
+++ b/_zh-tw/tutorials/scala-for-java-programmers.md
@@ -18,7 +18,7 @@ Chikei Lee 譯
這邊用標準的 *Hello world* 程式作為第一個例子。雖然它很無趣,可是這讓我們在僅用少量語言特性下演示 Scala 工具。程式如下:
object HelloWorld {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
println("Hello, world!")
}
}
@@ -60,7 +60,7 @@ Java 的標準函式庫定義了一些有用的工具類別,如 `Date` 跟 `Da
import java.text.DateFormat._
object FrenchDate {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val now = new Date
val df = getDateInstance(LONG, Locale.FRANCE)
println(df format now)
@@ -114,7 +114,7 @@ Scala 是一個純粹的物件導向語言,這句話的意思是說,*所有
def timeFlies() {
println("time flies like an arrow...")
}
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
oncePerSecond(timeFlies)
}
}
@@ -129,7 +129,7 @@ Scala 是一個純粹的物件導向語言,這句話的意思是說,*所有
def oncePerSecond(callback: () => Unit) {
while (true) { callback(); Thread sleep 1000 }
}
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
oncePerSecond(() =>
println("time flies like an arrow..."))
}
@@ -157,7 +157,7 @@ Scala 是一個純粹的物件導向語言,這句話的意思是說,*所有
函式 `re`、`im` 有個小問題,為了呼叫函式,我們必須在函式名稱後面加上一對空括號,如這個例子:
object ComplexNumbers {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val c = new Complex(1.2, 3.4)
println("imaginary part: " + c.im())
}
@@ -261,7 +261,7 @@ Java 中我們會將這個樹用一個抽象母類別表示,然後每種節點
我們還沒有探討完模式匹配的全部功能,不過為了讓這份文件保持簡短,先就此打住。我們還是希望能看到這兩個函式在真正的範例如何作用。因此讓我們寫一個簡單的 `main` 函數,對表示式 `(x+x)+(7+y)` 做一些操作:先在環境 `{ x -> 5, y -> 7 }` 下計算結果,然後在對 `x` 接著對 `y` 取導數。
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val exp: Tree = Sum(Sum(Var("x"),Var("x")),Sum(Const(7),Var("y")))
val env: Environment = { case "x" => 5 case "y" => 7 }
println("Expression: " + exp)
@@ -308,7 +308,7 @@ Java 中我們會將這個樹用一個抽象母類別表示,然後每種節點
def year = y
def month = m
def day = d
- override def toString(): String = year + "-" + month + "-" + day
+ override def toString(): String = s"$year-$month-$day"
這邊要注意的是宣告在類別名稱跟參數之後的 `extends Ord`。這個語法宣告了 `Date` 繼承 `Ord` 特質。
@@ -361,7 +361,7 @@ Scala 藉由可定義泛型類別 (跟函式) 來解決這問題。讓我們藉
為了使用 `Reference` 類型,我們必須指定 `T`,也就是這容器所包容的元素型別。舉例來說,創造並使用該容器來容納整數,我們可以這樣寫:
object IntegerReference {
- def main(args: Array[String]) {
+ def main(args: Array[String]): Unit = {
val cell = new Reference[Int]
cell.set(13)
println("Reference contains the half of " + (cell.get * 2))
diff --git a/api/all.md b/api/all.md
index 0ca4d83e28..6f049664b7 100644
--- a/api/all.md
+++ b/api/all.md
@@ -2,22 +2,28 @@
layout: singlepage-overview
title: Scala API Docs
includeTOC: true
+redirect_from:
+ - /reference.html
---
## Latest releases
-* Scala 2.13.3
- * [Library API](https://www.scala-lang.org/api/2.13.3/)
- * [Compiler API](https://www.scala-lang.org/api/2.13.3/scala-compiler/scala/)
- * [Reflection API](https://www.scala-lang.org/api/2.13.3/scala-reflect/scala/reflect/)
-* Scala 2.12.12
- * [Library API](https://www.scala-lang.org/api/2.12.12/)
- * [Compiler API](https://www.scala-lang.org/api/2.12.12/scala-compiler/scala/)
- * [Reflection API](https://www.scala-lang.org/api/2.12.12/scala-reflect/scala/reflect/)
+* Scala {{site.scala-3-version}}
+ * [Library API](https://www.scala-lang.org/api/{{site.scala-3-version}}/)
+* Scala 3.3.6 LTS
+ * [Library API](https://www.scala-lang.org/api/3.3.6/)
+* Scala 2.13.16
+ * [Library API](https://www.scala-lang.org/api/2.13.16/)
+ * [Compiler API](https://www.scala-lang.org/api/2.13.16/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.13.16/scala-reflect/scala/reflect/)
+* Scala 2.12.20
+ * [Library API](https://www.scala-lang.org/api/2.12.20/)
+ * [Compiler API](https://www.scala-lang.org/api/2.12.20/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.12.20/scala-reflect/scala/reflect/)
* Scala Modules
- * [XML API](https://www.scala-lang.org/api/2.12.12/scala-xml/scala/xml/)
- * [Parser Combinators API](https://www.scala-lang.org/api/2.12.12/scala-parser-combinators/scala/util/parsing/)
- * [Swing API](https://www.scala-lang.org/api/2.12.12/scala-swing/scala/swing/)
+ * [XML API](https://www.scala-lang.org/api/2.12.20/scala-xml/scala/xml/)
+ * [Parser Combinators API](https://www.scala-lang.org/api/2.12.20/scala-parser-combinators/scala/util/parsing/)
+ * [Swing API](https://www.scala-lang.org/api/2.12.20/scala-swing/scala/swing/)
* Scala 2.11.12
* [Library API](https://www.scala-lang.org/api/2.11.12/)
* [Compiler API](https://www.scala-lang.org/api/2.11.12/scala-compiler/)
@@ -41,18 +47,127 @@ includeTOC: true
## Nightly builds
+API documentation for nightly builds is not currently available in browsable form.
+
+Jars of nightly builds, including scaladoc jars, are available from
+https://scala-ci.typesafe.com/artifactory/scala-integration/org/scala-lang/
+
+
## Previous releases
+* Scala 3.7.0
+ * [Library API](https://www.scala-lang.org/api/3.7.0/)
+* Scala 3.6.4
+ * [Library API](https://www.scala-lang.org/api/3.6.4/)
+* Scala 3.6.3
+ * [Library API](https://www.scala-lang.org/api/3.6.3/)
+* Scala 3.6.2
+ * [Library API](https://www.scala-lang.org/api/3.6.2/)
+* Scala 3.5.2
+ * [Library API](https://www.scala-lang.org/api/3.5.2/)
+* Scala 3.5.1
+ * [Library API](https://www.scala-lang.org/api/3.5.1/)
+* Scala 3.5.0
+ * [Library API](https://www.scala-lang.org/api/3.5.0/)
+* Scala 3.4.3
+ * [Library API](https://www.scala-lang.org/api/3.4.3/)
+* Scala 3.4.2
+ * [Library API](https://www.scala-lang.org/api/3.4.2/)
+* Scala 3.4.1
+ * [Library API](https://www.scala-lang.org/api/3.4.1/)
+* Scala 3.4.0
+ * [Library API](https://www.scala-lang.org/api/3.4.0/)
+* Scala 3.3.5 LTS
+ * [Library API](https://www.scala-lang.org/api/3.3.5/)
+* Scala 3.3.4 LTS
+ * [Library API](https://www.scala-lang.org/api/3.3.4/)
+* Scala 3.3.3 LTS
+ * [Library API](https://www.scala-lang.org/api/3.3.3/)
+* Scala 3.3.1 LTS
+ * [Library API](https://www.scala-lang.org/api/3.3.1/)
+* Scala 3.3.0 LTS
+ * [Library API](https://www.scala-lang.org/api/3.3.0/)
+* Scala 3.2.2
+ * [Library API](https://www.scala-lang.org/api/3.2.2/)
+* Scala 3.2.1
+ * [Library API](https://www.scala-lang.org/api/3.2.1/)
+* Scala 3.2.0
+ * [Library API](https://www.scala-lang.org/api/3.2.0/)
+* Scala 3.1.3
+ * [Library API](https://www.scala-lang.org/api/3.1.3/)
+* Scala 3.1.2
+ * [Library API](https://www.scala-lang.org/api/3.1.2/)
+* Scala 3.1.1
+ * [Library API](https://www.scala-lang.org/api/3.1.1/)
+* Scala 3.1.0
+ * [Library API](https://www.scala-lang.org/api/3.1.0/)
+* Scala 3.0.2
+ * [Library API](https://www.scala-lang.org/api/3.0.2/)
+* Scala 3.0.1
+ * [Library API](https://www.scala-lang.org/api/3.0.1/)
+* Scala 3.0.0
+ * [Library API](https://www.scala-lang.org/api/3.0.0/)
+* Scala 2.13.15
+ * [Library API](https://www.scala-lang.org/api/2.13.15/)
+ * [Compiler API](https://www.scala-lang.org/api/2.13.15/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.13.15/scala-reflect/scala/reflect/)
+* Scala 2.13.14
+ * [Library API](https://www.scala-lang.org/api/2.13.14/)
+ * [Compiler API](https://www.scala-lang.org/api/2.13.14/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.13.14/scala-reflect/scala/reflect/)
+* Scala 2.13.13
+ * [Library API](https://www.scala-lang.org/api/2.13.13/)
+ * [Compiler API](https://www.scala-lang.org/api/2.13.13/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.13.13/scala-reflect/scala/reflect/)
+* Scala 2.13.12
+ * [Library API](https://www.scala-lang.org/api/2.13.12/)
+ * [Compiler API](https://www.scala-lang.org/api/2.13.12/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.13.12/scala-reflect/scala/reflect/)
+* Scala 2.13.11
+ * [Library API](https://www.scala-lang.org/api/2.13.11/)
+ * [Compiler API](https://www.scala-lang.org/api/2.13.11/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.13.11/scala-reflect/scala/reflect/)
+* Scala 2.13.10
+ * [Library API](https://www.scala-lang.org/api/2.13.10/)
+ * [Compiler API](https://www.scala-lang.org/api/2.13.10/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.13.10/scala-reflect/scala/reflect/)
+* Scala 2.13.9
+ * [Library API](https://www.scala-lang.org/api/2.13.9/)
+ * [Compiler API](https://www.scala-lang.org/api/2.13.9/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.13.9/scala-reflect/scala/reflect/)
+* Scala 2.13.8
+ * [Library API](https://www.scala-lang.org/api/2.13.8/)
+ * [Compiler API](https://www.scala-lang.org/api/2.13.8/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.13.8/scala-reflect/scala/reflect/)
+* Scala 2.13.7
+ * [Library API](https://www.scala-lang.org/api/2.13.7/)
+ * [Compiler API](https://www.scala-lang.org/api/2.13.7/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.13.7/scala-reflect/scala/reflect/)
+* Scala 2.13.6
+ * [Library API](https://www.scala-lang.org/api/2.13.6/)
+ * [Compiler API](https://www.scala-lang.org/api/2.13.6/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.13.6/scala-reflect/scala/reflect/)
+* Scala 2.13.5
+ * [Library API](https://www.scala-lang.org/api/2.13.5/)
+ * [Compiler API](https://www.scala-lang.org/api/2.13.5/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.13.5/scala-reflect/scala/reflect/)
+* Scala 2.13.4
+ * [Library API](https://www.scala-lang.org/api/2.13.4/)
+ * [Compiler API](https://www.scala-lang.org/api/2.13.4/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.13.4/scala-reflect/scala/reflect/)
+* Scala 2.13.3
+ * [Library API](https://www.scala-lang.org/api/2.13.3/)
+ * [Compiler API](https://www.scala-lang.org/api/2.13.3/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.13.3/scala-reflect/scala/reflect/)
* Scala 2.13.2
* [Library API](https://www.scala-lang.org/api/2.13.2/)
* [Compiler API](https://www.scala-lang.org/api/2.13.2/scala-compiler/scala/)
@@ -65,6 +180,62 @@ includeTOC: true
* [Library API](https://www.scala-lang.org/api/2.13.0/)
* [Compiler API](https://www.scala-lang.org/api/2.13.0/scala-compiler/scala/)
* [Reflection API](https://www.scala-lang.org/api/2.13.0/scala-reflect/scala/reflect/)
+* Scala 2.12.19
+ * [Library API](https://www.scala-lang.org/api/2.12.19/)
+ * [Compiler API](https://www.scala-lang.org/api/2.12.19/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.12.19/scala-reflect/scala/reflect/)
+ * Scala Modules
+ * [XML API](https://www.scala-lang.org/api/2.12.19/scala-xml/scala/xml/)
+ * [Parser Combinators API](https://www.scala-lang.org/api/2.12.19/scala-parser-combinators/scala/util/parsing/)
+ * [Swing API](https://www.scala-lang.org/api/2.12.19/scala-swing/scala/swing/)
+* Scala 2.12.18
+ * [Library API](https://www.scala-lang.org/api/2.12.18/)
+ * [Compiler API](https://www.scala-lang.org/api/2.12.18/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.12.18/scala-reflect/scala/reflect/)
+ * Scala Modules
+ * [XML API](https://www.scala-lang.org/api/2.12.18/scala-xml/scala/xml/)
+ * [Parser Combinators API](https://www.scala-lang.org/api/2.12.18/scala-parser-combinators/scala/util/parsing/)
+ * [Swing API](https://www.scala-lang.org/api/2.12.18/scala-swing/scala/swing/)
+* Scala 2.12.17
+ * [Library API](https://www.scala-lang.org/api/2.12.17/)
+ * [Compiler API](https://www.scala-lang.org/api/2.12.17/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.12.17/scala-reflect/scala/reflect/)
+ * Scala Modules
+ * [XML API](https://www.scala-lang.org/api/2.12.17/scala-xml/scala/xml/)
+ * [Parser Combinators API](https://www.scala-lang.org/api/2.12.17/scala-parser-combinators/scala/util/parsing/)
+ * [Swing API](https://www.scala-lang.org/api/2.12.17/scala-swing/scala/swing/)
+* Scala 2.12.16
+ * [Library API](https://www.scala-lang.org/api/2.12.16/)
+ * [Compiler API](https://www.scala-lang.org/api/2.12.16/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.12.16/scala-reflect/scala/reflect/)
+ * Scala Modules
+ * [XML API](https://www.scala-lang.org/api/2.12.16/scala-xml/scala/xml/)
+ * [Parser Combinators API](https://www.scala-lang.org/api/2.12.16/scala-parser-combinators/scala/util/parsing/)
+ * [Swing API](https://www.scala-lang.org/api/2.12.16/scala-swing/scala/swing/)
+* Scala 2.12.15
+ * [Library API](https://www.scala-lang.org/api/2.12.15/)
+ * [Compiler API](https://www.scala-lang.org/api/2.12.15/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.12.15/scala-reflect/scala/reflect/)
+ * Scala Modules
+ * [XML API](https://www.scala-lang.org/api/2.12.15/scala-xml/scala/xml/)
+ * [Parser Combinators API](https://www.scala-lang.org/api/2.12.15/scala-parser-combinators/scala/util/parsing/)
+ * [Swing API](https://www.scala-lang.org/api/2.12.15/scala-swing/scala/swing/)
+* Scala 2.12.14
+ * [Library API](https://www.scala-lang.org/api/2.12.14/)
+ * [Compiler API](https://www.scala-lang.org/api/2.12.14/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.12.14/scala-reflect/scala/reflect/)
+ * Scala Modules
+ * [XML API](https://www.scala-lang.org/api/2.12.14/scala-xml/scala/xml/)
+ * [Parser Combinators API](https://www.scala-lang.org/api/2.12.14/scala-parser-combinators/scala/util/parsing/)
+ * [Swing API](https://www.scala-lang.org/api/2.12.14/scala-swing/scala/swing/)
+* Scala 2.12.13
+ * [Library API](https://www.scala-lang.org/api/2.12.13/)
+ * [Compiler API](https://www.scala-lang.org/api/2.12.13/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.12.13/scala-reflect/scala/reflect/)
+* Scala 2.12.12
+ * [Library API](https://www.scala-lang.org/api/2.12.12/)
+ * [Compiler API](https://www.scala-lang.org/api/2.12.12/scala-compiler/scala/)
+ * [Reflection API](https://www.scala-lang.org/api/2.12.12/scala-reflect/scala/reflect/)
* Scala 2.12.11
* [Library API](https://www.scala-lang.org/api/2.12.11/)
* [Compiler API](https://www.scala-lang.org/api/2.12.11/scala-compiler/scala/)
@@ -149,140 +320,3 @@ includeTOC: true
* [XML API](https://www.scala-lang.org/api/2.12.1/scala-xml/#scala.xml.package)
* [Parser Combinators API](https://www.scala-lang.org/api/2.12.1/scala-parser-combinators/)
* [Swing API](https://www.scala-lang.org/api/2.12.1/scala-swing/#scala.swing.package)
-* Scala 2.11.11
- * [Library API](https://www.scala-lang.org/api/2.11.11/)
- * [Compiler API](https://www.scala-lang.org/api/2.11.11/scala-compiler/)
- * [Reflection API](https://www.scala-lang.org/api/2.11.11/scala-reflect/#scala.reflect.package)
- * Scala Modules
- * [XML API](https://www.scala-lang.org/api/2.11.11/scala-xml/#scala.xml.package)
- * [Parser Combinators API](https://www.scala-lang.org/api/2.11.11/scala-parser-combinators/)
- * [Actors API](https://www.scala-lang.org/api/2.11.11/scala-actors/#scala.actors.package) (deprecated)
- * [Swing API](https://www.scala-lang.org/api/2.11.11/scala-swing/#scala.swing.package)
- * [Continuations API](https://www.scala-lang.org/files/archive/api/2.11.11/scala-continuations-library/#scala.util.continuations.package)
-* Scala 2.11.10
- * [Library API](https://www.scala-lang.org/api/2.11.10/)
- * [Compiler API](https://www.scala-lang.org/api/2.11.10/scala-compiler/)
- * [Reflection API](https://www.scala-lang.org/api/2.11.10/scala-reflect/#scala.reflect.package)
- * Scala Modules
- * [XML API](https://www.scala-lang.org/api/2.11.10/scala-xml/#scala.xml.package)
- * [Parser Combinators API](https://www.scala-lang.org/api/2.11.10/scala-parser-combinators/)
- * [Actors API](https://www.scala-lang.org/api/2.11.10/scala-actors/#scala.actors.package) (deprecated)
- * [Swing API](https://www.scala-lang.org/api/2.11.10/scala-swing/#scala.swing.package)
- * [Continuations API](https://www.scala-lang.org/files/archive/api/2.11.10/scala-continuations-library/#scala.util.continuations.package)
-* Scala 2.11.9
- * [Library API](https://www.scala-lang.org/api/2.11.9/)
- * [Compiler API](https://www.scala-lang.org/api/2.11.9/scala-compiler/)
- * [Reflection API](https://www.scala-lang.org/api/2.11.9/scala-reflect/#scala.reflect.package)
- * Scala Modules
- * [XML API](https://www.scala-lang.org/api/2.11.9/scala-xml/#scala.xml.package)
- * [Parser Combinators API](https://www.scala-lang.org/api/2.11.9/scala-parser-combinators/)
- * [Actors API](https://www.scala-lang.org/api/2.11.9/scala-actors/#scala.actors.package) (deprecated)
- * [Swing API](https://www.scala-lang.org/api/2.11.9/scala-swing/#scala.swing.package)
- * [Continuations API](https://www.scala-lang.org/files/archive/api/2.11.9/scala-continuations-library/#scala.util.continuations.package)
-* Scala 2.11.8
- * [Library API](https://www.scala-lang.org/api/2.11.8/)
- * [Compiler API](https://www.scala-lang.org/api/2.11.8/scala-compiler/)
- * [Reflection API](https://www.scala-lang.org/api/2.11.8/scala-reflect/#scala.reflect.package)
- * Scala Modules
- * [XML API](https://www.scala-lang.org/api/2.11.8/scala-xml/#scala.xml.package)
- * [Parser Combinators API](https://www.scala-lang.org/api/2.11.8/scala-parser-combinators/)
- * [Actors API](https://www.scala-lang.org/api/2.11.8/scala-actors/#scala.actors.package) (deprecated)
- * [Swing API](https://www.scala-lang.org/api/2.11.8/scala-swing/#scala.swing.package)
- * [Continuations API](https://www.scala-lang.org/files/archive/api/2.11.8/scala-continuations-library/#scala.util.continuations.package)
-* Scala 2.11.7
- * [Library API](https://www.scala-lang.org/api/2.11.7/)
- * [Compiler API](https://www.scala-lang.org/api/2.11.7/scala-compiler/)
- * [Reflection API](https://www.scala-lang.org/api/2.11.7/scala-reflect/#scala.reflect.package)
- * Scala Modules
- * [XML API](https://www.scala-lang.org/api/2.11.7/scala-xml/#scala.xml.package)
- * [Parser Combinators API](https://www.scala-lang.org/api/2.11.7/scala-parser-combinators/)
- * [Actors API](https://www.scala-lang.org/api/2.11.7/scala-actors/#scala.actors.package) (deprecated)
- * [Swing API](https://www.scala-lang.org/api/2.11.7/scala-swing/#scala.swing.package)
- * [Continuations API](https://www.scala-lang.org/files/archive/api/2.11.7/scala-continuations-library/#scala.util.continuations.package)
-* Scala 2.11.6
- * [Library API](https://www.scala-lang.org/api/2.11.6/)
- * [Compiler API](https://www.scala-lang.org/api/2.11.6/scala-compiler/)
- * [Reflection API](https://www.scala-lang.org/api/2.11.6/scala-reflect/#scala.reflect.package)
- * Scala Modules
- * [XML API](https://www.scala-lang.org/api/2.11.6/scala-xml/#scala.xml.package)
- * [Parser Combinators API](https://www.scala-lang.org/api/2.11.6/scala-parser-combinators/)
- * [Actors API](https://www.scala-lang.org/api/2.11.6/scala-actors/#scala.actors.package) (deprecated)
- * [Swing API](https://www.scala-lang.org/api/2.11.6/scala-swing/#scala.swing.package)
- * [Continuations API](https://www.scala-lang.org/files/archive/api/2.11.6/scala-continuations-library/#scala.util.continuations.package)
-* Scala 2.11.5
- * [Library API](https://www.scala-lang.org/api/2.11.5/)
- * [Compiler API](https://www.scala-lang.org/api/2.11.5/scala-compiler/)
- * [Reflection API](https://www.scala-lang.org/api/2.11.5/scala-reflect/#scala.reflect.package)
- * Scala Modules
- * [XML API](https://www.scala-lang.org/api/2.11.5/scala-xml/#scala.xml.package)
- * [Parser Combinators API](https://www.scala-lang.org/api/2.11.5/scala-parser-combinators/)
- * [Actors API](https://www.scala-lang.org/api/2.11.5/scala-actors/#scala.actors.package) (deprecated)
- * [Swing API](https://www.scala-lang.org/api/2.11.5/scala-swing/#scala.swing.package)
- * [Continuations API](https://www.scala-lang.org/files/archive/api/2.11.5/scala-continuations-library/#scala.util.continuations.package)
-* Scala 2.11.4
- * [Library API](https://www.scala-lang.org/api/2.11.4/)
- * [Compiler API](https://www.scala-lang.org/api/2.11.4/scala-compiler/)
- * [Reflection API](https://www.scala-lang.org/api/2.11.4/scala-reflect/#scala.reflect.package)
- * Scala Modules
- * [XML API](https://www.scala-lang.org/api/2.11.4/scala-xml/#scala.xml.package)
- * [Parser Combinators API](https://www.scala-lang.org/api/2.11.4/scala-parser-combinators/)
- * [Actors API](https://www.scala-lang.org/api/2.11.4/scala-actors/#scala.actors.package) (deprecated)
- * [Swing API](https://www.scala-lang.org/api/2.11.4/scala-swing/#scala.swing.package)
- * [Continuations API](https://www.scala-lang.org/files/archive/api/2.11.4/scala-continuations-library/#scala.util.continuations.package)
-* Scala 2.11.2
- * [Library API](https://www.scala-lang.org/api/2.11.2/)
- * [Compiler API](https://www.scala-lang.org/api/2.11.2/scala-compiler/)
- * [Reflection API](https://www.scala-lang.org/api/2.11.2/scala-reflect/#scala.reflect.package)
- * Scala Modules
- * [XML API](https://www.scala-lang.org/api/2.11.2/scala-xml/#scala.xml.package)
- * [Parser Combinators API](https://www.scala-lang.org/api/2.11.2/scala-parser-combinators/)
- * [Actors API](https://www.scala-lang.org/api/2.11.2/scala-actors/#scala.actors.package) (deprecated)
- * [Swing API](https://www.scala-lang.org/api/2.11.2/scala-swing/#scala.swing.package)
- * [Continuations API](https://www.scala-lang.org/files/archive/api/2.11.2/scala-continuations-library/#scala.util.continuations.package)
-* Scala 2.11.1
- * [Library API](https://www.scala-lang.org/api/2.11.1/)
- * [Compiler API](https://www.scala-lang.org/api/2.11.1/scala-compiler/)
- * [Reflection API](https://www.scala-lang.org/api/2.11.1/scala-reflect/#scala.reflect.package)
- * Scala Modules
- * [XML API](https://www.scala-lang.org/api/2.11.1/scala-xml/#scala.xml.package)
- * [Parser Combinators API](https://www.scala-lang.org/api/2.11.1/scala-parser-combinators/)
- * [Actors API](https://www.scala-lang.org/api/2.11.1/scala-actors/#scala.actors.package) (deprecated)
- * [Swing API](https://www.scala-lang.org/api/2.11.1/scala-swing/#scala.swing.package)
- * [Continuations API](https://www.scala-lang.org/files/archive/api/2.11.1/scala-continuations-library/#scala.util.continuations.package)
-* Scala 2.11.0
- * [Library API](https://www.scala-lang.org/api/2.11.0/)
- * [Compiler API](https://www.scala-lang.org/api/2.11.0/scala-compiler/)
- * [Reflection API](https://www.scala-lang.org/api/2.11.0/scala-reflect/#scala.reflect.package)
- * Scala Modules
- * [XML API](https://www.scala-lang.org/api/2.11.0/scala-xml/#scala.xml.package)
- * [Parser Combinators API](https://www.scala-lang.org/api/2.11.0/scala-parser-combinators/)
- * [Actors API](https://www.scala-lang.org/api/2.11.0/scala-actors/#scala.actors.package) (deprecated)
- * [Swing API](https://www.scala-lang.org/api/2.11.0/scala-swing/#scala.swing.package)
- * [Continuations API](https://www.scala-lang.org/files/archive/api/2.11.0/scala-continuations-library/#scala.util.continuations.package)
-* [Scala 2.10.6](https://www.scala-lang.org/api/2.10.6/)
-* [Scala 2.10.5](https://www.scala-lang.org/api/2.10.5/)
-* [Scala 2.10.4](https://www.scala-lang.org/api/2.10.4/)
-* [Scala 2.10.3](https://www.scala-lang.org/api/2.10.3/)
-* [Scala 2.10.2](https://www.scala-lang.org/api/2.10.2/)
-* [Scala 2.10.1](https://www.scala-lang.org/api/2.10.1/)
-* [Scala 2.9.3](https://www.scala-lang.org/api/2.9.3/)
-* [Scala 2.9.2](https://www.scala-lang.org/api/2.9.2/)
-* [Scala 2.9.1-1](https://www.scala-lang.org/api/2.9.1-1/)
-* [Scala 2.9.1.final](https://www.scala-lang.org/api/2.9.1/)
-* [Scala 2.9.0.1](https://www.scala-lang.org/api/2.9.0.1/)
-* [Scala 2.9.0.final](https://www.scala-lang.org/api/2.9.0/)
-* [Scala 2.8.2.final](https://www.scala-lang.org/api/2.8.2/)
-* [Scala 2.8.1.final](https://www.scala-lang.org/api/2.8.1/)
-* [Scala 2.8.0.final](https://www.scala-lang.org/api/2.8.0/)
-* [Scala 2.7.7.final](https://www.scala-lang.org/api/2.7.7/)
-* [Scala 2.7.6.final](https://www.scala-lang.org/api/2.7.6/)
-* [Scala 2.7.5.final](https://www.scala-lang.org/api/2.7.5/)
-* [Scala 2.7.4.final](https://www.scala-lang.org/api/2.7.4/)
-* [Scala 2.7.3.final](https://www.scala-lang.org/api/2.7.3/)
-* [Scala 2.7.2.final](https://www.scala-lang.org/api/2.7.2/)
-* [Scala 2.7.1.final](https://www.scala-lang.org/api/2.7.1/)
-* [Scala 2.7.0.final](https://www.scala-lang.org/api/2.7.0/)
-* [Scala 2.6.1.final](https://www.scala-lang.org/api/2.6.1/)
-* [Scala 2.6.0.final](https://www.scala-lang.org/api/2.6.0/)
-* [Scala 2.5.1.final](https://www.scala-lang.org/api/2.5.1/)
-* [Scala 2.5.0.final](https://www.scala-lang.org/api/2.5.0/)
diff --git a/books.md b/books.md
index 0bdfff3358..3e33b863d5 100644
--- a/books.md
+++ b/books.md
@@ -1,12 +1,12 @@
---
title: Books
-layout: inner-page
+layout: basic-index
redirect_from:
- /documentation/books.html
---
-More and more books being published about Scala every year. Here, you can find
-just a small selection of the many available titles.
+More books about Scala are published every year. This is
+only a selection of the available titles.
diff --git a/contribute.md b/contribute.md
index 7957f89055..3ac938c17b 100644
--- a/contribute.md
+++ b/contribute.md
@@ -1,9 +1,9 @@
---
-layout: contribute
-title: Contribute
+layout: singlepage-overview
+title: Why Contribute to docs.scala-lang.org?
---
-###### Heather Miller
+###### A note from Heather Miller
## A Place to Build Documentation Together
@@ -21,126 +21,6 @@ If we want Scala to be accessible to more programmers, clear, easy-to-find docum
If you're interested in contributing to the Scala project in general, I argue that one of the most meaningful ways that you can, is to help us improve this transfer of information- let's make it easier and faster for people to _get_ core concepts, and to answer their own questions so they can progress to _Scala-proficient_ quickly. Each line that you contribute has the potential to affect the entire Scala community as a whole-- current, and future.
-## About docs.scala-lang.org
+## How Can I Contribute?
-### Content
-
-Currently, the _types_ of documentation supported in this repository are:
-
-- **Guides/Overviews**: Definitive guides/overviews of specific language features. Often long, detailed documents, often produced by members of the Scala team. An example is the excellent [Collections]({{ site.baseurl }}/overviews/collections-2.13/introduction.html) overview.
-- **Tutorials**: Bite-size, example-rich, and concise articles meant to get a developer up to speed quickly.
-- **Cheatsheets**: Quick reference of Scala syntax and behaviors.
-
-### Implementation
-
-This documentation repository is open-source, it lives in [github repository](https://github.com/scala/docs.scala-lang), and is always contribution-ready.
-
-It's statically generated from [Markdown](https://en.wikipedia.org/wiki/Markdown) source using [Jekyll](https://github.com/mojombo/jekyll), and hosted on [GitHub Pages](https://pages.github.com/). This workflow was chosen so as to make it as easy as possible for core committers and the community alike to produce HTML documentation, and as easy as possible to publish it in a central location.
-
-The markdown syntax being used supports [Maruku](https://github.com/bhollis/maruku) extensions, and has automatic syntax highlighting, without the need for any tags.
-
-Additionally [tut](https://github.com/tpolecat/tut) is used during pull requests to validate Scala code blocks. To use this feature you must use the backtick notation as documented by tut. Note that only validation is done. The output files from tut are not used in the building of the tutorial. Either use `tut` or `tut:fail` for your code blocks.
-
-## Submitting Docs
-
-For one to contribute a document, one must simply
-[fork](https://help.github.com/articles/fork-a-repo/) the
-[repo](https://github.com/scala/docs.scala-lang), write their article in
-[Markdown](https://daringfireball.net/projects/markdown/syntax) (example below), and submit a pull request. That's it. Likely after some edits and discussion, your document will be made live on [docs.scala-lang.org](https://docs.scala-lang.org).
-
- ---
- layout: overview
- title: My Awesome Title
- ---
-
- ## An h2 Header in Markdown
-
- And a paragraph, with a [link](https://www.scala-lang.org).
-
- One can contribute code by indenting it 4 spaces, or in-line by putting backticks around it like so, `def foo`
-
-Everything else is automatically generated for you; tables of contents, and most index pages. And of course, the styling is already taken care of for you.
-
-### Criteria for Docs to be Accepted
-
-The goal of this documentation repository is to be tighter and more organized than other community-driven documentation platforms, like wikis. As such, any document pulled in for inclusion on [https://docs.scala-lang.org](https://docs.scala-lang.org) must:
-
-- **"fit in"** to the repository ( _i.e.,_ it should not be a complete duplicate of another article),
-- **be polished** it must be thorough, complete, correct, organized, and "article-like" (personal programming notes don't quite fit.)
-- **be maintained** if the document might require revisions from time to time, it should come with an owner
-
-If you have something you're thinking about contributing, or that you're thinking about writing in order to contribute-- we'd love to consider it! Please don't hesitate to use GitHub issues and pull requests and the [scala/contributors room](https://gitter.im/scala/contributors) on Gitter for any questions, concerns, clarifications, etc.
-
-## Document Templates
-
-
-
Note: These templates will soon change slightly as a result of necessary refactoring.
-
-
-### Guides/Overviews
-
-A guide or an overview that can be logically placed on **one** page must be placed in the directory `overviews/RELEVANT-CATEGORY/_posts` with the file name in the format `YYYY-MM-dd-title-separated-by-dashes.md`, and header:
-
- ---
- layout: overview
- title: YOUR TITLE
- ---
-
-The rest of the document should, of course, be written in [Markdown](https://en.wikipedia.org/wiki/Markdown).
-
-At the moment, `RELEVANT-CATEGORY` corresponds to only a single category, "core," because we are currently focusing on building up documentation of core libraries. However, expect more categories here in the future.
-
-If your document consists of **multiple** pages, like the [Collections]({{ site.baseurl }}/overviews/collections-2.13/introduction.html) overview, an ordering must be specified, by numbering documents in their logical order with `num`, and a name must be assigned to the collection of pages using `partof`. For example, the following header might be used for a document in the collections overview:
-
- ---
- layout: overview
- title: YOUR TITLE
-
- partof: collections
- num: 10
- ---
-
-A **single** document in the collection must contain a tag in the header, `outof`, that indicates the total number of documents in the large overview. Putting it on the last page in the overview is often best:
-
- ---
- layout: overview
- title: YOUR TITLE
-
- partof: collections
- num: 15
- outof: 15
- ---
-
-Index pages, such as [https://docs.scala-lang.org/overviews/index.html](https://docs.scala-lang.org/overviews/index.html) are automatically generated, assuming documents are properly placed under the correct `RELEVANT-CATEGORY`. So, simply drop your document into the correct folder, and you're done.
-
-### Tutorials
-
-At the moment, a tutorial that can be logically placed on **one** page must be placed in the directory `tutorials/` with the file name in the format `title-separated-by-dashes.md`. For the moment, single-page tutorials use the same layout as single-page overviews:
-
- ---
- layout: overview
- title: YOUR TITLE
- ---
-
-If you have a **multiple-page** tutorial, like in the case of multiple-page overviews, you must both specify an ordering for your document, and a name must be assigned to the collection of tutorial pages. For example, the following header is used for the [Tour of Scala]({{ site.baseurl }}/tour/tour-of-scala.html) series of tutorial articles:
-
- ---
- layout: inner-page-no-masthead
- title: YOUR TITLE
-
- tutorial: scala-tour
- num: 4
- ---
-
-At the moment, only indexes for multiple-page tutorials are automatically generated.
-
-### Cheatsheets
-
-For now, cheatsheets are assumed to be in the form of tables. To contribute a cheatsheet, one must simply produce their cheatsheet as a Markdown table, with the following header:
-
- ---
- layout: cheatsheet
- title: YOUR TITLE
- by: YOUR NAME
- about: SOME TEXT ABOUT THE CHEAT SHEET.
- ---
+Please read: [Add New Guides/Tutorials](https://docs.scala-lang.org/contribute/add-guides.html)
diff --git a/docker-compose.yml b/docker-compose.yml
index 26f6d5b398..75b1876399 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,9 +1,9 @@
-version: '2'
-
services:
jekyll:
- image: bretfisher/jekyll-serve
- volumes:
- - .:/site
+ user: "${UID}:${GID}"
+ build: .
+ command: sh -c "chown $UID / && bundle exec jekyll serve --incremental --host=0.0.0.0 "
ports:
- - '8080:4000'
+ - '4000:4000'
+ volumes:
+ - .:/srv/jekyll
diff --git a/docker-compose_build-only.yml b/docker-compose_build-only.yml
new file mode 100644
index 0000000000..615d0425a7
--- /dev/null
+++ b/docker-compose_build-only.yml
@@ -0,0 +1,9 @@
+version: '2'
+
+services:
+ jekyll:
+ user: "${UID}:${GID}"
+ build: .
+ command: sh -c "chown $UID / && bundle exec jekyll build"
+ volumes:
+ - .:/srv/jekyll
diff --git a/guides.md b/guides.md
deleted file mode 100644
index 98700b64b3..0000000000
--- a/guides.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-layout: inner-page-no-masthead
-title: Guides and Overviews
-languages: [ja, zh-cn, es, ru]
-
----
diff --git a/index.md b/index.md
index 570a7959e5..22cbc790cc 100644
--- a/index.md
+++ b/index.md
@@ -1,41 +1,55 @@
---
-layout: inner-page-documentation
-title: Documentation
-languages: [ja, zh-cn, ru]
+layout: landing-page
+languages: [ja, zh-cn, ru, uk]
+
+title: Learn Scala
namespace: root
-partof: documentation
discourse: true
-# Content masthead links
+partof: documentation
more-resources-label: More Resources
-sections:
+redirect_from:
+ - /scala3/
+ - /scala3/index.html
+sections:
- title: "First Steps..."
links:
- title: "Getting Started"
description: "Install Scala on your computer and start writing some Scala code!"
icon: "fa fa-rocket"
- link: /getting-started.html
+ link: /getting-started/install-scala.html
- title: "Tour of Scala"
description: "Bite-sized introductions to core language features."
icon: "fa fa-flag"
link: /tour/tour-of-scala.html
- - title: "Scala Book"
- description: "An online book introducing the main language features."
- icon: "fa fa-book"
- link: /overviews/scala-book/introduction.html
- more-resources:
- - title: Online Courses, Exercises, & Blogs
- url: /learn.html
+ - title: "Scala 3 Book"
+ description: "Learn Scala by reading a series of short lessons."
+ icon: "fa fa-book-open"
+ link: /scala3/book/introduction.html
+ - title: "Scala Toolkit"
+ description: "Sending HTTP requests, writing files, running processes, parsing JSON..."
+ icon: "fa fa-toolbox"
+ link: /toolkit/introduction.html
+ - title: Online Courses
+ description: "MOOCs to learn Scala, for beginners and experienced programmers."
+ icon: "fa fa-cloud"
+ link: /online-courses.html
- title: Books
- url: /books.html
+ description: "Printed and digital books about Scala."
+ icon: "fa fa-book"
+ link: /books.html
+ - title: Tutorials
+ description: "Take you by the hand through a series of steps to create Scala applications."
+ icon: "fa fa-tasks"
+ link: /tutorials.html
- title: "Returning Users"
links:
- title: "API"
description: "API documentation for every version of Scala."
- icon: "fa fa-file-text"
+ icon: "fa fa-file-alt"
link: /api/all.html
- - title: "Overviews"
+ - title: "Guides & Overviews"
description: "In-depth documentation covering many of Scala's features."
icon: "fa fa-database"
link: /overviews/index.html
@@ -47,24 +61,50 @@ sections:
description: "A handy cheatsheet covering the basics of Scala's syntax."
icon: "fa fa-list"
link: /cheatsheets/index.html
- - title: "Scala FAQs"
- description: "A list of frequently-asked questions about Scala language features and their answers."
+ - title: "Scala FAQ"
+ description: "Answers to frequently-asked questions about Scala."
icon: "fa fa-question-circle"
link: /tutorials/FAQ/index.html
- - title: "Language Spec"
- description: "Scala's formal language specification."
+ - title: "Language Spec v2.x"
+ description: "Scala 2's formal language specification."
icon: "fa fa-book"
link: https://scala-lang.org/files/archive/spec/2.13/
+ - title: "Language Spec v3.x"
+ description: "Scala 3's formal language specification."
+ icon: "fa fa-book"
+ link: https://scala-lang.org/files/archive/spec/3.4/
+ - title: "Scala 3 Language Reference"
+ description: "The Scala 3 language reference."
+ icon: "fa fa-book"
+ link: https://docs.scala-lang.org/scala3/reference
+
+ - title: "Explore Scala 3"
+ links:
+ - title: "Migration Guide"
+ description: "A guide to help you move from Scala 2 to Scala 3."
+ icon: "fa fa-suitcase"
+ link: /scala3/guides/migration/compatibility-intro.html
+ - title: "New in Scala 3"
+ description: "An overview of the exciting new features in Scala 3."
+ icon: "fa fa-star"
+ link: /scala3/new-in-scala3.html
+ - title: "All new Scaladoc for Scala 3"
+ description: "Highlights of new features for Scaladoc"
+ icon: "fa fa-star"
+ link: /scala3/scaladoc.html
+ - title: "Talks"
+ description: "Talks about Scala 3 that can be watched online"
+ icon: "fa fa-play-circle"
+ link: /scala3/talks.html
- title: "Scala Evolution"
links:
- - title: "SIPs"
- description: "The Scala Improvement Process. Language & compiler evolution."
+ - title: "Scala Improvement Process"
+ description: "Description of the process for evolving the language, and list of all the Scala Improvement Proposals (SIPs)."
icon: "fa fa-cogs"
link: /sips/index.html
- - title: "SPP"
- description: "The Scala Platform Process. Community-driven library evolution."
- icon: "fa fa-users"
- link: https://platform.scala-lang.org
-
+ - title: "Become a Scala OSS Contributor"
+ description: "From start to finish: discover how you can help Scala's open-source ecosystem"
+ icon: "fa fa-code-branch"
+ link: /contribute/
---
diff --git a/learn.md b/learn.md
deleted file mode 100644
index 5da03071bd..0000000000
--- a/learn.md
+++ /dev/null
@@ -1,51 +0,0 @@
----
-title: Online Resources
-layout: inner-page-no-masthead
-redirect_from:
- - /documentation/books.html
----
-
-## Quick Online Exercises
-[Scala Exercises](https://www.scala-exercises.org/) is a series of lessons and exercises created by [47 Degrees](https://www.47deg.com/). It's a great way to get a brief introduction to Scala while testing your knowledge along the way.
-
-## Online Courses from EPFL
-
-The following courses are available for free. They teach you the main features of the Scala language and introduce you
-to functional programming. They are published either on [Coursera](https://www.coursera.org) or [edX](https://www.edx.org).
-
- * [Functional Programming in Scala Specialization](https://www.coursera.org/specializations/scala).
- The Specialization provides a hands-on introduction to functional programming using Scala. You can access the courses
- material and exercises by either signing up for the specialization or auditing the courses individually. The
- specialization has the following courses.
- * [Functional Programming Principles in Scala](https://www.coursera.org/learn/progfun1),
- * [Functional Program Design in Scala](https://www.coursera.org/learn/progfun2),
- * [Parallel programming](https://www.coursera.org/learn/parprog1),
- * [Big Data Analysis with Scala and Spark](https://www.coursera.org/learn/scala-spark-big-data),
- * [Functional Programming in Scala Capstone](https://www.coursera.org/learn/scala-capstone),
- * [Programming Reactive Systems](https://www.edx.org/course/programming-reactive-systems).
-
-Note : On Coursera and edX, there is a paid version available. The only difference with the free version is that
-the paid version delivers a certificate of completion. Learn more about
-[Coursera certificates](https://learner.coursera.help/hc/en-us/articles/209819053-Get-a-Course-Certificate) or
-[edX certificates](https://support.edx.org/hc/en-us/categories/115002269627-Certificates).
-
-## Dr.Mark C Lewis's Lectures from Trinity University
-
- * [Dr.Mark C Lewis](https://www.cs.trinity.edu/~mlewis/) from Trinity University, San Antonio, TX, teaches programming courses using the Scala language. Course videos are available in YouTube for free. Some of the courses below.
- * [Introduction to Programming and Problem Solving Using Scala](https://www.youtube.com/playlist?list=PLLMXbkbDbVt9MIJ9DV4ps-_trOzWtphYO)
- * [Object-Orientation, Abstraction, and Data Structures Using Scala](https://www.youtube.com/playlist?list=PLLMXbkbDbVt8JLumqKj-3BlHmEXPIfR42)
-
- You can visit his [YouTube channel](https://www.youtube.com/user/DrMarkCLewis/featured) for more videos.
-
-
-## Try Scala In Your Browser!
-There are a handful of websites where you can interactively run Scala code in your browser! Have a look at [ScalaFiddle](https://scalafiddle.io/) and [Scastie](https://scastie.org/).
-
-## allaboutscala
-[allaboutscala](https://allaboutscala.com/) provides detailed tutorials for beginners.
-
-## ScalaCourses
-[Independent Courseware](https://getscala.com), online self-study or instructor-led Scala and Play courses for a fee.
-
-## Visual Scala Reference
-[Visual Scala Reference](https://superruzafa.github.com/visual-scala-reference/), a guide to visually learn about Scala concepts and functions.
diff --git a/news/_posts/2012-12-12-functional-programming-principles-in-scala-impressions-and-statistics.md b/news/_posts/2012-12-12-functional-programming-principles-in-scala-impressions-and-statistics.md
index 38a941ac28..c4722a5bb3 100644
--- a/news/_posts/2012-12-12-functional-programming-principles-in-scala-impressions-and-statistics.md
+++ b/news/_posts/2012-12-12-functional-programming-principles-in-scala-impressions-and-statistics.md
@@ -1,5 +1,5 @@
---
-layout: inner-page-no-masthead
+layout: singlepage-overview
title: "Functional Programming Principles in Scala: Impressions and Statistics"
---
###### By Heather Miller and Martin Odersky
@@ -33,7 +33,7 @@ Those of you reading this who were enrolled in the course might recall that, sev
For example, as mentioned above, a success rate of 20% is quite high for an online course. One might suspect that it was because the course was very easy, but in our previous experience that's not the case. In fact, the online course is a direct adaptation of a 2nd year course that was given at EPFL for a number of years and that has a reputation of being rather tough. If anything, the material in the online course was a bit more compressed than in the previous on-campus class.
-In particular, 57% of all respondents to the survey rated the overall course as being 3, "Just Right", on a scale from 1 to 5, with 1 being "Too Easy" and 5 being "Too Difficult. With regard to programming assignments specifically, 40% rated the assignments as being 3, "Just Right", while 46% rated assignments as being 4 "Challenging".
+In particular, 57% of all respondents to the survey rated the overall course as being 3, "Just Right", on a scale from 1 to 5, with 1 being "Too Easy" and 5 being "Too Difficult". With regard to programming assignments specifically, 40% rated the assignments as being 3, "Just Right", while 46% rated assignments as being 4 "Challenging".
Another point which might be particularly interesting is the fact that the difficulty rating appears to be independent of whether people have a background in Computer Science/Software Engineering or not. One might guess that this could mean that learning Scala is not much more difficult without a formal educational background in Computer Science.
@@ -43,7 +43,7 @@ While a majority of the students in the course have degrees in Computer Science/
Participants' Fields of Study
-However, we were still interested to see how the formal education of participants influenced their assessment of the perceived difficulty. It turns out that, of those who have or have pursued university degrees— Bachelors or Masters degrees, there was almost no difference in perceived difficulty. The only marked differences appeared to the far left and the far right of the spectrum.
+However, we were still interested to see how the formal education of participants influenced their assessment of the perceived difficulty. It turns out that, of those who have or have pursued university degrees— Bachelors or Master's degrees, there was almost no difference in perceived difficulty. The only marked differences appeared to the far left and the far right of the spectrum.
Perceived Difficulty Relative to Level of Education
Scale: 1 - Too Easy, 2 - Easy, 3 - Just Right, 4 - Challenging, 5 - Too Difficult
@@ -79,7 +79,7 @@ We also collected numbers about the used programming tools. First, we were inter
Which editor do you normally use, and which editor did you use for the course?