Data, Values, and Operators

Data, Values, and Operators

This post is meant to follow the Landing page project in The Odin Project. Please follow The Odin Project up to that point and return here if you need to.

Otherwise, let's dive right in to Scala!

Learning Outcomes

Look through these now and then use them to test yourself after doing the assignment:

  • How do you define a value?
  • What are the rules for naming values?
  • What are operators, operands, and operations?
  • What is concatenation and what happens when you add numbers and strings together?
  • What are operator precedence values?
  • What are assignment operators?

How to Run Scala Code

For now, you'll be running Scala via the Scala CLI tool developed by VirtusLab. Later lessons in Foundations and the Scala path will show you how to run Scala in the browser and on the JVM using mill. Outside of these lessons, for now you should always default to running your Scala code via Scala CLI unless otherwise specified. Otherwise you may run into unexpected errors.

Installing the VirtusLab Scala CLI tool is relatively easy. All you need to do is run the following two commands in the CLI:

curl -sSLf https://virtuslab.github.io/scala-cli-packages/scala-setup.sh | sh
source ~/.profile

Once you've completed this step, you're now able to run Scala code in three different ways:

  • The Scala console
  • Compiling and running a Scala file
  • Compiling to Javascript with ScalaJS

Scala console

To enter the scala console you can run scala-cli console. You can run hello world by entering the following:

scala> "Hello, World!"

You should see the output of this command in the line below when you press enter.

In order to exit the Scala console, write :q and press enter.

The Scala console is the quickest and easiest way to run and test Scala code. You will find yourself using it to test your code even when you're an experienced programmer!

Unless otherwise noted, please try to run the examples in these articles in the Scala console. Experimenting with Scala will help you better understand the language!

Compiling and running a Scala file

This approach is much closer to what you'll be doing when you're writing actual programs in Scala. Your programs will be composed of one or many .scala files with an entrypoint that tells the compiler where your program should start from.

The most simple Scala program to run via this method is "Hello, World!", a program that outputs the text "Hello, World!" upon execution. To create and run this program, follow these steps in VSCode:

  1. Create a file named HelloWorld.scala in a folder of your choosing
  2. Write the line @main def program = println("Hello, World!") inside the file
  3. Save the file
  4. In the menubar, navigate to View > Terminal to access the internal vscode terminal
  5. Type scala-cli run HelloWorld.scala into the terminal and press enter

Your terminal should show some work done, followed by the line of text Hello, World!. Congratulations, you've just run your first Scala program!

One difference between the Scala console and a proper Scala program to keep in mind is that the Scala console will give you immediate feedback about every line you enter into it, while a proper Scala program will only output text if you use println.

Compiling to Javascript with ScalaJS

You can also run hello world by compiling a hello world scala program to javascript, and linking it into a basic HTML skeleton. In order to do this, we can recompile the previously created HelloWorld.scala into javascript:

  1. Create a basic HTML skeleton with the name index.html
  2. Add <script src="HelloWorld.js"></script> into the <head> section of your HTML
  3. Run scala-cli package HelloWorld.scala --js.
  4. Open index.html with your web browser
  5. Open the Developer console to see the message (F12 on Chrome, Ctrl+Shift+I on Firefox)

This process is something you'll be using for your webpage development with Scala. This form of Scala is called ScalaJS.

Now that we've gone over how to run Scala code, lets look at how to write it!

Numbers

Numbers are one of the basic building blocks of programming logic. They're so important that it's hard to think of any useful programming task that doesn't use numbers... so knowing how numbers work is quite important.

In Scala there are two main groups of numbers, whole numbers and fractional numbers. In Scala, the numerals 4 and 7 are whole, while the numerals 4d, 4.0, and 4.5 are fractional.

If you enter 4 into your Scala console, you should get a response from Scala right underneath

scala> 4
val res0: Int = 4

This val res0: Int = 4 underneath indicates the result of 4 in your console. Right now, you do not need to worry about what val res0: means. The Int here means that Scala interpreted your number as whole, and the = 4 means that the number was 4.

If you try entering 4d in your console, you'll get a different result:

scala> 4d
val res0: Double = 4.0

Here it says Double, which means it interpreted your number as a fractional number, and it wrote = 4.0. Unlike before, this is not exactly what you wrote. Instead, it's the equivalent of what you wrote, 4d in Scala is the same as writing 4.0.

Strings

Strings are the representation of textual data in Scala. They are used to output sentences to users and to receive text data like passwords, usernames, and email addresses in your program. "Hello World", "John", and "Welcome!" are examples of Strings in Scala.

You'll notice that a String begins with a " and ends with a ". These quotes tell your Scala program that you're entering textual data, and if you forget them you're likely to have the Scala compiler complaining and giving you errors like:

scala> Hello, World!
-- Error: ----------------------------------------------------------
1 |Hello, World!
  |     ^
  |     end of statement expected but ',' found

So try to remember your quotes.

Quotes inside Strings

When you write textual data in Scala, the end of the data is marked by a second " symbol. If you're wanting to use this double quote in your textual data, you'll quickly run into the issue that scala isn't sure what is and isn't a String anymore:

scala> "He told me he was "quoting his professor verbatim"..."
-- [E008] Not Found Error: -----------------------------------------------------
1 |"He told me he was "quoting his professor verbatim"..."
  |^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |value quoting is not a member of String
-- [E006] Not Found Error: -----------------------------------------------------
1 |"He told me he was "quoting his professor verbatim"..."
  |                            ^^^
  |                            Not found: his

If you're having this problem, you can get around it by using triple quotes """ instead:

"""He told me he was "quoting his professor verbatim"..."""

Triple quotes work similarly to normal quotes, except that you can use the double quotes symbol " inside your String without Scala getting confused.

Operators

When you were in school, you may remember your teacher going to the blackboard and writing 1 + 2 and asking you and your peers to tell you what the answer was. When your teacher did this, she was giving you two pieces of data, 1 and 2, and commanding you to add them together.

Adding is an operation in programming terms, and the + symbol is an operator. Operators take one or more pieces of data (called operands) and perform an operation on them. You'll be hardly surprised that if you write the above equation into your Scala console, you'll get a response from Scala:

scala> 1 + 2
val res0: Int = 3

As before, the result of what you entered is shown in the line before, but now that you're using operators, the result data is no longer the same as the data you entered. The two numbers were added together, much like your teacher wanted you to do back in school.

There are a number of different operators that act on different data in Scala. The arithmetic operators for numbers are as follows:

OperatorDescription
+Addition
-Subtraction
*Multiplication
/Division
%Modulus

These operators are what is known as binary operators. They take two pieces of number data, and perform an operation on them. Here's some quick examples of the operations in action:

Adding

The addition operator (+) adds numbers:

scala> 5 + 2
val res0: Int = 7

Subtracting

The subtraction operator(-) subtracts numbers.

scala> 5 - 2
val res0: Int = 3

Multiplying

The multiplication operator (*) multiplies numbers

scala> 5*2
val res0: Int = 10

Remainder

The modulus operator (%) returns the division remainder.

scala> 5%2
val res0: Int = 1

Division

The division operator (/) behaves oddly compared to the other operators. It behaves differently depending on if you use whole numbers or fractional numbers with it.

scala> 5/2
val res0: Int = 2

scala> 5d/2
val res1: Double = 2.5

When dividing whole numbers, Scala will return a whole number to you. If you want a fractional number, one of the numbers you pass to the division operator will need to be fractional, like in the second input above.

Strings and operators

The + operator and * operators exist for Strings as well as numbers, but their meanings are quite different. + for numbers means addition, but + for Strings means concatenation. What is the difference? Let's look at the addition operator one more time in a bit more depth:

scala> 1 + 2
val res0: Int = 3

scala> 2 + 1
val res1: Int = 3

As you can see, we can swap the data around when using the addition operator, but we still get the same result: 3. This is called commutativity.

Unlike addition, concatenation is not commutative; it glues two strings together in the order you pass them in:

scala> "Hello," + " World!"
val res0: String = Hello, World!

scala> " World!" + "Hello,"
val res1: String = " World!Hello,"

The concatenation operator can be used with two Strings, or a String and a number.

The * operator for Strings is repeat. It takes a number as its second input, and repeats a String the number of times requested.

scala> "Repeat me twice" * 2
val res0: String = Repeat me twiceRepeat me twice

This operator is quite finnicky, and requires that the first input be a String and the second be a number. Reversing the data will result in an error:

scala> 3 * "hello"
-- [E134] Type Error: ----------------------------------------------------------
1 |3 * "hello"
  |^^^
  |None of the overloaded alternatives of method * in class Int with types
  | (x: Double): Double
  | (x: Float): Float
  | (x: Long): Long
  | (x: Int): Int
  | (x: Char): Int
  | (x: Short): Int
  | (x: Byte): Int
  |match arguments (("hello" : String))
1 error found

Operator Precedence

Operators Precedence is the order in which operators will be evaluated in Scala. You may already be familiar with the concept of operator precedence from school, in the form of PEMDAS (parentheses, exponents, multiplication, division, addition, subtraction).

While relying on operator precedence to write code is generally bad form, having some knowledge of it can be helpful, so please read this article to understand operator precedence in Scala a bit better: geeksforgeeks.org/operators-precedence-in-s..

Values

You can think of values as simply "storage containers" for numbers and text in your code. Values are created in Scala using something called the val keyword.

scala> val name = "john"
val name: String = john

The string is now saved into the memory area associated with the value. We can access it using the value name:

scala> val name = "john"
val name: String = john

scala> name
val res0: String = john

scala> "Hello " + name + "!"
val res1: String = Hello john!

Values can always be used wherever data is needed in Scala. In fact, when you see a value, you can imagine that it is just a stand-in for the data that defines it.

scala> val a = 5
val a: Int = 5

scala> a + 5
val res0: Int = 10

scala> 5 + 5
val res1: Int = 10

scala> println(a)
5

scala> println(5)
5

scala> val b = a
val b: Int = 5

A real-life analogy

We can easily grasp the concept of a "value" if we imagine it as a "box" for data, with a uniquely-named sticker on it. For instance the value name can be imagined as a box labeled "name" with the data "john" in it.

We can put any data in the box.

Values and results from the Scala console

You may have noticed that the results of the Scala console look suspiciously like the creation of a value.

val name = "john"

val res0: Int = 3

When you were entering commands into the Scala console, it wasn't just giving you an answer back. It was creating a value with your result stored inside. You can test this like so:

scala> 4+2
val res0: Int = 6

scala> res0*2
val res1: Int = 12

The = operator

= is an operator in Scala just like + and -, but it has quiet a different meaning compared to the standard arithmetic definition. = is the assignment operator, and is used for defining things. In the above examples, it's used to define a value with some data.

Value naming

There are a few limitations on variable names in Scala:

  1. The first character must not be a digit
  2. The name may not contain special characters like ,,., ;
  3. The name cannot be a keyword

Examples of valid names are:

val userName = "donald"
val test123 = 3.2

When the name contains multiple words, camelCase is commonly used. That is: words go one after another, each word except starting with a capitalLetter: myVeryLongName.

Case matters

Values named apple and AppLE are two different values.

It is possible to use any language, including cyrillic letters or even hieroglyphs, like this:

val имя = "..."
val 我 = "..."

Technically, there is no error here. Such names are allowed, but there is an international convention to use English in variable names. Even if we're writing a small program, it may have a long life ahead. People from other countries may need to read or interact with it some time.

Name things right

When naming a variable or value, you should choose a clean, descriptive name that describes the data being stored. It's tempting to use names like i and a when writing small scripts, but names like these don't convey what is being stored, nor how it should be used. A fundamental part of programming is communication, not only with the computer, but with your fellow programmer. Please keep that in mind and try to communicate your intent through the names of your values and variables.

Values are immutable

Once you define a value in Scala, its contents can never change. In many other programming languages, you can use the assignment operator = to assign new data to a name when you want. In Scala, this will only result in an error:

scala> val x = 1
val x: Int = 1

scala> x = 4
-- [E052] Type Error: ----------------------------------------------------------
1 |x = 4
  |^^^^^
  |Reassignment to val x

longer explanation available when compiling with `-explain`
1 error found

If you're coming from another programming language, this may be confusing to you, as you're used to changing (also called mutating) data. Rest assured that you will be able to write powerful and complex programs in Scala without needing to mutate data in the least.

You cannot redefine values

So far, we've been running all our code in the REPL, but it's time to run a proper Scala program again. Create a file named Redefinition.scala and enter the following text into it:

val a = 4
val a = 8

Finally, try to run the file with scala-cli run Redefinition.scala. You should see output like this:

[error] ./Redefinition.scala:2:5: Double definition:
[error] val a: Int in package object Redefinition$package at line 1 and
[error] val a: Int in package object Redefinition$package at line 2
[error] val a = 8
[error]     ^

Declaring and defining a value with the same name twice in a Scala program is not allowed. This does not apply to the Scala console however, which will let you redefine values to your heart's content:

scala> val a = 4
val a: Int = 4

scala> val a = 8
val a: Int = 8

scala> a
val res0: Int = 8

Practice

Try the following exercises in scala-cli console.

  1. Add 2 numbers together! (just type 23 + 97)
  2. Add a sequence of 6 different numbers together.
  3. What is the solution to the following equation: (4 + 6 + 9) / 77? Was it what you expected? How would you get a fractional result?
  4. Let's use variables!
    1. Type the following in the console val a = 10
    2. In the console a should print 10
    3. Try the following: 9*a
    4. and this: val b = 7 * a and then b
  5. You should be getting the hang of this by now... try this sequence:
    1. Define the value maxto be 57.0
    2. Define another value actual to max - 13
    3. Define another value percentage to actual/max
    4. If you type percentage in the console and press enter, you should see a response like 0.7719
  6. Take a few minutes to keep playing around with various things in your console. Eventually, we will learn how to actually make those numbers and things show up on a webpage, but all of the logic will remain the same, so make sure you're comfortable with it before moving on.
  7. Enter :q in the console to quit.

Did you find this article valuable?

Support Mark Hammons' Blog by becoming a sponsor. Any amount is appreciated!