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
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 pure functional programming (FP) language
- It’s a pure 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:
def double(ints: List[Int]): List[Int] = {
val buffer = new ListBuffer[Int]()
for (i <- ints) {
buffer += i * 2
}
buffer.toList
foo
bar
}
val newNumbers = double(oldNumbers)
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 achieve the same effect:
val newNumbers = oldNumbers.map(_ * 2)
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:
val nums = List(1,2,3)
val p = Person("Martin", "Odersky")
Higher-order functions and lambdas make for concise code that’s readable:
nums.map(i => i * 2) // long form
nums.map(_ * 2) // short form
nums.filter(i => i > 1)
nums.filter(_ > 1)
And traits, classes, and methods are defined with a clean, light syntax:
trait Animal:
def speak(): Unit
trait HasTail:
def wagTail(): Unit
class Dog extends Animal, HasTail:
def speak() = println("Woof")
def wagTail() = println("⎞⎜⎛ ⎞⎜⎛")
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:
val s = "Hello"
val p = Person("Al", "Pacino")
val sum = ints.reduceLeft(_ + _)
val y = for i <- nums yield i * 2
val z = nums.filter(_ > 100)
.filter(_ < 10_000)
.map(_ * 2)
Because Scala is considered to be a strong, statically-typed language, you get all the benefits of static types:
- Correctness: you catch most errors at compile-time
- Great IDE support
- Code completion
- Catching errors at compile-time means catching mistakes as you type
- Easy and reliable refactoring
- Reliable code completion
- You can refactor your code with confidence
- Method type declarations tell readers what the method does, and help serve as documentation
- Types make your code easier to maintain
- Scalability: types help ensure correctness across arbitrarily large applications and development teams
- Strong types enable Scala features like implicits (TODO: I need help on this wording and description)
Expressive type system
Scala’s expressive type system enforces, at compile-time, that abstractions are used in a safe and coherent manner. In particular, the type system supports:
- Type inference
- Generic classes
- Variance annotations
- Upper and lower type bounds
- Polymorphic methods
- Intersection types
- Union types
- Type lambdas
given
instances andusing
clauses- Extension methods
- Type classes
- Multiversal equality
- Opaque type aliases
- Open classes
- Match types
- Dependent function types
- Polymorphic function types
- Context bounds
- Context functions
- Inner classes and abstract type members 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 pure FP language
Scala is a functional programming (FP) language, meaning:
- Functions are variables, and can be passed around like any other variable
- 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 collections classes in the standard library
- Those collections classes come with dozens of functional methods: they don’t mutate the collection, but instead return an updated copy of the data
A pure OOP language
Scala is a pure object-oriented programming (OOP) language. Every variable is an object, 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.
Supports FP/OOP fusion
The essence of Scala is the fusion of functional programming and object-oriented programming in a typed settings:
- Functions for the logic
- Objects for the modularity
As Martin Odersky has stated, “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, an implicit parameter directly leads to an inferred argument term that could also be written down explicitly.
Use cases for this concept include implementing type classes, 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.
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 and the Play Framework 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
:
import java.io._
val br = BufferedReader(FileReader(filename))
// read the file with `br` ...
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:
import scala.jdk.CollectionConverters._
val scalaList: Seq[Integer] = JavaClass.getJavaList().asScala.toSeq
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:
- The Play Framework is a lightweight, stateless, developer-friendly, web-friendly architecture for creating highly-scalable applications
- Lagom is a microservices framework that helps you decompose your legacy monolith and build, test, and deploy entire systems of reactive microservices
- Apache Spark 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 shows dozens of additional open source tools that developers have created to build Scala applications.
In addition to server-side programming, Scala.js 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.
Lower-level language features
Where the previous section covered high-level features of Scala 3, 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 likegiven
,using
, andextension
, focusing on intent over mechanism (see the Givens section for details) - Extension methods 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 rules out nonsensical comparisons with
==
and!=
(i.e., attempting to compare aPerson
to aPlanet
) - 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 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
@alpha
method annotation defines an alternate name for the method, improving Java interoperability, and letting you provide aliases for symbolic operators
- Multiple different uses of the
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.
Scala ecosystem
Scala has a vibrant ecosystem, with libraries and frameworks for every need. The “Awesome Scala” list provides a list of hundreds of open source projects that are available to Scala developers, and the Scaladex provides a searchable index of Scala libraries. Some of the more notable libraries are listed below.
Web development
- The Play Framework followed the Ruby on Rails model to become a lightweight, stateless, developer-friendly, web-friendly architecture for highly-scalable applications
- Scalatra is a tiny, high-performance, async web framework, inspired by Sinatra
- Finatra is Scala services built on TwitterServer and Finagle
- Scala.js is a strongly-typed replacement for JavaScript that provides a safer way to build robust front-end web applications
- ScalaJs-React lifts Facebook’s React library into Scala.js, and endeavours to make it as type-safe and Scala-friendly as possible
- Lagom is a microservices framework that helps you decompose your legacy monolith and build, test, and deploy entire systems of Reactive microservices
HTTP(S) libraries:
JSON libraries:
Serialization:
Science and data analysis:
Big data
AI, machine learning
- BigDL (Distributed Deep Learning Framework for Apache Spark) for Apache Spark
- TensorFlow Scala
FP & FRP
FP:
Functional reactive programming (FRP):
Build tools
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.