A Scala “functional programming style” To-Do List application

Back when I was writing Functional Programming, Simplified I started to write a little Scala/FP “To-Do List” application that you can run from the command line, based on a similar application in the Learn You A Haskell For Great Good book. For reasons I don’t remember, I decided not to include it in the book, and forgot about it until I started using GraalVM (“Graal”) recently.

Graal includes a native image feature lets you compile JVM classes and JAR files into native executables, so as I thought about things I can make faster, I was reminded of the To-Do List app and thought about how cool it would be if it started instantaneously. So I found the old project, blew the dust off of it (updated all of its dependencies), and made a few additions so I could create (a) a single, executable JAR file with sbt-assembly, and (b) a native executable with Graal.

Because I wrote the application for my book, I wrote the code using Scala in a functional programming (FP) style. If you read the book, the code should look very familiar, with the main exception being that I use some tools from the scalaz project. (It looks like I also have another version that I wrote with Cats.)

UPDATE: For an improved version of this code, see my newer article, A Scala functional programming style To-Do List written with Cats and Cats-Effect.

This post is sponsored by my new book,
Learn Functional Programming Without Fear.

How the application works

As mentioned, this is a command-line To-Do List application, and here’s a short demonstration of how it, starting with the v command (which stands for “view”) to show that there’s nothing in the initial list, followed by some add commands and a rm command:

> ./todo 
Command ('h' for help, 'q' to quit)
==> v


Command ('h' for help, 'q' to quit)
==> add wake up
1. wake up

Command ('h' for help, 'q' to quit)
==> add make coffee
1. wake up
2. make coffee

Command ('h' for help, 'q' to quit)
==> add go to work
1. wake up
2. make coffee
3. go to work

Command ('h' for help, 'q' to quit)
==> rm 3
1. wake up
2. make coffee

Command ('h' for help, 'q' to quit)
==> h

Possible commands
-----------------
add <task>       - add a to-do item
h                - show this help text
rm [task number] - remove a task by its number
v                - view the list of tasks
q                - quit

The Scala/FP code

If you’re interested in functional programming with Scala, the source code is available at this URL:

Here’s a short overview of how the code works:

  • ToDoListFIO extends App is where the action starts.
  • As its name implies, mainLoop is the application’s main loop. It runs until you enter q.
  • This line of code in the loop converts the user’s input into a Command: scala cmd <- getLine.map(Command.parse _)
  • Commands are then processed in the processCommand method.

Something new you’ll see in the code (compared to my book) is a call to Scalaz’s unsafePerformIO function. As one person wrote, that is an “Intentionally verbose and scary name to make you think twice about where you perform your side effects.”

Scalaz’s unsafePerformIO

For a little more background, the Scaladoc for unsafePerformIO states:

Runs I/O and performs side-effects. An unsafe operation. Do not call until the end of the universe.

Another way to state that is that with Scalaz you write all of your I/O code using its IO monad, and then make a single call to unsafePerformIO when you’re ready to trigger the execution of your application. In fact, if you don’t call unsafePerformIO, your application won’t do anything. (Side effects are a very big deal in functional programming, hence this scary method name.)

For more information about it, if you search this Eric Torreborre page for unsafePerformIO, you’ll find quite a few comments about it. The first part of this page also shows a short example of how it triggers the execution of a very small piece of code. I also show a short example of it in this A Scalaz putStrLn “Hello, world” IO Monad example.

In functional programming, side effects are kind of a big deal

Monday morning update: I woke up during the night and remembered that the reason I never posted this code before is that it has too many calls to unsafePerformIO, and I meant to dig more into Scalaz to learn how to improve the code. I have to travel a lot early this week, but I’ll try to post an improved version of the code by next weekend.

Hopefully the rest makes sense

If you read my FP book, hopefully the rest of the code will make sense. All of the I/O functions use an IO monad, and the rest of the code consists of pure functions.

Two bugs (oops)

Right as I was getting ready to go to press tonight I noticed that the code has two bugs.

First, if the todo.dat file doesn’t exist, the “view” command will throw an exception. (You can create an empty initial file to avoid that bug, or fix the code.)

Second, I noticed that I hadn’t fixed a bug related to the “remove” process. If you type in something like this:

rm foo

instead of this:

rm 1

the application will blow up. The remove function assumes that it receives an Int, but I don’t do anything to validate the user input.

I was going to fix these bugs, but I’m short on time, so I thought I’d leave them as an exercise for the interested reader. (My apologies that I’m a little rushed tonight.)

Creating a single, executable JAR file

To create a single, executable JAR file, use the sbt assembly command, or use the assembly command at the SBT prompt. That command should “just work” for you, but if you need more information, I wrote this sbt-assembly tutorial as part of the Scala Cookbook.

GraalVM

As mentioned, I got back into this project because of Graal. Over the last few weeks I’ve been updating some of my JVM-based shell scripts to use Graal so they’ll start faster, and for however my brain works, it triggered a, “Hey, you wrote a To-Do List app a few years ago” thought. Indeed, using Graal, the app starts up immediately after you type todo.

If you haven’t used Graal yet it takes a little work to set it up initially. Here’s a very short description of what it takes to create a native executable with Graal for this project:

  • Install GraalVM on your system
  • Configure your JAVA_HOME and PATH environment variables to use Graal
  • cd into this project’s Graal directory
  • In my case I don’t use Graal all the time, so I open a new MacOS Terminal tab where I only use Graal, then source the 1setup_graal file to set the necessary GraalVM parameters (i.e., . 1setup_graal)
  • After I run sbt-assembly, I then run the 2compile_graal.sh script to create the todo native image (executable)

While the app starts pretty fast with the java-jar command, it starts instantly when you create the Graal native image, and that’s a really cool feeling, especially if you’ve been sadly used to that initial Java/JVM startup lag time for 20 years.

Summary

In summary, if you wanted to see how to write a small but complete functional programming application in Scala — or if you just wanted a command-line To-Do List application — I hope this source code and project is helpful.

Finally, as a bit of self-promotion, if that code is hard to understand, please see my Functional Programming, Simplified book. About 40% of the book is available as a free preview, so hopefully you can get a good feel about whether or not you want to buy the book from that preview.

All the best,
Al