In this article, we’ll work through some basic programming examples from the legendary “Structure and Interpretation of Computer Programs” (SICP) book. You can run these examples, including modified versions, in your browser using Scastie. We won’t digress on the details of any single example and instead, we’ll explore a range of examples so you can start to see the patterns for yourself. Small exercises are included to help you learn Scala. We’ll again use Scastie for testing out the code we write in exercises.

Hello World

Before diving into SICP, let’s cover the time-honored tradition of showing a Hello World program, which simply prints “Hello World” as output.

We’re simply using the “print line” function. You can copy this code into Scastie to test this out.

Math Expressions

SICP starts by considering some example math expressions.

The format of these math expressions is rather intuitive. Also, if you’ve worked with other programming languages, then you may find the math syntax identical to other languages such as Python, Java, C#, C, and Javascript.

Note that the lines starting with > are not Scala code. I just added those lines to show us the results of each expression.

As an exercise, how would you multiply the numbers 7, 3, and 5 in Scala? Try out your code in your browser using Scastie.

Variables

In Scala, we can create a variable and assign it a value as follows.

Variables can be reassigned.

Variables are useful because they allow us to save the results of computation for reuse. They’re particularly helpful when we want to use the value of an expression in multiple places.

Vals (i.e., constant variables)

In general, Scala encourages us to avoid reassigning variables as that can make programs more complicated. Instead, Scala encourages the use of val variables, which cannot be reassigned.

We should use val in place of var whenever possible to keep our code simple and easy to reason about. Working with Scala will teach us patterns to avoid variable reassignment.

Functions

We’ll commonly want to define computation that can be reused. For that, we use functions. Functions take input parameters and compute a resulting value. E.g.,

The big thing to note in the function definition (i.e., def ) is that we have to specify the types for both function parameters and the return value of the function. In this case, the function takes a single integer parameter, x , and returns an integer.

Functions can take more than one input parameter.

In the previous two examples, the function just consisted of a single expression. We can have more complicated functions with multiple statements, including defining local variables.

Brackets are used to group together these multiple statements. Note, that the function evaluates to the value of the last expression and there’s no need for an explicit return statement as in some other programming languages. This example also introduces a new type, Double , that is used to represent numbers with decimal points; in math terms, real numbers.

Function parameters don’t have to be limited to numeric types and can take any data type. For instance, there is also the String type, which consists of text; i.e., a string of characters. Further, functions don’t have to evaluate to a usable value and these functions are declared with Unit return types.

How would you write a function that takes two integers, defines a val that is the sum of the two integers, and then print that value? Here’s a template.

Does your code run in Scastie?

Conditionals

Scala supports if expressions to conditionally evaluate expressions. Unlike more procedural languages where if is a statement (i.e., code that doesn’t evaluate to a value), the Scala if is an expression that evaluates to a value.

Just like functions, you can have a conditional expression that combines multiple statements (e.g., assigning a val ) and expressions. Same as functions, brackets are used to create such a compound expression and it evaluates to the value of the last expression.

Scala if expressions can be used to conditionally execute statements with side effects; e.g., printing a value. Note, a side effect is anything that happens outside of our code evaluating to a value, including printing output.

In this example, there is no else clause.

Can you modify the function to be called printClassification that prints both large and small numbers, with a suffix that says either “is large enough” or “is too small”?

Conditionals can be nested as shown in the following example for SICP abs function for computing the absolute value of an integer.

Recursive Functions

Sometimes we just want to repeat something in code. For example, printing something out n times or summing the integers from a to b. Historically, many programming languages used something called loops to repeat code. This coding practice is called procedural or imperative coding and was the dominant trend in mainstream programming languages until recently.

In contrast, a common pattern in functional programming languages, including Scala, consists of using function recursion in place of looping. I.e., functions that call themselves. We can see how this is applied in Scala with the classic factorial example.

This example also introduces the concept of throw ing exceptions. We won’t cover the details yet. Just know it’s a way for our code to handle erroneous situations like passing an invalid input to a function.

Can you write a function called sumUpTo(x: Int) that uses recursion to sum all integers from zero up to x (inclusive)?

Again, you can test your solution in Scastie.

An aside on basic pattern matching

I’d like to take a moment to show how the Scala match construct can be used to implement the conditional logic of the factorial function.

Here we’re using the match construct to evaluate different logic based upon the value of x . Further, you can see we’re not explicitly handling the negative value case. Instead, negative inputs result in throwing a MatchError because none of the defined case statements match that input. Also, note how we introduced the val xp that is only operated on when its value is positive.

This is a basic usage of match and it can do much more powerful things. We’ll consider more advanced usage of match in future articles.

Higher Order Functions

As the last part of this introduction to Scala, let’s explore higher-order functions. These are functions that take other functions as arguments. Consider the following example where we want to call a function, func , exactly n times using a function callFunctionNTimes .

You can see that the func argument of callFunctionNTimes is defined as (String) => Unit . This means that func is a function that takes a single String argument and has no return value. We can pass in any function that takes this form, including both println and printTwice.

Can you write a higher-order function of the form: callForIntegersInRange(func: (Int) => Unit, start: Int, end: Int): Unit

Here’s a template.

Again, you can test your solution in Scastie.

Aside: Is it interesting that we can treat println as both a (String) => Unit function and a (Int) => Unit function? We’ll explore how Scala allows us to do this later in this series when we explore a concept called generic types. The short answer is that println is defined as a function of type (Any) => Unit and both String and Int can be treated as Any type.

Closing Remarks

Thank you for exploring Scala with me! I hope you’ve enjoyed learning a bit about Scala and are excited to learn more. If any parts have been confusing, please let me know and I’ll revise those parts. Further, if there are parts you really liked, let me know and I’ll try to preserve that style in the future. Let me know what you think at matthew.hagy@gmail.com.

When you’re ready to continue on, the next installment in our series is A brief tour of lists in Scala and algorithmically processing them in SICP exercises.