© Toby Weston 2018

Toby Weston, Scala for Java Developers, https://doi.org/10.1007/978-1-4842-3108-1_3

3. Some Basic Syntax

Toby Weston

(1)London, UK

Defining Values and Variables

Let’s look at some syntax . We’ll start by creating a variable:

  val language: String = "Scala"

We’ve defined a variable as a String and assigned to it the value of “Scala.” I say “variable,” but we’ve actually created an immutable value rather than a variable. The val keyword creates a constant, and language cannot be modified from this point on. Immutability is a key theme you’ll see again and again in Scala.

If we will want to modify language later, we can use var instead of val. We can then reassign it if we need to.

  var language: String = "Java"
  language = "Scala"

So far, this doesn’t look very different from Java. In the variable definition, the type and variable name are the opposite way around compared to Java, but that’s about it. Scala uses type inference heavily, so Scala can work out that the var above is a String, even if we don’t tell it.

  val language = "Scala"

Notice that a semicolon isn’t needed to terminate lines. The Scala compiler can generally work out when an expression is finished without needing to tell it explicitly. You only need to add semicolons when you use multiple expressions on the same line.

Operator precedence is just as you’d expect in Java. In the following example, the multiplication happens before the subtraction.

  scala> val age = 35
  scala> var maxHeartRate = 210 - age * .5
  res0: Double = 192.5

Defining Functions

Function and method definitions start with the def keyword, followed by the signature. The signature looks similar to a Java method signature but with the parameter types the other way around again, and the return type at the end rather than the start.

Let’s create a function to return the minimum of two numbers.

  def min(x: Int, y: Int): Int = {
    if (x < y)
      return x
    else
      return y
  }

We can test it in the REPL by calling it

  scala> min(34, 3)
  res3: Int = 3


  scala> min(10, 50)
  res4: Int = 10

Note that Scala can’t infer the types of function arguments.

Another trick is that you can drop the return statement. The last statement in a function will implicitly be the return value.

  def min(x: Int, y: Int): Int = {
    if (x < y)
      x
    else
      y
  }

Running it the REPL would show the following:

  scala> min(300, 43)
  res5: Int = 43

In this example, the else means the last statement is consistent with a min function. If I forgot the else, the last statement would be the same regardless and there would be a bug in our implementation:

  def min(x: Int, y: Int): Int = {
    if (x < y)
      x
    y         // bug! where's the else?
  }

It always returns y:

  scala> min(10, 230)
  res6: Int = 230

If you don’t use any return statements, the return type can usually be inferred.

  // the return type can be omitted
  def min(x: Int, y: Int) = {
    if (x < y)
      x
    else
      y
  }

Note that it’s the equals sign that says this function returns something. If I write this function on one line, without the return type and just the equals sign, it starts to look like a real expression rather than a function.

  def min(x: Int, y: Int) = if (x < y) x else y

Be wary, though; if you accidentally drop the equals sign, the function won’t return anything. It’ll be similar to the void in Java.

  def min(x: Int, y: Int) {
    if (x < y) x else y
  }
  <console>:8: warning: a pure expression does nothing in statement position;
                        you may be omitting necessary parentheses
               if (x < y) x else y
                          ^
  <console>:8: warning: a pure expression does nothing in statement position;
                        you may be omitting necessary parentheses
               if (x < y) x else y
                                 ^
  min: (x: Int, y: Int)Unit

Although this compiles okay, the compiler warns that you may have missed off the equals sign.

Operator Overloading and Infix Notation

One interesting thing to note in Scala is that you can override operators. Arithmetic operators are, in fact, just methods in Scala. As such, you can create your own. Earlier, we saw the integer age used with a multiplier.

  val age: Int
  age * .5

The value age is an integer and there is a method called * on the integer class. It has the following signature:

  def *(x: Double): Double

Numbers are objects in Scala, as are literals. So, you can call * directly on a variable or a number.

  age.*(.5)
  5.*(10)

Using the infix notation, you’re able to drop the dot notation for variables and literals and call

  age * .5

…or, as another example,

  35 toString

Remember, 35 is an instance of Int.

Specifically, Scala support for infix notation means that when a method takes zero or one arguments you can drop the dot and parentheses, and if there is more than one argument you can drop the dot.

For example,

  35 + 10
  "aBCDEFG" replace("a", "A")

It’s optional though; you can use the dot notation if you prefer.

What this means is that you can define your own plus or minus method on your own classes and use it naturally with infix notation. For example, you might have a Passenger join a Train.

  train + passenger

There are not many restrictions on what you can call your functions and methods; you can use any symbol that makes sense to your domain.

Collections

Scala comes with immutable collection types (like Set, List, and Map) as well as mutable versions with the same API. The creators of Scala (and the functional programming community in general) favor immutability, so when you create a collection in Scala, the immutable version is the default choice.

So, we can create a list with the following:

  val list = List("a", "b", "c")

And create a map with

  val map = Map(1 -> "a", 2 -> "b")

…where the arrow goes from the key to the value. These will be immutable; you won’t be able to add or remove elements.

You can process them in a similar way to Java’s forEach and lambda syntax.

  list.foreach(value => println(value))                  // scala

which is equivalent to the following in Java:

  list.forEach(value -> System.out.println(value));      // java

Like Java’s method reference syntax, you can auto-connect the lambda argument to the method call.

  list.foreach(println)                                  // scala

which is roughly equivalent to this Java:

  list.forEach(System.out::println);                     // java

There are lots of other Scala-esque ways to process collections. We’ll look at these later, but the most common way to iterate is a for loop written like this:

  for (value <- list) println(value)

which reads, “for every value in list, print the value”. You can also do it in reverse:

  for (value <- list.reverse) println(value)

or you might like to break it across multiple lines:

  for (value <- list) {
    println(value)
  }

Tuples

A tuple is an ordered collection of elements. The name originates from the everyday language we use to describe multiples of things: single, pair, triple, quadruple, n-tuple, and so on. For example, the familiar quadruple is a collection of four elements. A tuple with n elements is an n-tuple. A 1-tuple is called a single, a 2-tuple a pair, a 3-tuple a triple, and so on. More colloquially, people refer to n-numbered tuples just as tuples. It’s pronounced /tuːpəl/ and not “tupple”.

In programming, tuples are useful to capture related values in a light-weight way without resorting to full blown objects. To capture a String value with a related Int, you’d write the following:

  val example = ("load", 21)

The underlying type of the tuple in this case is a Tuple2, which captures the underlying types of String and Int. Where as

  val tuple = ("save", 50, true)

…would result in a Tuple3 capturing the types String, Int, and Boolean in that order.

Access to the values is via numbered methods prefixed with an underscore.

  val event = tuple._1      // "save"
  val millis = tuple._2     // 50
  val success = tuple._3    // true

…or you can assign the values directly to variables like this:

  val (event, millis, success) = tuple

As tuple is a type, you can refer to it as such when defining values and variables arguments to functions.

  // specifying the type of the val
  val save: (String, Int, Boolean) = ("save", 50, true)


  // a function with a tuple as a typed argument
  def audit(event: (String, Int, Boolean)) = {
    ...
  }

Java Interoperability

I have already mentioned that you can use any Java class from Scala. For example, let’s say we want to create a Java List rather than the usual Scala immutable List.

  val list = new java.util.ArrayList[String]

All we did was fully qualify the class name (java.util.ArrayList) and use new to instantiate it. Notice the square brackets? Scala denotes generics using [] rather than <>. We also didn’t have to use the parentheses on the constructor, as we had no arguments to pass in.

We can make method calls—for example, adding an element—just as you’d expect:

  list.add("Hello")

…or, using infix:

l  ist add "World!"

Primitive Types

In Java there are two integer types: the primitive (non-object) int and the Integer class. Scala has no concept of primitives—everything is an object—so, for example, Scala’s integer type is an Int. Similarly, you’ll be familiar with the other basic types.

  Byte
  Short
  Int
  Long
  Char
  String
  Float
  Double
  Boolean

Although Scala has its own richer types, typically they just wrap the Java types. When working with these basic types, nine times out of ten you won’t need to worry if you’re using Scala or Java types. Things are pretty seamless. For example, Scala has a BigDecimal type with a + method, which means you can add two big decimals with much less code than in Java.

Compare the following Scala to Java:

  // scala
  val total = BigDecimal(10000) + BigDecimal(200)


  // java
  BigDecimal total = new BigDecimal(10000).add(new BigDecimal(200));

Scala hasn’t reimplemented Java’s BigDecimal; it just delegates to it and saves you having to type all that boilerplate.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.143.205.27