Scala runs on...

  • JVM
  • JavaScript in your browser
  • Natively with LLVM beta

Scala in a Nutshell

click the boxes below to see Scala in action!

Seamless Java Interop

Scala runs on the JVM, so Java and Scala stacks can be freely mixed for totally seamless integration.

Type Inference

So the type system doesn’t feel so static. Don’t work for the type system. Let the type system work for you!

Concurrency & Distribution

Use data-parallel operations on collections, use actors for concurrency and distribution, or futures for asynchronous programming.

Author.scala
class Author(val firstName: String,
    val lastName: String) extends Comparable[Author] {

  override def compareTo(that: Author) = {
    val lastNameComp = this.lastName compareTo that.lastName
    if (lastNameComp != 0) lastNameComp
    else this.firstName compareTo that.firstName
  }
}

object Author {
  def loadAuthorsFromFile(file: java.io.File): List[Author] = ???
}
App.java
import static scala.collection.JavaConversions.asJavaCollection;

public class App {
    public List<Author> loadAuthorsFromFile(File file) {
        return new ArrayList<Author>(asJavaCollection(
            Author.loadAuthorsFromFile(file)));
    }

    public void sortAuthors(List<Author> authors) {
        Collections.sort(authors);
    }

    public void displaySortedAuthors(File file) {
        List<Author> authors = loadAuthorsFromFile(file);
        sortAuthors(authors);
        for (Author author : authors) {
            System.out.println(
                author.lastName() + ", " + author.firstName());
        }
    }
}

Combine Scala and Java seamlessly

Scala classes are ultimately JVM classes. You can create Java objects, call their methods and inherit from Java classes transparently from Scala. Similarly, Java code can reference Scala classes and objects.


In this example, the Scala class Author implements the Java interface Comparable<T> and works with Java Files. The Java code uses a method from the companion object Author, and accesses fields of the Author class. It also uses JavaConversions to convert between Scala collections and Java collections.

Type inference
scala> class Person(val name: String, val age: Int) {
     |   override def toString = s"$name ($age)"
     | }
defined class Person

scala> def underagePeopleNames(persons: List[Person]) = {
     |   for (person <- persons; if person.age < 18)
     |     yield person.name
     | }
underagePeopleNames: (persons: List[Person])List[String]

scala> def createRandomPeople() = {
     |   val names = List("Alice", "Bob", "Carol",
     |       "Dave", "Eve", "Frank")
     |   for (name <- names) yield {
     |     val age = (Random.nextGaussian()*8 + 20).toInt
     |     new Person(name, age)
     |   }
     | }
createRandomPeople: ()List[Person]

scala> val people = createRandomPeople()
people: List[Person] = List(Alice (16), Bob (16), Carol (19), Dave (18), Eve (26), Frank (11))

scala> underagePeopleNames(people)
res1: List[String] = List(Alice, Bob, Frank)

Let the compiler figure out the types for you

The Scala compiler is smart about static types. Most of the time, you need not tell it the types of your variables. Instead, its powerful type inference will figure them out for you.

In this interactive REPL session (Read-Eval-Print-Loop), we define a class and two functions. You can observe that the compiler infers the result types of the functions automatically, as well as all the intermediate values.

Concurrent/Distributed
val x = Future { someExpensiveComputation() }
val y = Future { someOtherExpensiveComputation() }
val z = for (a <- x; b <- y) yield a*b
for (c <- z) println("Result: " + c)
println("Meanwhile, the main thread goes on!")

Go Concurrent or Distributed with Futures & Promises

In Scala, futures and promises can be used to process data asynchronously, making it easier to parallelize or even distribute your application.

In this example, the Future{} construct evaluates its argument asynchronously, and returns a handle to the asynchronous result as a Future[Int]. For-comprehensions can be used to register new callbacks (to post new things to do) when the future is completed, i.e., when the computation is finished. And since all this is executed asynchronously, without blocking, the main program thread can continue doing other work in the meantime.

Traits

Combine the flexibility of Java-style interfaces with the power of classes. Think principled multiple-inheritance.

Pattern Matching

Think “switch” on steroids. Match against class hierarchies, sequences, and more.

Higher-order functions

Functions are first-class objects. Compose them with guaranteed type safety. Use them anywhere, pass them to anything.

Traits
abstract class Spacecraft {
  def engage(): Unit
}
trait CommandoBridge extends Spacecraft {
  def engage(): Unit = {
    for (_ <- 1 to 3)
      speedUp()
  }
  def speedUp(): Unit
}
trait PulseEngine extends Spacecraft {
  val maxPulse: Int
  var currentPulse: Int = 0
  def speedUp(): Unit = {
    if (currentPulse < maxPulse)
      currentPulse += 1
  }
}
class StarCruiser extends Spacecraft
                     with CommandoBridge
                     with PulseEngine {
  val maxPulse = 200
}

Flexibly Combine Interface & Behavior

In Scala, multiple traits can be mixed into a class to combine their interface and their behavior.

Here, a StarCruiser is a Spacecraft with a CommandoBridge that knows how to engage the ship (provided a means to speed up) and a PulseEngine that specifies how to speed up.

Switch on the structure of your data

In Scala, case classes are used to represent structural data types. They implicitly equip the class with meaningful toString, equals and hashCode methods, as well as the ability to be deconstructed with pattern matching.


In this example, we define a small set of case classes that represent binary trees of integers (the generic version is omitted for simplicity here). In inOrder, the match construct chooses the right branch, depending on the type of t, and at the same time deconstructs the arguments of a Node.

Pattern matching
// Define a set of case classes for representing binary trees.
sealed abstract class Tree
case class Node(elem: Int, left: Tree, right: Tree) extends Tree
case object Leaf extends Tree

// Return the in-order traversal sequence of a given tree.
def inOrder(t: Tree): List[Int] = t match {
  case Node(e, l, r) => inOrder(l) ::: List(e) ::: inOrder(r)
  case Leaf          => List()
}

Go Functional with Higher-Order Functions

In Scala, functions are values, and can be defined as anonymous functions with a concise syntax.

Scala
val people: Array[Person]

// Partition `people` into two arrays `minors` and `adults`.
// Use the anonymous function `(_.age < 18)` as a predicate for partitioning.
val (minors, adults) = people partition (_.age < 18)
Java
List<Person> people;

List<Person> minors = new ArrayList<Person>(people.size());
List<Person> adults = new ArrayList<Person>(people.size());
for (Person person : people) {
    if (person.getAge() < 18)
        minors.add(person);
    else
        adults.add(person);
}

Run Scala in your browser

Scastie is Scala + sbt in your browser! You can use any version of Scala, or even alternate backends such as Dotty, Scala.js, Scala Native, and Typelevel Scala. You can use any published library. You can save and share Scala programs/builds with anybody.

Run Scala code interactively

Online Courses

Functional Programming Principles in Scala

  • Free (optional paid certificate)
  • New sessions starting every 2 weeks!

Functional Program Design in Scala

  • Free (optional paid certificate)
  • New sessions starting every 2 weeks!

Parallel Programming

  • Free (optional paid certificate)
  • New sessions starting every 2 weeks!

Big Data Analysis with Scala and Spark

  • Free (optional paid certificate)
  • New sessions starting every 2 weeks!

Functional Programming in Scala Capstone

  • Free (optional paid certificate)
  • New sessions starting every 2 weeks!

Programming Reactive Systems

  • Free (optional paid certificate)
  • 18 Feb 2019

Upcoming Training

Scala ecosystem

The Scala Library Index (or Scaladex) is a representation of a map of all published Scala libraries. With Scaladex, a developer can now query more than 175,000 releases of Scala libraries. Scaladex is officially supported by Scala Center.

The Scala Library Index

What’s New

BLOG

Better management of transitive dependencies and conflicts

Thursday, October 17, 2019

Early in 2019, the Scala Center advisory board accepted a proposal from Spotify, whose goal is to improve the handling of conflicts in dependency management in sbt.

The work we’ve been doing may interest you if:

  • You’ve run into trouble with version conflicts between dependencies and didn’t know what to do or where to look for advice.
  • You want more control on how version conflicts are resolved in your build.
  • You want automated assistance with deciding whether a version upgrade might break something in your project.

At the time we started this project, Ivy was still used by default to resolve libraries in sbt, but efforts were in progress to use coursier instead, so we focused on the latter as a vehicle for improvements. Since then, coursier support in sbt became official, and ships by default in sbt 1.3.0. Besides having a simpler model than the one used before in sbt or in Ivy, coursier has the advantage of being usable from the command line, and can benefit other users of the coursier API.

For the third point about static analysis, we found the missinglink tool for Maven, originating from Spotify themselves. This tool can analyze the classpath of a Maven project, and detect ahead of time (at “link” time) whether binary incompatibilities can be encountered at run-time. The only issue was that it was not usable from sbt, rendering it useless for a large subset of Scala users. We built and released an sbt plugin for missinglink to address this hole.

Version ordering and reconciliation

While most people have a simple intuition about library resolution (a newer version of a library gets picked over an older version), the details of how versions are compared and reconciled are quite complicated. We contributed a dedicated documentation page on the coursier website to help users understand how resolution works in the not-so-trivial cases. In order to improve the experience of upgrading from sbt 1.2.x and Ivy-based resolution, we tweaked resolution in coursier 2.0.0-RC3-4 with the help of Eugene Yokota to be more in line with Ivy, the former sbt behavior, and the semantic versioning specification. The documentation page should be updated accordingly soon.

On top of that, Eugene Yokota recently wrote a blog post comparing how versions are compared and reconciled in both Ivy and coursier.

Strict conflict manager

By default, both Ivy and coursier tolerate that the dependency graph contains two different versions of a library, in which case they pick a winner. Sometimes, we want more control, and do not want any conflict resolution to happen. Instead, we would like an error to be reported if there are two different versions of a library. A strict conflict manager does precisely that, and we added one to coursier. Instructions follow for enabling the strict conflict manager 1) in an sbt build, and 2) from the coursier command line.

sbt

From sbt, enable the strict conflict manager either through the original conflictManager key, like

conflictManager := ConflictManager.strict

or enable it in a possibly more fine-grained way if sbt-coursier is around with

versionReconciliation += "*" % "*" % "strict"

(Note that to use sbt-coursier from an sbt 1.3.x project, the coursier-based sbt launcher is required. Get it via its custom sbt-extras runner or generate one with coursier bootstrap sbt-launcher && ./sbt.)

The update task will then succeed only if the strict checks pass. If they don’t, either force the versions of faulty dependencies with dependencyOverrides, like

dependencyOverrides += "org.typelevel" % "cats-core_2.12" % "1.5.0"

or adjust their version reconciliation, like

versionReconciliation ++= Seq(
  "org.typelevel" %% "cats-core" % "relaxed", // "semver" reconciliation is also available
  "*" % "*" % "strict"
)

A number of version reconciliation types are available:

  • "strict" requires all dependees to depend on the exact selected version (if they depend on an interval, the selected version only needs to be contained in it)
  • "semver" requires all dependees to depend on the same major version as the selected version (if they depend on an interval, the selected version only needs to be contained in it too)
  • "default" is the default version reconciliation in coursier, enabled in the coursier CLI or with the sbt-coursier plugin. It is described in more detail in this page.
  • "relaxed" does not trigger any conflict. It is the default in the coursier support of sbt 1.3.x, which allows for better compatibility with former sbt versions. It ignores the lowest versions and version intervals, until they can be reconciled with the same algorithm as "default".

Since reconciliation strategies can be set per artifact, or per organization, it becomes much easier to declaratively tell sbt, for example, that some project adheres to SemVer, and that it is fine to resolve dependencies on that specific project according to SemVer, but not others.

CLI

From the command line, we can use the new strict conflict manager of coursier with:

$ coursier resolve --strict \
    org.typelevel:cats-effect_2.12:2.0.0 \
    org.typelevel:cats-core_2.12:1.5.0
Resolution error: Unsatisfied rule Strict(*:*): Found evicted dependencies:

org.typelevel:cats-core_2.12:2.0.0 (1.5.0 wanted)
└─ org.typelevel:cats-core_2.12:1.5.0

To ignore some strict checks, one can exclude the faulty dependency with

$ coursier resolve \
    --strict-exclude 'org.typelevel:cats-core*' \
    org.typelevel:cats-effect_2.12:2.0.0 \
    org.typelevel:cats-core_2.12:1.5.0
org.scala-lang:scala-library:2.12.9:default
org.typelevel:cats-core_2.12:2.0.0:default
org.typelevel:cats-effect_2.12:2.0.0:default
org.typelevel:cats-kernel_2.12:2.0.0:default
org.typelevel:cats-macros_2.12:2.0.0:default

(passing --strict-exclude automatically enables --strict), or only include a subset of the dependencies in the strict checks, like

$ coursier resolve \
    --strict-include 'org.scala-lang:*' \
    org.typelevel:cats-effect_2.12:2.0.0 \
    org.typelevel:cats-core_2.12:1.5.0
org.scala-lang:scala-library:2.12.9:default
org.typelevel:cats-core_2.12:2.0.0:default
org.typelevel:cats-effect_2.12:2.0.0:default
org.typelevel:cats-kernel_2.12:2.0.0:default
org.typelevel:cats-macros_2.12:2.0.0:default

Alternatively, forcing the version of the faulty dependency makes the strict checks ignore it:

$ coursier resolve \
    --strict \
    --strict-exclude 'org.scala-lang:*' \
    --force-version org.typelevel:cats-core_2.12:1.5.0 \
    org.typelevel:cats-effect_2.12:2.0.0 \
    org.typelevel:cats-core_2.12:1.5.0
org.scala-lang:scala-library:2.12.9:default
org.scala-lang:scala-reflect:2.12.6:default
org.typelevel:cats-core_2.12:1.5.0:default
org.typelevel:cats-effect_2.12:2.0.0:default
org.typelevel:cats-kernel_2.12:1.5.0:default
org.typelevel:cats-macros_2.12:1.5.0:default
org.typelevel:machinist_2.12:0.6.6:default

Static analysis checks

To leverage the power of the static analysis offered by missinglink library in sbt projects, we have developed sbt-missinglink. The readme explains how to use it, but the basics are simple.

First, add the following line in project/plugins.sbt:

addSbtPlugin("ch.epfl.scala" % "sbt-missinglink" % "0.1.0")

then simply run the following task for the project you want to test:

> theProject/missinglinkCheck

This will check that the transitive dependencies of your project do not exhibit any binary compatibility conflict, assuming that the methods of your Compile configuration (in src/main/) are all called. You can add that task to your CI script, for example.

If the checks succeed, you have a guarantee that no LinkageError can happen at run-time, unless run-time reflection is involved, making static analysis impossible.

The plugin is very simple at the moment, and will be extended to support more features of missinglink, in particular the ability to add exclusions to the checks performed. If missinglink itself proves insufficient for the needs of Scala developers, we may also contribute improvements to it in the future.

Conclusion

We have seen a few new ways you can improve the management of your transitive dependencies. In particular, we have introduced:

  • reconciliation strategies, which let you declaratively specify the compatibility guarantees of individual libraries, allowing coursier to do a better, safer job at conflict resolution, and
  • sbt-missinglink, an sbt plugin to easily check ahead of time that your resolved transitive dependencies are actually binary compatible.

Twitter Feed

See more tweets, or

Follow Scala on twitter

The Scala language is maintained by

  • Scala Center
  • Lightbend

Scala Center is supported by

EPFL IBM Verizon Goldman Sachs 47 Degrees SAP Twitter Your company