# Complete guide : Scala programming language

Life is too short to write an introduction. Let's get started!

## Syntax of Scala

Scala has a friendly mixture of C-like syntax and functional programming expressions, but
in a more imperative way. Scala code remains short and concise with high readability.

## Language Concepts

Following are the interesting facts about the language

- Scala is a
functional programming language . So functions are first-class citizen. - Scala is also an
object-oriented programming language . So objects are also first-class citizen. - Scala runs on JVM. Thus, you can use Java libraries too.
- Scala and Java primitive data types are compatible and interchangable.
- Scala comes with data immutability

## Functional Programming (Scala-ish)

Scala is a functional programming language but not purely. By design, it is
inspired heavily by Haskell so we see lots of borrowed features as follows.

### Algebraic data types

A concept of algebraic data types can easily confuse people.
Unlike usual data types, algebraic data types allow following behaviours of variables.

Composition of values. Similar to C++ struct, this data type is capable of holding multi-field data like:

```
case class MyData(a: Int, b: String, c: List[Int])
```

Set of possible values. Similar to C++ enum, but the value can be parameterised. Below is an example of a typeShape which can be either NoShape, Circle or Rect.

```
trait Shape
case object NoShape extends Shape
case class Circle(r: Double) extends Shape
case class Rect(w: Double, h: Double) extends Shape
```

### Pattern matching

Instead of writing explicit if-else to match certain conditional patterns,
Scala offers a more expressive way of writing pattern matching like following.

```
myArray match {
case Nil => "Empty list"
case head :: _ => head.toString
}
```

Matching case classes are also easy.

```
shape match {
case NoShape => None
case Circle(r) => Some(Math.PI
``` r r)
case Rect(w,h) => Some(w * h)
case _ => None
}

Mixing more complex cases are also possible with pattern matching.

```
data match {
case v @ (_ : Type1 | _ : Type2) => process(v)
case v: Type3 if v.isEnabled => v.process
case _ => process(0)
}
```

Magically, pattern matching can also be exploited inside a function like .map(), .filter(), .flatMap().

```
Seq(NoShape, Rect(3,3), Circle(4)).map{
case NoShape => 0
case Circle(r) => r
case Rect(a,b) => a*b
}
```

## Monad Laws

Monad
is a process which you can flatMap and it has to adhere following laws.

### Identity law

Applying a flatMap function on a monad and its true value yields identical results. See the following example.

```
// Define a flatMap function
def f(a: Int) = Some(a * 10)
```

Following two lines yield the identical output.

```
Some(4).flatMap(f) -- equals Some(40)
f(4) -- equals Some(40)
```

### Associativity law

Sounds very familiar? Yes, this is the same associativity law in math.
The flatMap operators have associative property. Thus you can do the following.

```
def f(a: Int) = Some(a * 10)
def g(a: Int) = Some(a * 5)
```

```
Some(4).flatMap(f).flatMap(g) -- equals Some(200)
Some(4).flatMap(i => f(i).flatMap(g)) -- also equals Some(200)
```

## Monoid

Monoid is a concept of a set of data
which you applies some certain operators on its elements, the result still
remain a members of the set. Confusing? Consider the following rules.

### The result of an addition of two monoid elements remains an element of the monoid.

Let's consider a set of integer as a monoid. Picking up any pair
of these integers and add them together still yield an integer.
It never goes off the monoid set.

Given $\forall a \in I, \forall b \in I$

Then,

$c = a + b, c \in I$

### Adding an element with an identity does not change the value.

This applies to any element inside the monoid. Say 0 is an identity
value for integer, you add it to any integer values you still get
the same value.

`identity + a = a`

### Foldability and reducability

You may have been a user of .fold() or
.reduce() operators in other languages.
Folding or reducing a list of monoidic values results in
a monoidic value in the end. Have a look at the signatures below.

List's fold function signature.

```
def fold[A1 >: A](z: A1)(op: (A1, A1) ⇒ A1): A1
```

List's reduce function signature.

```
def reduce[A1 >: A](op: (A1, A1) ⇒ A1): A1
```

It is obvious such that both .fold() and
.reduce() obey monadic rules. They take
monadic elements as parameters and their output still
remain inside the same monadic set.

`You start with a list of integer. Reducing them into one single scalar value still gets you an integer.`

Scala, however, does not natively allow you to implement your own
Monoid. There are some widely-used functional programming framework
which supports this feature more natively including cats

## Mixin + Traits

Mixin is supported and
motivated natively by Scala. You can define a trait having certain set
of functionality and share across multiple classes or even traits.

See the example below.

```
trait Splittable[A] {
def split: Seq[A]
}
.
trait Joinable[A] {
def join(ns: Seq[A]): Seq[A]
}
```

Then you can pluck the traits above into certain classes or traits
you want to mix these functionality in natively as follows.

```
class MyData[A] extends BaseClass[A]
with Splittable[A]
with Joinable[A]
.
.
class YourData[A,B] extends BaseClass[A]
with Joinable[A]
```

## Generic Typings

You may wonder what is the use of [A] in the example
above. Thinking of C++ generic class which you can define a class
which works with any kind of type T. In Scala, this idea works similarly
but with more flexibility.

### With generic type

Let's define a class or trait with a generic type as follows.

```
trait T[A] { def f[A](a: A): A }
class C[A] extends T[A]
```

The example above is simple especially for the people who are already
familiar with C++ generic class. Instead of restricting the trait and
class with specific type like Int, Boolean, String, etc, you loosen
the constraint with generic type A.

### Tighter type constraint, upperbound

In C++, generic typing does not allow you to constraint the
type T to only works with numeric types or certain classes.
Lucky enough, Scala allows you to do so.

```
trait Base
trait Child extends Base
trait GrandChild extends Child
.
.
class C[T]
class D[T <: Base]
```

From example above, the key differences between C and D are.

C is bound toany type T. D is bound toBase or any of its child traits/classes.

### Tighter type constraint, lowerbound

In oppose to constraint above, we can constrain the deepest subtypes
to bind with the class as follows.

```
trait Base
trait Child extends Base
trait GrandChild extends Child
.
.
class D[T <: Child]
class E[T >: Child]
```

From example above.

D is bound to Child or any of itschild traits/classes so Child and Grandchild work.E is bound to Child or any of itssuperclasses so Child and Base work.

## Destructuring Patterns

Similar to Python, you can destructure the values like so.

```
val Seq(a,b,c) = Seq(1,2,3)
val n::ns = Seq(1,2,3)
```

Then you'll get the following values assigned to variables.

`a=1, b=2, c=3, n=1, ns=Seq(2,3)`

It works with case class too.

```
case class C(a: Int, b: Int=0, c: Boolean=false)
.
val k = C(30)
val C(a,b,c) = k
```

Then you'll get the following values assigned to variables.

`a=30, b=0, c=false`

## Best Practices

I recommend reading Effective Scala
as a starting point. The guide is highly comprehensive and suggests
lots of common practice of writing a more readable and better Scala code.