Exercism in Scala 3

I was looking to improve by bash-skills and came across exercism.org, which has exercises in a veritable plethora of different languages. The emphasis seems to be on mentoring, but when I tried that I never got any response, which I didn’t find particularly surprising: why anyone would want to review other people’s crappy solutions to simple bash exercises for free is beyond me.

However it comes with a CLI and you can just try out any of the exercises in your local environment, with test scripts included. Then you can upload it back to the site, and even if you’ve got it hopelessly wrong, you can view community solutions and hopefully learn a thing or two about how to do it right.

The site just in the past couple of weeks went through a major upgrade, and theoretically allows you to do the problems and run tests right there in your own flipping browser, though it wasn’t yet working for Scala. I’m sure it will work at some point, but I don’t think it’ll be as nice to develop in as an IDE, with intelligent code completion and instant syntax and type checking.

They have nearly 100 Scala exercises with Scalatest tests, which are mostly pretty easy, but good for keeping the old skillz sharp. After doing a few I saw someone had submitted a solution in Scala 3.

Scala 3!?! Ah, so Dotty is finally on general release. After reading up a bit on the new bits and pieces (reduced need for curly braces, and significant indentation being the most obvious differences, with the implicit keyword being given the boot in most circumstances, in close second), I decided to give it a go.

So I’m just sharing some practical tips on how to get it working.

First, build.sbt needs to be updated to tell sbt that you want it to run Scala 3. So change the scalaVersion to 3.0.1 as of the time or writing.

Also, the version of Scalatest needs updating to work with Scala 3, currently 3.2.9

Then, it turns out that Scalatest in their wisdom recently decided to change the name of FunSuite to AnyFunSuite and switch all the packages around, so the test source imports and class names need updating.

Finally, if you’ve tried importing the project as a module into IntelliJ already, you’ll have a build.properties file that may specify an old version of sbt. It seems you need at least version 1.5.x in order to compile Scala 3 code, so in that case you’ll need to update the `sbt.version` specified there (1.5.5 is currently latest). In theory you can set the sbt version used from “Bundled” to a “Custom” version in IntelliJ Settings, but I found it kept switching back to “Bundled”.

So I put together a little bash script to do all this for me, which I then assigned to an alias “cs3” (Convert to Scala 3), and can run in the downloaded directory. The replacements may not be exhaustive, but work with most exercises. A few exercises come with other weird dependencies in the build.sbt file that you might need to update manually or comment out.

Here it is. Feel free to copy/paste it and use.

#!/usr/bin/env bash

# Check we're in a valid directory
if [[ $PWD =~ xercism/scala/.+ ]] ; then
    echo "directory OK"
  else
    echo "invalid directory"; exit 1
fi

# build.sbt: Replace scala and scalatest versions
perl -i -0pe 's/scalaVersion :=.*/scalaVersion := "3.0.1"/' build.sbt
perl -i -0pe 's/"scalatest" % "[^"]*"/"scalatest" % "3.2.9"/' build.sbt

# build.properties (if supplied): Replace sbt version
if [[ -a project/build.properties ]] ; then
perl -i -0pe 's/sbt\.version=.*/sbt.version=1.5.5/' project/build.properties
echo build.properties updated
fi

# test source: Change scalatest imports
filename=$(find src/test/scala/*.scala |head -1)
## FunSuite
perl -i -0pe 's/import org.scalatest.{Matchers, FunSuite}/import org.scalatest.funsuite.AnyFunSuite\nimport org.scalatest.matchers.should.Matchers/' "$filename"
perl -i -0pe 's/import org.scalatest.{FunSuite, Matchers}/import org.scalatest.funsuite.AnyFunSuite\nimport org.scalatest.matchers.should.Matchers/' "$filename"
perl -i -0pe 's/extends FunSuite/extends AnyFunSuite/' "$filename"
## FlatSpec
perl -i -0pe 's/import org.scalatest.{Matchers, FlatSpec}/import org.scalatest.flatspec.AnyFlatSpec\nimport org.scalatest.matchers.should.Matchers/' "$filename"
perl -i -0pe 's/extends FlatSpec/extends AnyFlatSpec/' "$filename"

I also made a handy script to submit the build.sbt and test files along with the solution source file, so that people on Exercism can see the changes required to run it. I aliased this to “exs” (“Exercism submit”).

#!/usr/bin/env bash

if [[ $PWD =~ xercism/scala/.+ ]] ; then
    echo "directory OK"
  else
    echo "invalid directory"; exit 1
fi

files="$(ls -d ./src/main/scala/* build.sbt ./src/test/scala/* | xargs)"

echo "files: $files"

exercism submit $files

Just paste these into files, and add an alias in ~/.bash_aliases, something like

alias exs="/mnt/c/Users/rjone/Exercism/scala/submitScala3.bash"
alias cs3="/mnt/c/Users/rjone/Exercism/scala/convertToScala3.bash"

So my workflow is this:

  1. Open my Exercism project in IntelliJ, where I have directories for bash, scala etc.
  2. If I’m using Windows, switch to WSL2 bash by typing “bash” in the terminal
  3. Download an exercise by copy-pasting the command provided on the exercise page
  4. cd to the scala/whatever-exercise folder
  5. Run cs3
  6. Fire up sbt (make sure you have version 1.5.x + on your command line), which will add the build properties
  7. If I want syntax checking, highlighting etc, click the “+” button (Link sbt Project) in the sbt Tool Window, and select the exercise folder. This will allow IntellJ to know your Scala version and to import and index your libraries.
  8. Do some coding
  9. Test using sbt test in the terminal. If you’ve done step 7, you can use IntellJ’s runner, though it had problems not running pending tests if they weren’t implemented yet (which you can get around by replacing ??? with null) – and frankly the terminal is faster and easier
  10. Submit using exs

One other IntelliJ quirk I found was that I couldn’t get the sbt tool window to appear to allow me to import a project folder: it simply wasn’t there in the tool windows menu. I think I had to go into Project Structure and make a new Scala module first as a one-off to make the tool window appear – but my mind has gone a bit hazy around this.

To be honest, though, it’s a lot simpler than it sounds!

And Scala 3 is great. Compilation is still slow, but I’m loving the new syntax.

Leave a Reply

Your email address will not be published. Required fields are marked *