Object-georiënteerde Software Ontwikkeling - Exercises

Overview

This course will be taught in Dutch, but the exercises are written in English. The exercises become available at the start of the session and the solutions will be posted at the end of the session.

Tools

We will be using the IntelliJ IDEA which should be pre-installed on the Linux machine. In case you want to use your own machine, make sure that you have installed a Java SE Development Kit (JDK). You can download the latest one from here. Next, you can download the community IntelliJ IDEA from here.

Make sure you have the Scala plugin installed and enabled. To check this, open IntelliJ IDEA, on the main screen go to Configure > Settings > Plugins and search for Scala (Scala, SBT, SSP, HOCON and Play 2 support). When you do not find this plugin, click on Browse Repositories, search for Scala in the category Languages and install it. You might have to restart IntelliJ IDEA before the plugin starts working.

Install Scala plugin

As a start, click on Create New Project to create a Java project and select Scala under Additional Libraries and Frameworks. The Project SDK should point to the location of the Java 8 JDK. In case this field indicates <None>, click New... > JDK and select the JDK folder (default-Java on the machine). You should fill in a name, click Next and subsequently click Finish. The field Use library should point to scala-sdk-2.12.x. In case this field indicates [No library selected], Click Create > Download > Scala version 2.12.1 (or later), it should download the SDK and configure the field correctly. It should look similar to the picture depicted below.

Create new project

Click Next, fill in a name and subsequently click Finish. The project should be created succesfully.

Scala

The documentation, style guide, cheatsheets etc. of Scala can be found at http://docs.scala-lang.org.
The API can be found at http://www.scala-lang.org/api/current.

Session 1: Variables & functions.

You can start by creating a new Scala project by clicking on Java and selecting Scala under Additional Libraries and Frameworks. You should only have to fill in a name, click Next and subsequently click Finish.

It is suggested for now to create Scala Worksheets and write your code there. You can do this by right-clicking on the source (src) folder and clicking on New > Scala Worksheet. To execute the code you've written, simply click on the green arrow to evaluate the worksheet. You can also evaluate parts of the worksheet by selecting the code and right-click to choose Send Selection to Scala Console or Run Scala Console to run the code in a newly instantiated console. You can choose whatever way works best for you.

1. Variables
1.1 Definition

The syntax of a variable definition is as follows:

v name: type = value

where the following applies:

  • v is either var or val to indicate that the variable is either mutable or not,
  • type is the type of the variable (can be optional) and
  • value is the initial value.

Scala is a statically-typed language. This means that variables are associated with a type. This is in contrast to dynamically-typed languages (e.g. Scheme, Python) where types are associated with values. The following value types are defined in Scala: Byte, Short, Int, Long, Char, String, Float, Double, Boolean and Unit.

Scala's type hierarchy
1.2 Type inference

1.2.1 Execute the following piece of code and observe the result of the evaluation.

scala> val n = 1
n: Int = 1

Surprisingly, the compiler was able to detect that we assigned an integer to n even though we omitted the type of the variable. This ability is called type inference and allows us to ommit the type in places where the compiler can infer it.

Do you think that the following code snippets will execute successfully? Do you know why?

scala> val n = 1 + "ok" 
scala> val n:Int = 1 + "ok"

Hint: search through the API of the class Int.

2. Functions
2.1 Definition

The syntax of a function definition is as follows:

def name(p1: t1, p2: t2, ..., pn: tn): rt = { body }

where the following applies:

  • name is the function name in lower camel case,
  • px: tx is a combination of a parameter name px and its corresponding type tx,
  • rt is the result (i.e. return) type of the function (can be optional),
  • body is the body of the function, the curly braces are optional for functions that consist of a single expression.

Additionally, parenthesis are optional in case there are no formal parameters. As a convention, functions that perform side-effects should always define the (empty) parenthesis. Finally, the last expression of the body is considered to be the result value. The following examples are all valid:

def name(p1: t1, p2: t2, ..., pn: tn): rt = body
def name: rt = body

The type signature of a function is defined as follows: (t1, t2, ..., tn) ⇒ rt. This means that there exists a function that takes n arguments of the type tx and returns a value of type rt. For example, the function increment its type signature is Int ⇒ Int and can be written as follows:

def inc(n: Int) = n + 1

It is also possible to nest function definitions which introduces lexical scoping, similar to Scheme. For example, the local function g has access to the parameter n, even though it does not take any parameters itself.

def f(n: Int) = { 
  def g = n + 1
}

Note: Remember that parameters are immutable and that you cannot change this!

An interesting feature are default arguments. These enable you to give a default value for a parameter by assigning a the default value to the parameter:

def f(n: Int = 2) = { 
...
}

Given this method definition, you can call f by either f() (i.e., without any argument) which implies that the value of n will be 2 (as specified by the default argument) or f(4) which implies that the value of n will be 4.

Another feature are named arguments.

2.2 Simple and recursive functions

2.2.1 Write a function that computes the average of two integers.

2.2.2 Write a function that computes the minimum of two integers.

2.2.3 What is the diference between defining something with val (or var) and def? Try it out by executing and observing the results between both versions.

val inc = println("ok")
def inc = println("ok")

2.2.4 Write a tail-recursive function that computes the factorial of an integer.

2.2.5 Write a function that computes the factorial of an integer by using a local function facIter.

2.2.6 Write a function that computes the fixpoint of a function using the half interval method. The Scheme version is shown below as a reference. What is the fixpoint of f(x) = (x * 2) + 3?

(define (search f a b)
  (define (average x y) (/ (+ x y ) 2.0))
  (define (close-enough? x y)
    (< (abs (- x y)) 0.001))
  (let ((mid (average a b)))
    (if (close-enough? a b)
      mid
      (let ((value (f mid)))
        (cond
          ((positive value) (search f a mid))
          ((negative value) (search f mid b))
          (else mid))))))

2.2.7 Write a function that computes the fixpoint without requiring boundaries. The Scheme version is shown below as a reference. Now, implement two functions that compute the square and the cube root using this fixpoint function. What is the square and cube root of 5 according to your solution?

(define (fixpoint f)
  (define (close-enough? x y)
    (< (abs (- x y)) 0.001))
  (define (try guess)
    (let ((next (f guess)))
      (if (close-enough? guess next)
        next
        (try next))))
  (try 1.0))

Session 2 to be announced.

Session 3 to be announced.

Session 4 to be announced.

Session 5 to be announced.

Session 6 to be announced.

Session 7 to be announced.