example-lab.md 11.9 KB
Newer Older
Olivier Blanvillain's avatar
Olivier Blanvillain committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# Example lab

The goal of this lab is to familiarize yourself with the infrastructure and tools used in this class. Even though the grade in this lab won't influence your grade for the course, it is important that you work through this lab carefully.

## Part 1: Obtaining the Project Files

First, make sure you've followed the [Tools Setup](tools-setup.md) page.

**At this point, we strongly encourage you to take the time to read at least the first three chapters of the [Git Book](https://git-scm.com/book/en/v2). 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 lab (make
sure to replace `GASPAR` with your EPFL username (the one with letters, not the
one with number) in the following command).

```shell
16
git clone -b example git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-example
Olivier Blanvillain's avatar
Olivier Blanvillain committed
17 18
```

Guillaume Martres's avatar
Guillaume Martres committed
19
**If this command fails, make sure you've [logged into
20
gitlab](https://gitlab.epfl.ch/users/sign_in) and [registered in this table](https://docs.google.com/spreadsheets/d/12KvfD_jN5AcApmWhCz7xZmln48fctQOa984RPWrqRkY/edit#gid=0),
21 22 23
then wait a few minutes.
If it still doesn't work it's likely that you didn't correctly upload your ssh
key to gitlab, look at the last part of the [Tools Setup](tools-setup.md) page again.**
Guillaume Martres's avatar
Guillaume Martres committed
24

Olivier Blanvillain's avatar
Olivier Blanvillain committed
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
```shell
cd cs210-example
```

Now that we've obtained the project, let's take a look at its structure:

```shell
.
├── build.sbt
├── project
│   ├── ...
└── src
    ├── main
    │   └── scala
    │       └── example
    │           └── Lists.scala
    └── test
        └── scala
            └── example
                └── ListsSuite.scala
```

- All the files ending with `.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 labs
- The project sources are in `src/main/scala/`
- The sources of the unit tests are in `src/test/scala/`. You will need to make all the tests pass to complete the labs, and you should write additional tests to check for cases that our tests do not cover.

## Part 2: Using sbt

Start sbt by running:
```shell
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` (this automatically compiles your code if needed to). Note that if
compilation fails, no tests will be run. The first time you'll run `test` in an
lab you should see many errors: that's normal, your job is to make the
63
tests pass! But first, let's look at a failed test in detail:
Olivier Blanvillain's avatar
Olivier Blanvillain committed
64 65 66 67 68

![](images/sbt-test-error.png)

This tells us several things:

69 70 71 72 73 74 75 76 77 78
- There's a test named `sum of a few numbers (10pts)` in the class `ListsSuite` in the package `example`
- The test failed (that's why it's in red and starts with `==> X`) with an exception: `NotImplementedError`.
- This exception was thrown from the method `???` in `scala.Predef` in the file
  `Predef.scala`, this file is not part of our project (that's why it's in
  grey), to find the actual error in our code we have to look at where this
  method was called from.
- This method was called from method `max` in `example.Lists` in the file
  `Lists.scala` at line 40, this is where the bug is!
- It's also important to see where in our test this was called from, here
  it's line 102 of `ListsSuite.scala`.
Olivier Blanvillain's avatar
Olivier Blanvillain committed
79

80
Time to go fix that bug! The next section will show you how to do that using the IDE.
Olivier Blanvillain's avatar
Olivier Blanvillain committed
81 82 83

## Part 3: Using the IDE

84 85 86 87 88 89 90 91
### Setup

Let's upgrade the IDE support first, close VSCode if it's open and run:

```shell
code --force --install-extension scalameta.metals
```

Olivier Blanvillain's avatar
Olivier Blanvillain committed
92 93
### Startup

94 95 96 97
To start Code, run the following in the project directory (the same directory where you
previously ran `sbt`), it's important to run Code in the correct directory or
it won't be able to import your project:

Olivier Blanvillain's avatar
Olivier Blanvillain committed
98
```shell
99
code .
Olivier Blanvillain's avatar
Olivier Blanvillain committed
100 101
```

102 103 104
(In this command the `.` is important, it's how we tell Code to run in the
current directory)

Guillaume Martres's avatar
Guillaume Martres committed
105 106 107
(if you see an error `Expected ';'` it means you're inside sbt, open a new
terminal in the same directory)

108 109 110
The first time the IDE starts, it will take some time to download more
components, eventually it will ask you to import the build, please click "Import
build":
Olivier Blanvillain's avatar
Olivier Blanvillain committed
111

112
![](images/metals-import.png)
Olivier Blanvillain's avatar
Olivier Blanvillain committed
113

114 115
You'll need to wait a bit for the import to finish, if an error appears try
closing and restarting Code in the same way we started it above.
Olivier Blanvillain's avatar
Olivier Blanvillain committed
116 117
### Usage

118 119
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 102 of the file `ListsSuite.scala`, so let's open that file:
Olivier Blanvillain's avatar
Olivier Blanvillain committed
120 121 122

![](images/open-test.png)

123
Here's the source code of the test:
Olivier Blanvillain's avatar
Olivier Blanvillain committed
124 125 126

![](images/test-source.png)

127 128 129 130
The first line gives a name to the test, the second line runs
`sum(List(1, 2, 0))` and tests that it equals 3, but in our case we never got to
this point because an exception was thrown, recall that the second line
of the stack trace was:
Olivier Blanvillain's avatar
Olivier Blanvillain committed
131 132

```scala
133
at example.Lists$.sum(Lists.scala:25)
Olivier Blanvillain's avatar
Olivier Blanvillain committed
134 135
```

136
This tells us that the crash happened when calling `sum`, we can hover with our mouse over the call to `sum` in the test method to get more information on it:
Olivier Blanvillain's avatar
Olivier Blanvillain committed
137 138 139

![](images/hover.png)

Guillaume Martres's avatar
Guillaume Martres committed
140
**If hovering doesn't show this see the [Troubleshooting](#troubleshooting) section.**
Olivier Blanvillain's avatar
Olivier Blanvillain committed
141 142 143

The hover is split into two parts: the first part is:
```scala
144
def sum(xs: List[Int]): Int
Olivier Blanvillain's avatar
Olivier Blanvillain committed
145
```
146 147 148 149
This means that `sum` is a method that takes a `List` of `Int` as argument and
returns an `Int`. The second part is the documentation of `sum`. We can jump to
the definition of sum by `Ctrl+click` (`Cmd+click` on Mac) or by `right click ->
Go to Definition`. Once there we see:
Olivier Blanvillain's avatar
Olivier Blanvillain committed
150

151
![](images/sum-def.png)
Olivier Blanvillain's avatar
Olivier Blanvillain committed
152

153 154
Now we know why the test failed: `sum` calls `???`, which is a method defined in
the Scala standard library that simply crashes your program: whenever you see it
155 156 157 158 159 160 161
in a lab it means that this is something you need to replace by your own
implementation.

Once you've implemented this method, you can run `test` from sbt again to see if
the test passed, if you want to run a single test instead of all tests you can
use `testOnly` instead and specify part of the name of the test:
```scala
Guillaume Martres's avatar
Guillaume Martres committed
162
testOnly -- "--tests=.*max of a few.*"
163
```
Olivier Blanvillain's avatar
Olivier Blanvillain committed
164 165 166 167 168 169

You now know enough to be able to work with the IDE, here are some additional tips:

- When you press `Enter` to make a new line, the IDE will automatically indent the
  line if needed (for example, if the last word on the previous line was
  `then`), however it will never unindent code for you (for example, when
170 171
  writing `else`). You can indent code manually by pressing `Tab` and
  unindent it by pressing `Backspace` or `Shift + Tab`.
Olivier Blanvillain's avatar
Olivier Blanvillain committed
172
- When working on an lab,  you are free to create as many methods, classes and objects as you want. **But you shouldn't change the name of existing methods, classes and objects, because that may break the automated grading system, this is important!**.
173
- You can see a list of all warnings and errors reported by the compiler by clicking on ![](images/warnings-errors.png) at the bottom left of Code.
Olivier Blanvillain's avatar
Olivier Blanvillain committed
174
- The IDE can show you on hover the documentation of classes, defs and vals defined in the current project but support for external project is currently missing. To compensate for this, you can consult the documentation online:
175 176 177
  - The documentation for the Scala standard library is at [https://www.scala-lang.org/files/archive/api/2.13.3/](https://www.scala-lang.org/files/archive/api/2.13.3/)
  - The documentation for the Java standard library is at [https://docs.oracle.com/en/java/javase/15/docs/api/index.html](https://docs.oracle.com/en/java/javase/15/docs/api/index.html)
- You can customize Code as much as you want, including installing additional extensions, but please avoid installing other Scala-related extensions: they may conflict with the one we use for this course.
Olivier Blanvillain's avatar
Olivier Blanvillain committed
178 179
- While working on your lab, 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:

180 181 182 183
    1. Start the IDE
    2. Start sbt in the terminal (protip: you can start a terminal inside Code from the
       menu: `Terminal -> New Terminal`)
    3. Inside sbt, run `~test`
Olivier Blanvillain's avatar
Olivier Blanvillain committed
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
    4. Work in the IDE, and check the output of the sbt console from time to time

## Part 4: Running your code

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.

### The REPL
After having started sbt, you can start the REPL by typing `console`, you will see the following prompt:
```scala
scala>
```
At this point you can write any Scala expression you want, for example:
```scala
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
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 lab are available inside the REPL, so you can for instance import all the methods from `object Lists` and start using `max`:

```scala
scala> import example.Lists._
import example.Lists._

scala> max(List(1,3,2))
res1: Int = 3
```

227
You can enter a multiline expression in the REPL by using `Alt+Enter` instead of `Enter`:
Olivier Blanvillain's avatar
Olivier Blanvillain committed
228 229 230 231 232 233 234 235 236

```scala
scala> if 1 == 1 then
     |   "a"
     | else
     |   "b"
val res0: String = a
```

237 238 239 240
(on macOS, first go to `Terminal -> Preference -> Profiles -> Keyboard` and then
select `Use Option as Meta key`, then `Option+Enter` will work for multiline
expressions.)

Olivier Blanvillain's avatar
Olivier Blanvillain committed
241 242 243 244 245 246
In order to exit the Scala REPL and go back to sbt, type `Ctrl+D`.

### The worksheet mode
A *worksheet* is a file where every line of code written in the IDE is executed and its output displayed as a comment.

#### Creating a worksheet
247
Any file that ends in `.worksheet.sc` is considered to be a worksheet by the IDE. Once Code 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 `.worksheet.sc`.
Olivier Blanvillain's avatar
Olivier Blanvillain committed
248 249 250

#### Using the worksheet mode

251 252 253 254
Inside this file, you can type any line of code you would type in the REPL. The
worksheet will be automatically run when the code is saved and auto-save is
enabled by default. Each line of code will be executed one by one and its output
will be shown in green on the right.
Olivier Blanvillain's avatar
Olivier Blanvillain committed
255 256 257 258

## Part 5: Submitting your Solution

[Click here to learn how to submit your lab.](grading-and-submission.md)
259 260 261

# Troubleshooting

262 263 264 265 266 267 268 269 270 271 272 273 274
## sbt fails to start

If you see any kind of error when sbt starts that prevents you from using it,
try cleaning the project cache by running:
```shell
git clean -Xdf
```
Then restarting `sbt`, if this still doesn't work, try deleting the global sbt
cache:
```shell
rm -r ~/.sbt
```

275 276 277 278 279 280 281 282 283 284 285 286 287
## IDE features like type-on-hover or go-to-definition do not work

It's likely that the build wasn't imported, we can import it manually:

Click on the "m" logo in the left bar (where the red arrow is in the screenshot below):

![](images/menu-metals.png)

In the sidebar that appears, click on "Import build", then wait a bit:

![](images/import-build.png)

If things still don't work, try restarting Code (launch it in the same way you
288 289 290
started it before, using `code .` from the project directory). If you're still
having issues, try clicking on "Clean compile workspace" from the same
sidebar.
291

292 293 294 295 296
## Warning about Bloop installed version

If you get a warning like this:

![](images/bloop-update.png)
Guillaume Martres's avatar
Guillaume Martres committed
297 298

Please click the first button "Turn off old server".