What is Scala?

Scala is a statically typed programming language that incorporates functional and object-oriented programming. It primarily targets the JVM platform but can also be used to write software for multiple platforms, including native platforms using Scala-Native and JavaScript runtimes through ScalaJs.

Scala is a programming language written for increasing the scalability of the application. It is a Scalable Language. Hence, it got the name "Scala". This language is intended to solve the problems of Java while simultaneously being more concise. Initially designed by Martin Odersky, it was released in 2003.

In this Scala programming tutorial for beginners, you will learn:

Why learn Scala

Here, are prime reasons for learning Scala:

  • Scala is easy to learn for object-oriented programmers, Java developers. It is becoming one of the popular languages in recent years.
  • Scala offers first-class functions for users
  • Scala can be executed on JVM, thus paving the way for the interoperability with other languages.
  • It is designed for applications that are concurrent, distributed, and resilient message-driven. It is one of the most demanding languages of this decade.
  • It is concise, powerful language and can quickly grow according to the demand of its users.
  • It is object-oriented and has a lot of functional programming features providing a lot of flexibility to the developers to code in a way they want.
  • Scala offers many Duck Types
  • It has less boilerplate if you are coming from Java
  • The frameworks Lift and Play written in Scala are in the growth curve.

How to install Scala

To begin writing Scala programs, you need to have it installed on your computer. In order to do this, you will need to visit their site https://www.scala-lang.org/download/ in order to download the latest version of Scala.

Following the link, we're led to two options which we can choose to install Scala on our machines. For this tutorial, we'll download the IntelliJ IDE.

Once you visit the download link, you'll find two versions of the IntelliJ IDE.

For this tutorial, we'll download the Community Edition, which is free and comes with all you need to write Scala programs.

Step 1) on the page, click on the dropdown on the Community Edition.

It presents us with an option to download the IntelliJ IDE together with JBR which contains a JDK implementation(Java Development Kit) OpenJDK which Scala needs to compile and run the code.

Step 2) Once you download IntelliJ, double click it in order to run the installation wizard and follow the dialog.

Step 3) Choose a location to install the IDE.

If by chance you didn't download the one with the JDK, we still get a prompt where that we can check to download it by selecting the checkbox.

Step 4) Leave the other defaults as they are and click next.

Step 5) Once the installation completes, run the IntelliJ IDE by clicking its startup icon in the startup menu like a regular application.

You still need to go through an additional step of adding the Scala plugin to IntelliJ; you do so by clicking the dropdown on the configure menu located at the bottom right of the screen and selecting the plugin option.

On the Marketplace tab, a search for Scala will present the plugin as the first result under the Languages tag.

Step 6) Click install, which will lead the plugin beginning the download.

Step 7) After the download completes, you'll be prompted to restart the IDE so that the installed plugin can start working.

After restarting you'll find yourself on the same page as before when we ran the IDE, but this time around we have already installed the Scala plugin.

Scala Hello World Program

Step 1) Select the Create Project option, which will lead us to a page where we can select the kind of language our project will be using.

Step 2) choose Scala by selecting the Scala checkbox and click next.

Step 3) Select a location to save our projects file and give our project a name.

If the directory doesn't exist, IntelliJ will prompt us to ask us for permission to create the folder. Accept and click finish. You will be taken to your Scala project, which currently doesn't have any Scala code.

It will take some time to load some indexes so don't worry if you're not able to immediately do anything while there's a progress bar at the bottom of your IDE, it simply means your IDE is loading some files necessary to run Scala and help with IDE autocompletion.

Step 4) Next, we'll click on the projects tab on the left of the IDE and expand so we can see the contents of our project.

At the moment the project is empty and only contains a .idea folder and hello-world.iml file generated by the IDE. Our point of interest is the src folder. Src is where we store the source code for our project. It's where we'll create our first Scala file.

Step 5) Right-click on src to open a menu to create a new Scala file.

We will then create a name for the file, in this tutorial we'll use hello and then choose from a dropdown what to put as the content of the Scala file. Select "Object"

Once we do this, we'll have a Scala file that has a Singleton object that we'll use to run our code.

Now that you have a Scala file with a Hello object. You will write your first program by extending the object you have created using the App keyword.

Extending our object with App tell the compiler which code to run when it starts your program. Immediately after extending App, a green arrow shows up on the left side, indicating that you can now be able to run your program.

Inside the Hello object, we write one function println() which is used to print the text inside it to the console. We will run our code by clicking on the green arrow.

Clicking the arrow presents us with the option Run, hello, upon clicking it, our code will start compiling and after some seconds we'll see the results of our program printed from the console that's inbuilt in the IntelliJ IDE.

And there we go, we have successfully installed Scala and run our first program.

What you can do with Scala

  • Frontend web development with ScalaJS
  • Mobile development, both Android Development and IOS - with Scala Native
  • Server-side libraries like HTTP4S, Akka-Http, Play Framework
  • Internet of things using
  • Game development
  • NLP - Natural Language Processing using a suite of libraries ScalaNLP
  • Testing advanced programming techniques such as Functional Programming and in Object-Oriented Programming
  • Build highly concurrent communication application using actors a library for the JVM inspired by Erlang
  • Use it for machine learning using libraries like Figaro that does probabilistic programming and Apache Spark that

Anonymous Functions

The Scala language has anonymous functions, which are also called function literals. Scala being a functional language often means developers break down large problems into many small tasks and create many functions to solve these problems. To make it easy to create functions, Scala contains these functions that can be instantiated without a name. We can assign them directly to variables or definitions 'def' as follows

val multiplyByTwo = (n:Int) => n * 2
def multiplyByThree = (n:Int) => n *3

We can then use the normal way we use functions by passing parameters to them follows.

multiplyByTwo(3)

//6

multiplyByThree(4)

//12

These methods come in handy when we want to have a clean and concise code. We can use anonymous functions when defining methods that are not large and don't require a lot of code in their body. They're very simple and don't need a ceremony to create.

These methods are not limited to functions with arguments and can be used to instantiate methods that don't take in any arguments.

val sayHello = ()=>{ println("hello") }

Most of these anonymous functions are used in other parts of our code where we need to create a quick function in place.

Another reason why these functions are also referred to as inline functions. Using anonymous functions is a common pattern which is used pervasively in the collections library to perform quick actions over a collection.

For instance, we have the filter method that takes an inline function/anonymous function to create another collection with only elements that meet the criteria we define in the anonymous function.

val myList = List(1,2,3,4,5,6,7)

val myEvenList = myList.filter((n: Int) => n % 2 == 0)
//List(2,4,6)

val myOddList = myList.filter((n:Int) => n % 2 != 0)
//List(1,3,5,7)

Here the methods we have as anonymous functions are the ones checking if the value we're getting from the list is odd and even and returning the item.

//the one checking that the value is even
(n: Int) => n % 2 == 0

//the one checking that the value is odd
(n:Int) => n % 2 != 0

In Scala, it's also possible to use wildcards where our anonymous function's parameter aren't named. For example

var timesTwo = (_:Int)*2

timesTwo(5)
//10

In this scenario, we don't name the parameter we're passing in. The only thing we use an underscore to represent it.

Lazy Evaluation

Most languages sequentially evaluate variables and function parameters, one after the other. In Scala, we have a keyword called lazy, which helps in dealing with values we don't want to be evaluated until they're referenced.

A variable marked as lazy won't be evaluated where it is defined, that's commonly known as eager evaluation, it will only be evaluated when it's referenced at some later in the code.

This can be helpful when evaluating a value might be an expensive computation, if it's not the case that the value is always needed, we can save ourselves from running an expensive computation which can slow down our software by making our variable lazy.

lazy val myExpensiveValue = expensiveComputation

def runMethod()={
    if(settings == true){
        use(myExpensiveValue)
    }else{
        use(otherValue)
    }
}

This is not the only use case for lazy variables. They also help deal with issues of circular dependency in code.

In case the settings is false, we might not need to use myExpensiveValue, which can lead us to save us from doing an expensive computation which helps ensure that users have a nice time using our application as our their other needs can be properly computed without overwhelming the RAM.

In case the settings is false, we might not need to use myExpensiveValue, which can lead us to save us from doing an expensive computation which helps ensure that users have a nice time using our application as our their other needs can be computed appropriately without overwhelming the RAM.

The laziness also helps with function arguments, where the arguments are only used when they're referenced inside the function. This concept is called Call-by-name parameters.

def sometimesUsedString(someValue:String, defaultValue:=> String)={
 if(someValue != null){
   use(defaultValue)
 }else{
   use(someValue)
   }
 }

Many languages use the call-by-value way of evaluating arguments. The parameter passed through call-by-name will only be evaluated when needed in the function body and will not be evaluated before that. Once the value is evaluated, it is stored and can be reused later without it having to be re-evaluated. A concept which is known as memoization.

Type Inference

In Scala, you don't have to declare types for every variable you create. This is because the Scala compiler can do type inference on types based on evaluation of the right-hand side. This allows your code to be more concise - it frees us from writing boilerplate where the expected type is obvious

var first:String = "Hello, "
var second:String = "World"
var third = first + second
//the compile infers that third is of type String

Higher-Order-Function

A higher-order function is a function that can take functions as arguments and can return a function as a return type. In Scala, functions are considered first-class citizens. Using these functions this way enables us to be very flexible in the kind of programs we can make. We can create functions dynamically and feed in functionality dynamically to other functions.

def doMathToInt(n:Int, myMathFunction:Int=>Int): Int ={
    myMathFunction(n)
}

In the above function, we pass in an int and a function that takes an int and returns an int. We can pass in any function of that signature. By signature, we mean a function's input and output. A signature of Int=>Int means that a function takes an Int as input and returns an Int as its output.

A Signature of ()=>Int means that a function takes nothing as it's input and returns an Int as its output. An example of a function like that would be one that generates a random int for us.

def generateRandomInt()={
 return scala.util.Random.nextInt()
}

The above function has a signature ()=>Int

We can have a function that has a signature scala ()=>Unit. This means the functions don't take anything in and doesn't return a type. The function could be doing some kind of computation by changing something to doing something predetermined.

These kinds of methods are not encouraged, though, as they seem to be a black box that can affect a system in some unknown ways. They're also untestable. Having explicit input and output types enable us to reason about what our function does.

A higher-order function can also return a function.

For example, we could create a method that will create a powering function, i.e., takes a number and applies power to it.

def powerByFunction(n:Int):Int=>Int = {
  return (x:Int)=> scala.math.pow(x,n).toInt
}

The above function takes an int. Our return type is an anonymous function that takes an Int x, * we use the int x as the argument for the power function.

Currying

In Scala, we can convert a function that takes two arguments into one that takes one argument at a time. When we pass in one argument, we partially apply it and end up with a function that takes one argument to complete the function. Currying enables us to create functions by partially adding some arguments.

This can be useful for creating functions dynamically before we have a complete set of arguments

def multiply two numbers(n:Int)(m:Int): Unit ={
  return n * m
}

If we need to create a function that multiplies by some specific number, we don't need to create another multiplication method.

We can simply call the .curried on our function above and get a function that takes one argument first and return a partially applied function

def multiplyTwoNumbers(n:Int)(m:Int): Unit ={
  return n * m
}

var multiplyByFive = multiplyTwoNumbers(5) 

multiplyByFive(4)

//returns 20

Pattern Matching

Scala has a powerful inbuilt mechanism for helping us check a whether a variable matches up to certain criteria, much like we would do in a switch statement in Java or in a series of if/else statements. The language has pattern matching that we can use to check whether a variable is of a particular type. Pattern matching in Scala is powerful and can be used destructure the components that have an unapply method in order to get fields we're interested in directly from the variable we're matching.

Scala's pattern matching also provides a more pleasant syntax compared to switch statement.

myItem match {
  case true => //do something
  case false => //do something else
  case  _ => //if none of the above do this by default
}

We compare our variable to a set of options, and when the variable we're matching up meets the criteria, the expression on the right-hand side of the fat arrow (=>) evaluates and is returned as the result of the match.

We use an underscore to catch cases that are unmatched in our code. It mirrors the behavior of the default case when dealing with switch statements.

class Animal(var legs:Int,var sound:String)
class Furniture(var legs:Int, var color:Int, var woodType:String)

myItem match {
case myItem:Animal => //do something
case myItem:Furniture => //do something else
case _ => //case we have a type we don't recognize do sth else
}

In the code above, you are able to find out the type of the myItem variable and based on that branch off to some specific code.

Pattern matching checks whether the variable matches

The underscore works as a placeholder that matches any other condition that is not matched by the other items in the case statements above. We take a variable myItem and call the match method.

  • we check whether myItem is true using and do some logic on the Right Hand Side of the fat arrow "=>."
  • we use the underscore to match to anything that doesn't match up to any of the case statements we have defined in the code.

With Case classes, we can even go further and destructure the class to get fields inside the object.

By using the sealed keyword to define our classes, we get the benefit of having the compiler exhaustively check the cases we try to match against and warn us if we forget to handle a particular one.

Immutability

It's possible to create values that can't be changed by other functions in Scala using the val keyword. This is achieved in Java by using the final keyword. In Scala, we do so by using a val keyword when creating a variable instead of using var, which is the alternative we would use to create a mutable variable.

A variable defined using the val keyword is read-only, whereas one defined with var can be read and be changed by other functions or arbitrarily by the user in the code.

var changeableVariable = 8

changeableVariable =10
//the compiler doesn't complain, and the code compiles successfully

println(changeableVariable)
//10

val myNumber = 7

myNumber = 4

//if we try this the code won't compile

Trying to assign a value to myNumber after we've declared it as a val throws a compile-time error or "reassignment to val."

Why use Immutability?

Immutability helps us prevent code and other programmers from changing our values unexpectedly, which would lead to unexpected results if they are intended to use the value we store they can instead make a copy of it. This way, bugs that can be caused by multiple actors changing the same variable are prevented.

Classes and Objects:

We all know that objects are the real-world entities, and class is a template that defines objects. Classes have both state and behaviors. The states are either values or variables. The behaviors are the methods in Scala.

Let us look into how you can define a class, instantiate it, and use it using Scala.

Here, the class called Rectangle, which has two variables and two functions. You can also use the parameters l and b directly as fields in the program. You have an object which has a main method and has instantiated the class with two values.

Example:

class Rectangle( l: Int,  b: Int) {
  val length: Int = l
  val breadth: Int = b
  def getArea: Int = l * b
  override def toString = s"This is rectangle with length as $length and breadth as  $breadth"
  }
object RectObject {
  def main(args: Array[String]) {
    val rect = new Rectangle(4, 5)
    println(rect.toString)
    println(rect.getArea)    
  }
}

All the fields and method are by default public in Scala. It is essential to use override because toString method is defined for Object in Scala.

Inheritance

Scala has multiple types of inheritance (like single, multi-level, multiple, hierarchical, hybrid,) that share a lot in common with traditional forms found in Java. You can inherit both from classes and traits. You can inherit the members of one class into another class using the keyword "extends". This enables reusability.

It's possible to inherit from one class or multiple classes. It's also possible to inherit from subclasses that themselves have their superclasses, creating a hierarchy of inheritance in the process.

In the below example, the Base class is Circle, and derived class is Sphere. A circle has a value called radius, which is inherited in the Sphere class. The method calcArea is overridden using the keyword override.

Example:

class Circle {
  val radius = 5;
  def calcArea = {
    println(radius * radius )
  }
}
class Sphere extends Circle{
 override def calcArea = {
    println(radius * radius * radius )
  }
}
  object SphereObject{
    def main(args : Array[String]){
      new Sphere().calcArea 
    }
  }

Abstraction

In Scala, we can create abstract methods and member fields using abstract classes and traits. Inside abstract classes and traits, we can define abstract fields without necessarily implementing them.

Example:

trait MakesSound{
    var nameOfSound:String
    def sound():String
}
abstract class HasLegs(var legs:Int){
    val creatureName:String

    def printLegs():String={
        return s"$creatureName has this number of legs: $legs"
    }
}

These fields are implemented by the classes that extend the trait or abstract class. You can use traits to create contracts as to what our application should be able to do and then implement those methods later.

trait DatabaseService{
    def addItemName(itemName:String)
    def removeItem(itemId:Int)
    def updateItem(itemId:Int, newItemName:String)
}

This way, we can plan out how our application will look like without implementing the methods which can help us envision how various methods will look like. It follows along a pattern know as programming to abstractions and not the actual implementation.

The class which is prefaced with keyword abstract can contain both abstract and non-abstract methods. But, multiple inheritances is not supported in abstract class. So, you can extend at most one abstract class.

Singleton Objects

A Singleton is a class that is only instantiated once in a program. It's from a popular and useful programming pattern known as the "singleton pattern". It's useful in creating instances that are meant to be long-living and will be commonly accessed throughout your program whose state is integral in coordinating the events of a system. Creating such a class in Scala is easy as Scala provides us with a simple means of creating singletons using the object keyword.

object UserProfile{
    var userName=""
    var isLoggedIn:Boolean = false
}

We can then reference this object throughout our program with the guarantee that all parts of our program will see the same data as there's only one instance of it.

def getLoggedInStatus():Boolean={
   return UserProfile.isLoggedIn
}

def changeLoggedInStatus():Boolean={
    UserProfile.isLoggedIn = !UserProfile.isLoggedIn
    return  UserProfile.isLoggedIn
}

The concept of static members is not there in Scala, that is the reason you need to use singleton objects, which act like static members of a class.

Implicit Classes

Implicit classes are the new functionality added after version 2.1. It is primarily to add new functionality to the closed classes.

The implicit keyword should be defined in a class, object, or trait. The primary constructor of an implicit class should have exactly one argument in its first parameter list. It may also include an additional implicit parameter list.

In the below example, new functionality to replace vowels of a String with * is added.

object StringUtil {
  implicit class StringEnhancer(str: String) {
    
    def replaceVowelWithStar: String = str.replaceAll("[aeiou]", "*")
  }
}

You need to import in the class where you are using it.

import StringUtil.StringEnhancer

object ImplicitEx extends App {
  val msg = "This is Guru99!"
  println(msg.replaceVowelWithStar)
}

Object-Oriented Programming (OOP) vs. Functional Programming(FP)

In OOP programs are constructed by grouping data and the functions that operate on that data into highly connected units. Objects carry their data in the fields and methods that operate on them. In this style of programming, the main abstraction is the data as the methods that are created are meant to operate on the data.

Functional programming, on the other hand, separates data and the functions that operate on the data. This enables developers to treats functions as the abstraction and driving force when modeling programs.

Scala enables functional programming by having functions as first-class citizens, allowing them to be passed as values to other functions and returned as values as well. The combination of these two paradigms has made Scala a great choice in building complex software in various industries, such as Data Science.

Important frameworks on Scala

Here, are some important frameworks of Scala

  • Play is an open-source web application framework that uses MVC architecture. Released in 2007 and now licensed under Apache, It became the most popular framework on GitHub in 2013. Companies such as LinkedIn, Walmart, Samsung, Eero use this framework.
  • Lift is another free web framework written in Scala launched in 2007. Foursquare uses the Lift framework. It is high performing, faster to build framework.
  • Akka
  • Cats
  • Spark

Concurrency support

  • The values in Scala are by default immutable. This makes it very adaptive to the concurrent environment.
  • There are a lot of features in Scala that makes it best for concurrent applications.
  • Futures and Promises make it easier to process data asynchronously, thus supporting parallelism.
  • Akka - toolkit that uses Actor concurrency model. There is a number of Actors that act when they receive messages.
  • Concurrency using threads from Java can also be supported in Scala.
  • Stream processing is another great feature that enables continual, real time processing of data.

Scala has some of the best concurrency libraries in the Java ecosystem.

  • Native Java threads
  • Fibers from libraries like Vertex
  • ZIO - a library that has primitives to help us deal with concurrency and asynchronous computation
  • STM - Transaction
  • Future - inbuilt in the Scala language

Java vs. Scala

Here are the main difference between Java and Scala.

Scala Java
More compact and concise Comparatively larger chunks of code
Designed and Developed to be both object and functional oriented language. Supports a wide variety of functional programming features such as concurrency, Immutability. Originally developed as an object-oriented language and started supporting functional programming features in recent days. Still is not strong as a functional programming language.
Uses actor model for supporting concurrency which is modern Uses the conventional thread-based model for concurrency.
Supports frameworks – Play, Lift Supports Spring, Grails, much more
Supports lazy evaluation Does not support lazy evaluation
No static members Contains static members
Supports operator overloading Does not support operator overloading
Compilation of source code is comparatively slow Compilation of source code is faster than Scala
Traits – act like Java 8 interfaces Java 8 interfaces try to bridge the gap between classes and interfaces
Rewriting is needed Rewriting is not required
No assurance about the bug-free codes Complete assurance of lesser defects
Supports backward compatibility. Scala does not support backward compatibility.
Operators are treated differently in Java and are not method calls. All operators on entries ar via a method called in Scala.
Supports multiple inheritances using classes but not by abstract classes Does not support multiple inheritances using classes, but by interfaces
Code is written in a compact form. Code is written in long form.
Scala does not contain the static keyword. Java contains the static keyword.

Summary:

In this tutorial, you have learned how to get started with Scala. You have also learned the functional and object-oriented features. You have also discovered the similarities and differences between Java and Scala. This tutorial should have helped you with a wide variety of examples that are well demonstrated.

 

YOU MIGHT LIKE: