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)
  • New sessions starting every 2 weeks!

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

Scala Native 0.4.0 is here!

Tuesday, January 19, 2021

If you ever thought about running your Scala code in an environment other than JVM, you’ve probably already met Scala Native—a project with a promise of instant startup, low memory usage, interop with C libraries, and competitive performance thanks to the Interflow optimizer.

The long-awaited release 0.4.0 is here, bringing support for Scala 2.12 and 2.13!

Today we are going to discuss the most exciting new features and major changes coming in this release. We will start with changes made to the Scala Native compiler plugin, especially supported Scala versions and cross-platform testing. Next we will talk about changes to C interoperability and to the sbt plugin that need to be taken into account when upgrading to this release. Last but not least, we will discuss why we needed to break binary compatibility with previous versions.

Support for latest Scala 2 versions

Until now Scala Native supported only Scala 2.11, which is now perceived by most of the developers as deprecated. We can proudly announce that Scala Native is now compatible with Scala versions 2.12.13 and 2.13.4, in addition to the 2.11.12 with known bugs fixed.

Reflective instantiation

The SN plugin removes unused definitions of classes, methods, and variables during the linking stage to reduce the size of the output binary. This used to make using reflective calls very difficult. Fortunately, this is a thing of the past—with release 0.4.0 we introduce a subset of reflective operations allowed to be used.

It would not be wise to enable reflective calls to all definitions as we would need to load many more objects and increase the size of the binary. That’s why you need to signal to the compiler which classes can use this mechanism - it can be done by marking your trait, class, or object with the @EnableReflectiveInstantiation annotation. It will also make all of its descendants able to be reflectively instantiated.

Annotated classes and modules, having a concrete implementation, can be accessed via the provided scalanative.reflect.Reflect API. If you have used Scala.js before, it may seem similar to you, as the new implementation uses exactly the same API.

Cross-platform testing using JUnit

Until recently, all our internal tests were executed using our own native testing framework, mainly due to lack of proper reflection support in Scala Native. After getting rid of this blocker, we have decided to use JUnit instead and as a result implemented the native plugin for this framework. Thanks to this change you are also able to also use it in your own projects.
Naturally you are still able to use any other testing framework supporting Scala Native. As an example Scala Native will soon be supported in uTest and scalatest.

To enable Native JUnit tests, add the two following lines to your build.sbt.

addCompilerPlugin("org.scala-native" % "junit-plugin" % nativeVersion cross CrossVersion.full)
libraryDependencies += "org.scala-native" %%% "junit-runtime" % nativeVersion % Test

The above settings, when running sbt test, would result in the tests being compiled using the SN plugin and executed with a native implementation of the JUnit framework. Additionally you can easily run your tests both on JVM and Native with a simple adjustment to your build. You can find a guide how to do this in Scala Native reference

Interop changes

Including Native Code in your Application or Library

Previously, Scala Native used C source files in its build pipeline allowing you to mix the Scala code with native libraries, it was a great way to use existing native libraries and distribute them with the plugin. However, this feature was only reserved for the SN plugin internals.

With the 0.4.0 release you’re able to put your C/C++ sources in the resources/scala-native directory inside your project, and they will be linked and compiled inside the SN pipeline.

As an example you can use it to access macro-defined constants and functions or to pass structs from the stack to C functions.

// src/resources/scala-native/example.c
typedef int (*Callback0) (void);

const int EXAMPLE_CONSTANT = 42;

int exec(Callback0 f) {
 return f();
};

// src/main/example.scala
@extern
object example {
 def exec(cb: CFuncPtr0[CInt]): ExecResult = extern

 @name("EXAMPLE_CONSTANT")
 final val someConstant: Int = extern
}

Better interop for functions

Since 0.3.9 it was possible to pass Scala functions to native libraries by defining CFuncPtrN - single abstract method traits working as a wrapper for Scala functions. Native calls to such functions were done via generated externForwarder - method, boxing parameters before passing them to the function, and unboxing results. On the other hand, if you wanted to use a native function you could declare it as an extern. This design was quite good, but it did not allow working with generic functions passed to Scala Native as *void, or Ptr[Byte] in SN syntax.

To support the last scenario, this design was extended and changed. You no longer need to implement the CFuncPtrN trait which is now private for plugin implementation. Instead, you can use an implicit conversion from scala.FunctionN to CFuncPtrN.

type Callback = CFuncPtr1[CInt,Unit]
def registerCallback(cFn: Callback): Unit = extern
def fn(n: CInt): Unit = ???

registerCallback(CFuncPtr1.fromScalaFunction(fn))
registerCallback(fn)

registerCallback { (n: CInt) => println("hello native") }

It is now also possible to work with an arbitrary pointer and convert it to CFuncPtrN that can be called in your Scala code, or to convert your function to any pointer if your native library needs this.

import scala.scalanative.unsafe.Ptr
val cFnPtr: CFuncPtr0[CInt]    = ???
val fnPtr: Ptr[Byte]           = CFuncPtr.toPtr(cFnPtr)
val fnFromPtr: CFuncPtr0[CInt] = CFuncPtr.fromPtr[CFuncPtr0[CInt]](fnPtr)

New garbage collector

This release also adds a new garbage collector - Commix, a parallel mark and concurrent sweep GC, based on the well known Immix GC. It reduces GC pause times by utilizing additional processor cores during mark and sweep phases. It was added soon after the 0.4.0-M2 release, but was only available via an unofficial snapshot.

While the GC itself will use multiple threads, Scala Native still does not support multi-threading in the application code. Commix GC was written in C and uses pthread to work. In case your application needs concurrency support, you may try the experimental library scala-native-loop

Sbt plugin changes

Introducing NativeConfig

This Scala Native release also brings changes to the sbt configuration. We’ve decided to deprecate the varied set of NativeX setting keys, in favor of a single NativeConfig.

nativeConfig ~= (
 _.withMode(build.Mode.releaseFast)
  .withGC(build.GC.immix)
  .withLTO(build.LTO.full)
  .withOptimize(true)
  .withCompileOptions(Nil)
  .withLinkingOptions(Nil)
 )

Old style settings keys are still supported, but with lower priority than the new config. They will be removed at some point in the future. In the following example resulting LTO setting would be set to thin

nativeConfig := nativeConfig.value
 .withLTO(build.LTO.thin)

nativeLTO := "none"

Cross compiling

By default, Scala Native has always compiled and optimized the resulting assembly based on host architecture and its operating system. Although it worked well when you were running a program on the same machine, it caused many problems when trying to run it anywhere else. With the latest release you’re able to define a custom build target for the compiler by providing an LLVM-style TargetTriple in your config.

For example, if you’re working on Linux and would like to create an executable suitable for MacOS without changing your whole build, you can use the following sbt setting:

sbt 'set nativeConfig ~= {_.withTargetTriple("x86_64-apple-darwin<version>")}' myApp/nativeLink

We consider changing the target triple as an experimental feature for advanced users, and cannot promise it will currently work with any possible configuration yet. However, the number of supported architectures and operating systems would definitely grow in the future.

Changes to the intermediate representation

NIR (Native Intermediate Representation) is a format used to represent a subset of LLVM instructions, types and values, augmented with a number of high-level primitives that are necessary to efficiently compile Scala. You can read more about it in the Scala Native documentation.

The new release includes many necessary changes to NIR, starting with the way Strings are stored, through adding new literals like Val.ClassOf and last, but not least support for default methods. The last one was introduced to support Scala 2.12 behavior which compiles trait methods as default methods in Java interfaces.

Although we always try to keep our NIR changes to absolute minimum, the number of removed or no longer used primitives used in the previous version forced us to break backward binary compatibility. This decision allows us to remove many known bugs and will make future maintenance easier. NIR format might still change in following minor releases of Scala Native, but they are going to be fully backward-compatible within the 0.4.x series.

How about existing libraries?

Scala Native had many libraries compatible with SN 0.4.0-M2. Unfortunately, the new release is not binary compatible with them, and you’ll need to wait until authors republish them using Scala Native 0.4.0.

However, with increasing interest in running the Scala code natively, it should happen quickly after the release.

Contributing

Contributors are always welcome. You can support the Scala Native project in multiple ways. The most straightforward way of doing so is by working on the plugin itself. Take a look at our contributors’ guide.

Making our ecosystem more native-compatible is extremely important too. Scala Native compiler does not operate on JVM bytecode, but on its own intermediate representation distributed in *.nir files in resulting JAR. Library dependencies not compiled with Scala Native would fail when linking. Therefore, you can help by developing tools and libraries which do not depend on the Java standard library. For example, you can take a look at sconfig - a Scala port of the widely used Lightbend Config library.

Summary

Scala Native is starting to keep up with the rest of the Scala ecosystem. We believe it will bloom quickly thanks to this release, resulting in many libraries and tools. Supporting recent Scala versions makes it much more approachable for the users, and easier testing through JUnit support improves overall usability.

Even though resources allocated into this project were quite limited, we have managed to fulfill all our goals announced last year in Scala Native Next Steps. Currently, this project is developed by a single engineer working full-time, thanks to our cooperation with VirtusLab, and with guidance of Sébastien Doeraene, author of Scala.js. We also appreciate and would like to thank our community contributors for the huge amounts of work they have done for this project, and a special thanks to a contributor who also donated significant personal funds and propelled our efforts in 2020.

We have many plans for the future of Scala Native. Our top priorities include Scala 3 support and support for more architectures such as ARM Stay tuned for the next updates…

For more changes coming in Scala Native 0.4.0 check out changelog website

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 Goldman Sachs 47 Degrees Twitter Spotify Lunatech VirtusLab Your company