left-icon

Scala Succinctly®
by Chris Rose

Previous
Chapter

of
A
A
A

CHAPTER 2

Variables and Values

Variables and Values


A variable is a name used to point to different values. For instance, we might create an integer variable called personAge and point it to 35. We can point a variable to a different value, which means we can later change personAge and point it to 36. In this sense, Scala variables are similar to references in other languages. In Scala, we define variables by using the var keyword.

A value is a fixed quantity or object. Values do not change, and they are pointed to by variables. In other languages, values are called constants, and we might define a value called PI and set it to 3.14159. In Scala, we define values by using the val keyword.

Code Listing 3: Setting and Changing Vars and Vals

object MainObject {

      def main(args: Array[String]): Unit = {

            // Create a variable called myVariable.

            var myVariable = 0

            

            // Create a value called myValue.

            val myValue = 0

            

            // We can change the value that myVariable points to:

            myVariable = 10

            

            // But we can't change a val! The following line is an error!

            myValue = 10

      }

}

In Code Listing 3, we create a variable called myVariable and set it to 10. We also create a value called myValue, again set to 0. Next, we change the setting of myVariable to 10. This is fine because variables can be set to many different settings throughout a program. But in the next line we try to set myValue to 10—this line is an error, and I have highlighted it in red. Note that we cannot reassign a value. In order to reassign a val would be something like reassigning a meaning to the number 3 or to Pi—the operation makes no sense and is not legal.

The syntax for defining a variable begins with the var or val keyword, followed by the identifier name, such as myVariable or myValue. We follow this with the assignment operator “=” and supply a value, variable, or literal. This method, used in Code Listing 3, is a shorthand syntax. Scala will infer the data type for the variable from the initial assignment.

We can also explicitly state the data type for the variable by including a colon and the name of the data type (we will look at all the available data types shortly). Code Listing 4 shows some examples of using this longer syntax to define Int, String, and Double variables by specifying the data types.

Code Listing 4: Specifying Data Types

object MainObject {

      def main(args: Array[String]): Unit = {

            // Create an Int variable called myInt

            var myInt: Int = 0

            

            // Create a String variable called personName

            var personName: String = "Thomas"

            // Create a double val set to the Golden Ratio

            val goldenRatio: Double = 1.61803398875

      }

}

Identifier names

An identifier is a name we use to stand for something in our program. Identifiers are used to name val and var, as well functions, classes, and objects. Scala is flexible when it comes to naming identifiers. There are almost no restrictions at all, unlike languages such as Java, which do not allow arbitrary symbols. By contrast, Scala allows all types of string to be identifiers, including options like “&”, and “Days of the week!”.

Simple identifiers can be made in Scala much the same as with other languages. These identifiers consist of a string of characters that begin with a letter or underscore. The string can contain digits, but it cannot begin with a digit. For example: userName, _height, record56, Square_Root.

We can also use operator symbols as identifiers. This is often the case when we name member methods that are to act as operators for our objects in object-oriented programming. We will look at naming member methods when we look at classes. For example: +, ++, :::. Generally, naming our regular variables with these symbols or strings of these symbols is not a good idea because doing so can make the code difficult to read.

Finally, we can use back quotes to delimit arbitrary strings. These strings can contain spaces, symbols, digits, anything at all. The identifier name is the string without the back quotes. We can use the identifier name by itself, but only in certain circumstances because the compiler sometimes needs the back quotes in order to understand where our variable names begin and end. Code Listing 5 shows some examples of Scala identifiers with simple and complex names.

Code Listing 5: Identifier Examples

object MainObject {

    def main(args: Array[String]): Unit = {

            // Identifiers for variables are usually descriptive strings

            // of letters and digits:

            var root2 = Math.sqrt(2)

      

            // We can also define identifiers beginning with underscore:

            val _someVar = 23

      

            // But, we can define an identifier as a series of operators.

            // Note that this doesn’t make sense in the current context, and

            // this type of identifier is much more useful when we are

            // defining classes in Object-Oriented programming!

            def +&^%(i: Int, y: Int): Int = 42

            

            // We can name a variable an arbitrary string of characters, but

            // sometimes we have to use back quotes to delimit the name:

            val `#*^`: Int = 623

            

            // And we can use back quotes to define arbitrary identifiers:

            val `my identifier has 4's in its name, and $ as well!` = 9

            

            // If it can, Scala will recognize the identifiers without quotes

            // even their name consists of arbitrary operator symbols:

            println("The value of #*^ is " + #*^)

            // We can include the back quotes if our names are confusing:

            println("The value of #*^ is " + `#*^`)

            

            

            // If the names of the variable have spaces, we need to use

            // back quotes because the Scala compiler

            // will split the name into tokens unless it is delimited

            // with back-quotes:

            println("The value of my silly val is: " +

                  `my identifier a 4 in its name, and $ as well!`)

      

            // The following is indecipherable and will generate an error!

            //println("The value of my silly val is: " +

            //    my identifier has 4's in its name, and $ as well!)

      }

}

Note: Although we are able to name our identifier’s keywords like def, this is not a good idea (in fact you would have to use back quotes to do this). We should always try to name identifiers in a descriptive way, and we should never try to redefine keywords by creating identifiers with the same name.

Tip: It is conventional to use Camel Case to name Scala identifiers. Identifiers begin with a lowercase letter, and every following word within the identifier begins with an uppercase letter, such as averageIncome and computePerimiter. This is just a convention, and when we name classes, we typically use an uppercase letter to begin each word within the same name, such as MyClass. This makes it easy to differentiate between variables and classes.

Scala is case sensitive, which means the identifiers MYID and myID are completely different identifiers, and def is a keyword, but DEF is not.

Data Types

Data Types

  1. Figure 13: Data Types

The fundamental data types are the same as in Java, except they begin with an uppercase letter. The Scala compiler is often clever enough to deduce the data type from the context, so the data type can often be left out when we are defining variables and values, but, if we want to explicitly state the data types for our variables, we use the names in the first column of Figure 13. Figure 14 depicts an overview of some of the characteristics of the fundamental data types in Scala.

Overview of Fundamental Data Types

Figure 14: Overview of Fundamental Data Types

Code Listing 6 shows some examples of declaring and defining variables and values (note this listing has no main method and cannot be run).

Code Listing 6: Defining Variables and Values

var someInteger: Int = 190 // Declare and define an integer.

val someChar: Char = 'A' // Declare and define a character.

var someBool: Boolean = false // Declare and define a Boolean.

var someFloat = 3.14f // Declare and define a float.

var someDouble = Math.sqrt(2) // Declare and define a double.

In the the final two examples, I have not used a data type, but Scala knows that someFloat is supposed to be a floating-point number because the literal 3.14f is a float (it ends with f, which is the suffix for a float). Likewise, someDouble will have the type of Double because Math.sqrt(2) is a function that returns Double.

The integers are whole numbers. For instance, an integer could be set to 178 or -59. The different integer types (Byte, Short, Int, and Long) are used when we need more or less range for our numbers. Bytes can only store between -128 and 127 inclusive, so if you have a variable you know will fall only between these values, you can save RAM and store the variable as a Byte. Otherwise, if your variable needs a lot of range, you might use a Long, because it has a range of -263 up to 263-1. We usually use Int for whole numbers and only use Byte or Short when we know the range is small and we want to conserve RAM, or when we need to interoperate with a system that uses one of these smaller data types. Likewise, it’s rare to use a Long unless we know that the particular variables need the range.

Scala uses the same integer arithmetic as other languages. This means that operations result in truncation rather than rounding. For instance, 10/6 will give the result 1, even though the actual value, 1.66666, is nearer to 2. Integer arithmetic always truncates the fractional part of the answer and returns the remaining integer part as the result. If you need to know the remainder after division, this can be returned with % operator. So, 10/6 in terms of integer operations is 10/6, which equals 1 with the remainder returned 10%6, which equals 4; in other words, 10/6 equals 1 with remainder 4.

Floating-point numbers (Float and Double) are able to express fractional values such as 67.8 and -99.24. Floating-point arithmetic often incurs error, and there are many fractions that floating point cannot represent exactly. For instance, 1/3 is impossible for floating point to represent because Scala uses IEEE 754 standard, and this standard only allows exact representations of sums of perfect powers of 2. When we set a Double variable to 1/3, the number stored is very close 1/3, but not exact. This is sometimes important—for instance, when checking if two doubles are equal, we sometimes must consider a small amount of error, such that 0.333333333 would be equal to 0.333333332, because the 2 on the end is possibly a rounding error. Code Listing 7 shows an example of using Math.abs to test equality of doubles.

Code Listing 7: Testing Equality Between Doubles

object MainObject {

    def main(args: Array[String]): Unit = {

      // Define two variables which are mathematically

      // equal:

      var a = (10.0 / 3.0)

      var b = (1.0/3.0) * 2.0 * 5.0

            

      // This will not work! Testing the exact

      // values of doubles for equality is often

      // a waste of time!

      if(a == b)

            println("The two are equal!")

      else

            println("The two are not equal...")

      

      // Allowing some small error using Math.abs

      // makes more sense. The following report

      // that a and b are equal:

      if(Math.abs(a - b) < 0.0001)

            println("The two are equal!")

      else

            println("The two are not equal...")

      }

}

In Code Listing 7, we create two variables, a and b, which should theoretically be set to exactly the same value;—10/3 is mathematically identical to (1/3)*2*5. But in IEEE 754, we will get two different values for these expressions, so we should use Math.abs when we compare them, and we should allow for a small degree of error (0.0001 in the example will report equal value as long as the doubles are similar to within 1/10000). The small value used for the comparison of floating-point types is usually called the epsilon value. We can use exactly the same technique when comparing Float values because Floats suffer from the same rounding errors.

Boolean variables are used in logical expressions in order to make decisions and for filtering. They have only two values: true or false.

The Char data type is used for characters and for Strings. It represents Unicode characters, such as 'A' or '@'.

Literals

A literal is a value that appears in the code, such as 190 or 'A'. They are used to set variables and values and also to form expressions. All of the literals are values, and like val, they cannot be redefined. We can, however, point variables to them.

Integer literals

Integer literals appear as whole numbers, such as 899 or -77162. They can have a negative sign to indicate values less than 0. Integer literals without a suffix are read as base 10 or decimal literals, so that 899 means “eight hundred and ninety-nine.” Integer literals with the 0x suffix are read as hexadecimal, or base 16 numbers. For instance, 0xff0a and 0x772e (hexadecimal is a positional notation, the same as decimal, except that there are 16 digits, 0 through to 9, A, B, C, D, E and F—for more information on hexadecimal, visit Wikipedia: https://en.wikipedia.org/wiki/Hexadecimal). Long integer literals end with L, such as 789827L or -898827L. Long integer literals have a range of -263 to 263-1.

Note: In previous versions of Scala, we could use a leading '0' to denote an octal number. For instance, 037 would mean the decimal value 31. Octal literals are now obsolete, and placing a leading 0 at the beginning of an integer literal will cause an error.

Floating-point literals

Type Double literals contain a decimal point—for example, 90.7 or -178.5. Type Float literals can contain a decimal point, too, and they end with an 'f'. For instance, 271f or -90.872f. You can also use scientific notation for the Float and Double literals—for example, 54.9e2, which is the same as 5490.0 (or 54.9 multiplied by 10 to the power of 2). You can use the 'f' suffix along with scientific notation to create a Float literal too, e.g., 16e-1f would mean 1.6 or 16 by 10 to the power of negative 1.

Other literals

Character literals are surrounded with single quotes, such as 'A', '%', or '6'. Note that '6' is very different from the integer 6. '6' is a Unicode character with the Int value of 54. For a complete table of the Unicode characters, visit http://unicode-table.com/en/. There are also some escape sequences available as character literals: '\n' for new line, '\r' for carriage return, '\t' for tab, '\"' for double quotes. In order to use a Unicode code directly, we place the '\u suffix followed by the number, so that '\u0065' is the same as 'A', because '6' has a Unicode value of 65.

The Boolean literals are true and false. Code Listing 8 shows some Boolean literals. We can use the true and false keywords, and we can also use other literals along with logical operators such as '>' (which means greater than) in order to form logical expressions. In Code Listing 8, 2 is not greater than 5, which means the Boolean called twoGreaterThanFive will be set to false.

Code Listing 8: Boolean Literals

val myBoolean = true

var myOtherBoolean = false

val twoGreaterThanFive = 2 > 5

String is not a fundamental data type, but strings are so commonly used that we can introduce them with the other fundamental data types. String literals are formed by surrounding text with double quotes. We can also use triple-double quotes to denote multiline string literals. Multiline literals can include new line characters. Code Listing 9 shows two examples of string literals—a single line literal and a multiline literal.

Code Listing 9: String Literals and Multiline String Literals

var str = "This is a string!"

var multiLineString = """

This is also a string, only this one

can span many lines because it is delimited with

triple quotes! It can also contain single quotes,

like ".

"""

Comments

Comments are notes programmers place in the code for themselves and other programmers. Comments are ignored by the Scala compiler. Scala allows the same commenting as Java. We use // to specify a single line comment or to comment on the remaining text on a line, and we use /* and */ to include block comments (see Code Listing 10 for an example using single and multiline comments).

Code Listing 10: Comment Example

/* HelloWorld

* Displays the text 'Hello world' to the user

* CommandLine Args: None

* Returns: None

* */

object MainObject {

      def main(args: Array[String]): Unit = {

            // Print 'Hello world!' to the console:

            println("Hello world!") // Single line comment!

      }

}

Note: Scala also allows special comments called ScalaDoc comments. These comments begin with /** and end with */. They are used to generate documentation for our code. For more information on the syntax and use of ScalaDoc comments, visit: http://docs.scala-lang.org/style/scaladoc.html.

Casting

To cast is to change the data type of a variable, value, or literal. Casting in Scala is achieved by calling functions that each of the data types supply. For instance, to cast an Int to a String, we would use someInt.toString. To cast a Double to a Float, we would use someDouble.toFloat. Code Listing 11 shows examples of casting between the various types.

Code Listing 11: Casting

object MainObject {

      def main(args: Array[String]) {

      

            // Casting numerical types to other types and strings:

            var someDouble = 1.3

            println("As a float: " + someDouble.toFloat)

            println("As a char: " + someDouble.toChar)

            println("As an Int: " + someDouble.toInt)

            println("As a String: " + someDouble.toString)

            

            // Casting strings to numerical types:

            val myInt = "192".toInt

            val myFloat = "192.2".toFloat

      

      }

}

Note: The toInt method is a digit parsing method, which means if we use any symbols not available to the integers, we will cause an error. In order to cast the string “72.5” to an integer, we first need to convert it to a Double or Float, then cast it to an Int.

Note: Casting a Float or Double to Int uses truncation. This is true when we change a Float type to a Short, Int, or Long. Numbers are not rounded—they are truncated to the nearest whole value towards Zero.

Scroll To Top
Disclaimer
DISCLAIMER: Web reader is currently in beta. Please report any issues through our support system. PDF and Kindle format files are also available for download.

Previous

Next



You are one step away from downloading ebooks from the Succinctly® series premier collection!
A confirmation has been sent to your email address. Please check and confirm your email subscription to complete the download.