# Introduction Scala#

## Basics#

### Types#

In Scala, there are 5 major types

Type

Literal

Description

Boolean

true, false

Int

3, 0x32

32 bits integer

Float

3.14f

32 bits floating point

Double

3.14

64 bits floating point

String

“Hello world”

UTF-16 string

### Variables#

In scala, you can define a variable by using the `var` keyword:

```var number : Int = 0
number = 6
number += 4
println(number) // 10
```

Scala is able to infer the type automatically. You don’t need to specify it if the variable is assigned at declaration:

```var number = 0   //The type of 'number' is inferred as a Int during the compilation.
```

### Constants#

But, in fact, it’s not very common to use `var` in Scala. Instead, constant values defined by `val` are often used:

```val two   = 2
val three = 3
val six   = two * three
```

### Functions#

For example, if you want to define a function which returns `true` if the sum of its two arguments is bigger than zero, you can do as follows:

```def sumBiggerThanZero(a: Float, b: Float): Boolean = {
return (a + b) > 0
}
```

Then, to call this function, you can just write:

```sumBiggerThanZero(2.3f, 5.4f)
```

You can also specify arguements by name, which is useful if you have many arguements:

```sumBiggerThanZero(
a = 2.3f,
b = 5.4f
)
```

#### Return#

The `return` keyword is not necessary. In absence of it, Scala takes the last statement of your function as the returned value.

```def sumBiggerThanZero(a: Float, b: Float): Boolean = {
(a + b) > 0
}
```

#### Return type inferation#

Scala is able to automatically infer the return type. You don’t need to specify it:

```def sumBiggerThanZero(a: Float, b: Float) = {
(a + b) > 0
}
```

#### Function that returns nothing `Unit`#

If you want a function to return nothing, the return type should be set to `Unit`. It’s equivalent to the C/C++ void.

```def printer(): Unit = {
println("1234")
println("5678")
}
```

#### Arguements default value#

You can specify a default value for each arguement of a function:

```def sumBiggerThanZero(a: Float, b: Float = 0.0f) = {
(a + b) > 0
}
```

#### Apply#

Functions named apply are special because you can call them without having to type their name:

```class Array(){
def apply(index: Int): Int = index + 3
}

val array = new Array()
val value = array(4)   //array(4) is interpreted as array.apply(4) and will return 7
```

This concept is also applicable for scala `object` (static)

```object MajorityVote{
def apply(value: Int): Int = ...
}

val value = MajorityVote(4) // Will call MajorityVote.apply(4)
```

### Object#

In scala, there is no `static` keyword. In place of that, there is `object`. Everything defined into an `object` is static.

The following example defines a static function named `pow2` which takes a floating point value as parameter and returns a floating point as well.

```object MathUtils{
def pow2(value: Float): Float = value*value
}
```

Then you can call it by writing:

```MathUtils.pow2(42.0f)
```

### Entry point (main)#

The entry point of a Scala program (the main function) should be defined inside an object as a function named `main`.

```object MyTopLevelMain{
def main(args: Array[String]) {
println("Hello world")
}
}
```

### Class#

The class syntax is very similar to Java. Imagine that you want to define a `Color` class which takes as construction parameters three Float values (r,g,b) :

```class Color(r: Float, g: Float, b: Float){
def getGrayLevel(): Float = r * 0.3f + g * 0.4f + b *0.4f
}
```

Then, to instantiate the class from the previous example and use its `getGrayLevel` function:

```val blue = new Color(0, 0, 1)
val grayLevelOfBlue = blue.getGrayLevel()
```

Be careful, if you want to access a construction parameter of the class from the outside, this construction parameter should be defined as a `val`:

```class Color(val r: Float, val g: Float, val b: Float){ ... }
...
val blue = new Color(0, 0, 1)
val redLevelOfBlue = blue.r
```

#### Inheritance extends#

As an example, suppose that you want to define two classes, `Rectangle` and `Square`, which extend the class `Shape`:

```class Shape{
def getArea(): Float
}

class Square(sideLength: Float) extends Shape {
override def getArea() = sideLength * sideLength
}

class Rectangle(width: Float, height: Float) extends Shape {
override def getArea() = width * height
}
```

#### Case class#

Case class is an alternative way of declaring classes.

```case class Rectangle(width: Float, height: Float) extends Shape {
override def getArea() = width * height
}
```

Then there are some differences between `case class` and `class` :

• case classes don’t need the `new` keyword to be instantiated

• construction parameters are accessible from outside, you don’t need to define them as `val`.

In SpinalHDL, this explains the reasoning behind the coding conventions: it’s in general recommended to use `case class` instead of `class` in order to have less typing and more coherency.

### Templates / Type parameterization#

Imagine you want to design a class which is a queue of a given datatype, in that case you need to provide a type parameter to the class:

```class  Queue[T](){
def push(that: T) : Unit = ...
def pop(): T = ...
}
```

If you want to restrict the `T` type to be a sub class of a given type (for example `Shape`), you can use the `<: Shape` syntax :

```class Shape() {
def getArea(): Float
}
class Rectangle() extends Shape { ... }

class  Queue[T <: Shape](){
def push(that: T): Unit = ...
def pop(): T = ...
}
```

The same is possible for functions:

```def doSomething[T <: Shape](shape: T): Something = { shape.getArea() }
```