NOTE: You should follow this page even if you took the Functional Programming course last semester, the workflow you’ll follow is similar but not identical!
The goal of this assignment is to familiarize yourself with the infrastructure and tools used in this class. Even though the grade in this assignment won’t influence your grade for the course, it is important that you work through this assignment carefully.
First, make sure you’ve followed the Tools Setup page.
At this point, we strongly encourage you to take the time to read at least the first three chapters of the Git Book. If you just copy-paste the commands we give you without understanding them, it’s likely that you’ll make a mistake somewhere and waste time. Git can be a huge productivity enhancer when used correctly, so it’s definitely worth the investment!
We’ll starting by cloning the repository containing all our assignment (make sure to replace GASPAR
with your EPFL username (the one with letters, not the one with number) in the following command).
git clone -b example git@gitlab.epfl.ch:lamp/student-repositories-s19/cs206-GASPAR.git cs206-example
cd cs206-example
IMPORTANT: The example
branch you just cloned contains your assignment, but is read-only on our server, you should not try to edit it.
To be able to submit your assignment you need to create your own branch to work in:
git checkout -b my-example
Now that we’ve obtained the project, let’s take a look at its structure:
.
├── assignment.sbt
├── build.sbt
├── project
│ ├── build.properties
│ ├── buildSettings.sbt
│ ├── MOOCPlugin.scala
│ ├── plugins.sbt
│ └── StudentPlugin.scala
└── src
├── main
│ └── scala
│ └── example
│ └── Lists.scala
└── test
└── scala
└── example
└── ListsSuite.scala
.sbt
or in the project/
directory are build tool configuration files: you don’t need to modify them or look at them for any of the assignmentssrc/main/scala/
src/test/scala/
. You will need to make all the tests pass to complete the assignments, and you should write additional tests to check for cases that our tests do not cover.Start sbt by running:
sbt
Once it’s finished starting (this may take a while), you’ll be able to enter sbt commands. You can compile your project using compile
and run the tests with test
. Note that if compilation fails, no tests will be run. The first time you will run test in an assignment you should see many errors: that’s normal, your job is to make the tests pass! To do this, it’s useful to understand in details what the test output means, here’s an example:
This tells us several things:
max of a few numbers
in the class ListsSuite
in the package example
scala.NotImplementedError: an implementation is missing
. This is followed by a stack trace showing where the exception happened.scala.Predef$.$qmark$qmark$qmark
in the file Predef.scala
at line 284.example.Lists$.max
example.ListsSuite.max of a few numbers
It’s now time to look at some code: the next section will show you how to start and navigate using the IDE.
This course is run with an experimental version of Scala called Dotty that will become Scala 3 in the future. Because it’s so new, most IDEs like IntelliJ and Eclipse are unlikely to work correctly with it. Thankfully we’ve developed our own IDE support. It’s designed to work with any text editor but we currently only support VSCode. If you’ve followed the Tools Setup page you should have VSCode installed by now, but don’t start it just yet, instead run the following command from sbt
:
launchIDE
This will download the Dotty extension for VSCode and set everything up. You will need to do this for every assignment, and we recommend always using this command to start the IDE.
The first time the IDE starts, it will take some time to download more components, as displayed in the bottom left:
Fixing bugs in the compiler and the IDE is much easier when we have all the information needed to reproduce them. To help us achieve that, we’ve added an optional data collection mechanism in the IDE extension, when you start an assignment, you’ll see the following pop-up:
You are free to either allow or deny the data collection, but we would appreciate it if you clicked “Allow”. If you do, you’ll contribute to making Scala better! If you change your mind, you can turn on or off the data collection at any time by clicking on the “Scala telemetry” button on the bottom-left of the IDE window:
It’s now time to dig in! Earlier we talked about a failing test, the stack trace told us that it was failing on line 83 of the file ListsSuite.scala, so let’s open that file:
Here’s the source code of the test method:
This looks like a regular method except for a few things:
@Test
, this is an annotation that lets JUnit (the testing framework we use) know that this is a test method.max of a few numbers failed
is easier to read than maxOfAFewNumbers failed
, but this is just a convention: if you define your own tests you’re free to name them however you want.Recall that the second line of the stack trace was:
at example.Lists$.max(Lists.scala:41)
This tells us that the crash happened when calling max
, we can hover with our mouse over the call to max
in the test method to get more information on it:
The hover is split into two parts: the first part is:
(xs: List[Int]): Int
This means that max
is a method that takes a List
of Int
as argument and returns an Int
. The second part is the documentation of max
. We can jump to the definition of max by Ctrl+click
(Cmd+click
on Mac) or by right click -> Go to Definition
. Once there we see:
Now we know why the test failed: max
calls ???
, which is a method defined in the Scala standard library that simply crashes your program: whenever you see it in an assignment it means that this is something you need to replace by your own implementation.
There’s one mystery left, the first line of the stack trace was:
at scala.Predef$.$qmark$qmark$qmark(Predef.scala:284)
But what do all these dollars mean? It’s not because we’re mining crypto-currencies on your computer: it turns out that when Scala code is compiled to Java bytecode, some names need to be translated to be valid. In particular, ?
is translated to $qmark
, and object Predef
is translated to Predef$
, so all this is saying is that the crash occurred when running the method ???
defined in the object Predef
in the package scala
, as expected.
You now know enough to be able to work with the IDE, here are some additional tips:
While working on your assignment, you will regularly want to go back to the sbt console to run the tests. You could simply run the command test
every time, but you can take advantage of the watch mode instead: if a command is prefixed by ~
, sbt will watch the source directory for changes and re-run the command every time a file is saved. So a possible workflow is:
launchIDE
~test
(or run ~compile
if you don’t want to look at the tests)Writing code and running tests is nice, but sometimes more direct feedback is useful, like when you want to experiment with Scala, or try out some methods that you implemented. You can do this using the Scala REPL (Read/Eval/Print Loop) or with a worksheet.
After having started sbt, you can start the REPL by typing console
, you will see the following prompt:
scala>
At this point you can write any Scala expression you want, for example:
scala> val l = List(3,7,2)
val l: List[Int] = List(3, 7, 2)
(If you write an expression without wrapping it in a val
or a def
, the REPL will give it a name for you, starting with res
)
scala> l.isEmpty
val res0: Boolean = false
scala> println(res0)
false
scala> l.tail.head
res1: Int = 7
scala> List().isEmpty
res2: Boolean = true
The classes of the assignment are available inside the REPL, so you can for instance import all the methods from object Lists
and start using max
:
scala> import example.Lists._
import example.Lists._
scala> max(List(1,3,2))
res1: Int = 3
In order to exit the Scala REPL and go back to sbt, type Ctrl+D
.
A worksheet is a file where every line of code written in the IDE is executed and its output displayed as a comment.
Any file that ends in .sc
is considered to be a worksheet by the IDE. Once VSCode is launched in a project, all you have to do is create a new file and save it (Ctrl+N, Ctrl+S
) using any name as long as it ends in .sc
.
Inside this file, you can type any line of code you would type in the REPL. To run the worksheet, either press the “Run this worksheet” button at the top of the file, or save the file. Each line of code will be executed one by one and its output is shown in green on the right. If your code contains an infinite loop, the worksheet will never finish running by itself, but you can cancel it by clicking the same button used to run the worksheet at the top of the file.
IMPORTANT: When you run a worksheet, you should have sbt open and either ~test
or ~compile
running as recommended in Part 3, otherwise changes to other files won’t be reflected in the output of your worksheet.