Scala: Useful User Information + Why you should consider the Language

Alex Heres
Apr 22 · 9 min read

In general, becoming proficient in Scala is a benefit for many reasons: It is a multi-paradigm language (functional, object-oriented) with syntax closely resembling that of Java, and even has access Java libraries and compiles programs on a JVM. In this post, we look over the lesser-known benefits of Scala, and why one might consider using the language to approach a task or project.

Benchmarking Speed

In terms of execution speed, we already know Scala has great benefits since it is a compiled language. But how does it stack up to other compiled languages, such as C++ and Java? To measure this, we will run a benchmark on 3 languages and compare the times of each.

The Test

What we will do to compare the benchmarking speeds of 2 programming languages, is run the same program in both languages, making sure to capture the time take to execute the program entirely. Specifically, we will see how long each language takes to run ten million unsuccessful binary searches.

For each language, we will use an iterative binary search algorithm to perform unsuccessful searches on a large array of integers, size 2097152. We are interested in the time it takes for the binary searches only, so we make sure not to include the instantiation times for the array, etc.

The algorithm will run 10 times on each language, where we can collect an average. We will also try to match the syntax between languages as closely as possible.

Scala Program and Results

The following is the Scala source code we used to run our experiment:

object MyProgram extends App {
def iterativeBinarySearch(list: Array[Int], target: Int): Int = {
var left = 0
var right = list.length - 1
while (left <= right) {
val mid = left + (right - left) / 2
if (list(mid) == target)
return mid
else if (list(mid) > target)
right = mid - 1
else
left = mid + 1
}
-1
}

def tenMillionSearches(numList: Array[Int], numListSize: Int): Unit = {
var avg: Double = 0
print("Times for 10,000,000 unsuccessful binary searches on array of size " + numListSize + ": \n")
for (i <- 1 to 10) {
val begin = System.currentTimeMillis

for (j <- 0 until 10000000) {
iterativeBinarySearch(numList, 1)
}

val elapsedTime = System.currentTimeMillis - begin
avg += elapsedTime

print("Trial #" + i + ": " + elapsedTime + " milliseconds.\n")
}

avg /= 10
print("Time for 10,000,000 unsuccessful binary searches on array of size " + numListSize + ", averaged over 10 runs: " + avg + " milliseconds.\n")

}

val arr = Array.fill(2097152)(0)
tenMillionSearches(arr, 2097152)
}

Running the program above, we obtain the following results:

Scala vs. C++

Now we write the same program in C++. We have the following C++ code:

#include <iostream>
#include <time.h>

int iterativeBinarySearch(int arr[], int size, int key)
{
int lowerBound = 0;
int higherBound = size - 1;

while (lowerBound <= higherBound)
{
int middle = (lowerBound + higherBound) / 2;

if (arr[middle] == key)
return middle;

else if (arr[middle] > key)
higherBound = middle - 1;

else
lowerBound = middle + 1;
}
return -1;
}

void tenMillionSearches(int numList[], int numListSize)
{
double avg = 0;

std::cout << "Times for 10,000,000 unsuccessful binary searches on array of size " << numListSize << ": " << std::endl;
for (int i = 0; i < 10; i++)
{
clock_t begin = clock();
for (int j = 0; j < 10000000; j++)
iterativeBinarySearch(numList, numListSize, 1);

double elapsed_secs = double(clock() - begin) / CLOCKS_PER_SEC;
avg += elapsed_secs;
std::cout << "Trial #" << i + 1 << ": " << elapsed_secs << " seconds." << std::endl;
}

avg /= 10;
std::cout << "Time for 10,000,000 unsuccessful binary searches on array of size " << numListSize << ", averaged over 10 runs: " << avg << " seconds." << std::endl;
}

int main()
{
int* arr = new int[2097152];
tenMillionSearches(arr, 2097152);
delete[] arr;

system("pause");
return 0;
}

We have the following results from our program:

By direct comparison of our timings, the C++ times are almost twice as long as our Scala times.

Scala vs. Java

Finally, we’ll write our program for another JVM language: Java.

public class BinarySearch {

int binarySearch(int arr[], int x) {
int l = 0, r = arr.length - 1;
while (l <= r) {
int m = l + (r-l)/2;

if (arr[m] == x)
return m;

if (arr[m] < x)
l = m + 1;

else
r = m - 1;
}
return -1;
}

void tenMillionSearches(BinarySearch bs, int numList[]) {
double avg = 0;

System.out.println("Times for 10,000,000 unsuccessful binary searches on array of size " + numList.length + ": \n");
for(int i = 0; i < 10; i++) {
long start = System.currentTimeMillis();
for (int j = 0; j < 10000000; j++) {
bs.binarySearch(numList, 1);
}

double elapsed = (System.currentTimeMillis() - start) / 1000.0;
avg += elapsed;
System.out.println("Trial #" + (i + 1) + ": " + elapsed + " seconds.");
}
avg /= 10;
System.out.println("Time for 10,000,000 unsuccessful binary searches on array of size " + numList.length + ", averaged over 10 runs: " + avg + " seconds.");

}

public static void main(String[] args) {
BinarySearch bs = new BinarySearch();
int arr[] = new int[2097152];

bs.tenMillionSearches(bs, arr);
arr = null;
}
}

With Java, we obtain the following results:

These are our fastest times yet, just slightly faster than those of Scala. Out of our three tested languages, C++ had the slowest times, while Java had the fastest.

Scala’s performance in this simple benchmark was actually pretty good compared to other compiled languages, and was among one of the fastest.

Safety

Programmers can make all kinds of mistakes; copy-paste errors, code typos, typing errors, you name it. Depending on the mistake, the impacting consequence can vary. Safety is the application of programming practices that prevent these kinds, including type safety to prevent type errors.

In general, we try to make the most out of what we know about our values at compile-time to minimize the consequences of these mistakes.

Avoiding Null

In a compiled language with a type-checker, like Scala, many such mistakes are caught before you even run your code by the compiler. Passing in the wrong type such as an int when a string was expected results in a type-error. Passing in null when no-null was expected results in an error that is not caught by the compiler.

Avoiding Side Effects

Side effects in Scala are not detected by the compiler, and can lead to serious program errors. Let us look at an example.

var result = 0

for (i <- 0 until 10) {
result += i
}

if (result > 10) result = result + 5

println(result) // 50
makeUseOfResult(result)

Here, the result variable is calculated via mutations (i.e. where result is incremented) and prepared for use with the makeUseOfResult function. But what if makeUseOfResult receives some invalid input produced by a particular mutation, or the lack thereof?

var result = 0

for (i <- 0 until 10) {
results += i
}

println(result) // 45
makeUseOfResult(result) // invalid input!

A good solution to this problem would be to eliminate the side effects, while specifying each stage of the result variable such that we eliminate the ambiguity of possible errors:

val summed = (0 until 10).sum

val result = if (summed > 10) summed + 5 else summed

println(result) // Compilation Failed: not found: value result
makeUseOfResult(result)

Note that this does not make your code ‘invincible’. For example, using the result variable before its ready, even indirectly, will lead to a compilation error.

Structured Data and Variance

We have covered variance a little bit in the past, and know that the use of variance in the type system allows us to make intuitive connections between complex types. For example:

  • A covariant class Foo[+A] implies that for two types A and B where A is a subtype of B, then List[A] is a subtype of List[B].
  • A contravariant class Foo[-A] implies that for two types A and B where A is a subtype of B, List[B] is a subtype of List[A].
  • An invariant class Foo[A] is the default of generic classes in Scala. A Foo[A] is not a Foo[B], nor is the reverse true.

Using variance to our advantage, we can specifically define classes that have a more-complex relationship of its objects. For a more detailed explanation of class variance in Scala, please check out the official documentation.

Ease of Use

Scala is an accessible language in that it is easy to start programming in the language right away, even if you do not have the language or its requirements installed.

Running Scala Programs without an Installation

If you are looking to run some Scala code but your machine lacks the required build tools, worry not for there is Scasti.

Scastie is an simple online Scala IDE with substantial configuration options. Programs compiled with Scastie are built using sbt.

In the Build Settings tab, you can change the following information:

  • The Target Compiler (set to Scalac by default)
  • Scala Version (set to 2.12.8 by default)
  • Libraries to Include in Project
  • Sbt Configuration (build.sbt file settings)

Alternatively, if you are interested in installing the tools needed write Scala programs straight from your machine’s command line, you can refer to our installation guide.

Intuitive Syntax, and Up-To-Date Documentation

Scala is very similar to Java in syntax. Though in Scala, the semicolon at the end of lines is optional.

  • Case Sensitivity — As with most programming languages, case sensitivity exists in Scala. If you have Foo and foo, they would have different meanings.
  • Program file name — the program file should match the object name. If this does not match, the program will not compile.

Currently, the Scala language is up to version 2.13.0, and many previous versions of the language can be found here. For each of these versions, there is extensive documentation and APIs that can be found here.

Since each version’s documentation is available with great community support, a lot of the versions are viable options to choose to use for a project, though we generally recommend one of the more recent versions.

Memory Footprint

In terms of performance, the next most important concept alongside time complexity, is space complexity.

Data Types and Their Sizes

The following table lists Scala data types along with their sizes and ranges:

Why You Should Write in Scala

Scala is a powerful language which combines the functionalities of functional as well as object oriented programming languages.Functions, macros, and tuples are some of those functionalities.Scala’s complex features promote better coding and performance increase.

Scala was introduced in 2003 to address many of the concerns associated with Java. the language was built on top of the Java Virtual Machine to offer compatibility with Java and Interoperability. According to Google’s run-time measurements:

  • Scala provides code complexity optimization
  • It offers concise notation

Testing and development in Scala are also amplified as a result of developers utilizing strength of both object oriented and functional coding paradigms. Also, it can perform the same tasks as Java with less lines of code. An obvious question arises, why can’t we simply shorten the code in Java? That is possible but the methods would break away from standard practice and makes it harder to read.

Scala has a learning curve i.e it takes a while to master this language but it adds to Java and make it more functional. Some of the features introduced by Scala are:

  • String comparison advancements
  • Pattern matching
  • Mixins, which incorporate functions in class definitions.
  • Class variance

Scala is a fun learning experience that a lot of developers compare with other languages. It is accessible and well-documented which makes it a good decision for developers with varied levels of experience. It also includes a full fledged API library. It is easier to code, test, debug and deploy a scalable software. For any software and program using Scala never affects the performance adversely. It is versatile and can be used to develop desktop software, games, web apps, mobile solutions and software as a service. Klout, LinkedIn, Amazon, Blizzard, Coursera, Twitter are using Scala now a days. It offers clean code, advanced features, functional and object-oriented programming in an open-source package that leverages Java’s environment.

Authors

Alessandro Heres — Github
Tristen Sprainis — Github
Ayushi Priyadarshi — Github | LinkedIn

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade