Tuples and OOP examples of [Scala learning]

Posted by Genesis730 on Thu, 30 Dec 2021 17:21:37 +0100

A FEW MISCELLANEOUS ITEMS

https://docs.scala-lang.org/overviews/scala-book/misc.html

In this section we'll cover a few miscellaneous items about Scala:

  • Tuples tuples
  • Scala OOP example of pizza restaurant order entry system

TUPLES

https://docs.scala-lang.org/overviews/scala-book/tuples.html

Tuple is a concise class that provides you with a simple way to store heterogeneous (different) items in the same container. For example, suppose you have such a class:

class Person(var name: String)

You don't have to create a special class to store things, like this:

class SomeThings(i: Int, s: String, p: Person)

you can just create a tuple like this:

val t = (3, "Three", new Person("Al"))

As shown in the figure, just put some elements in parentheses and you have a tuple. Scala tuples can contain 2 to 22 items. They are very useful when you only need to put some things together and don't want to have to define the burden of a class, especially when the class feels a little "artificial" or fake.

Technically, Scala 2 X classes named Tuple2, Tuple3... Up to Tuple22. In fact, you rarely need to know this, but it's also good to know what's going on behind the scenes. (this architecture has been improved in Scala 3.)

A few more tuple details

This is a two element tuple:

scala> val d = ("Maggie", 30)
d: (String, Int) = (Maggie,30)

Note that it contains two different types. This is a triple element:

scala> case class Person(name: String)
defined class Person

scala> val t = (3, "Three", new Person("David"))
t: (Int, java.lang.String, Person) = (3,Three,Person(David))

There are several ways to access tuple elements. One way to access them is through the element number, where the number is preceded by an underscore:

scala> t._1
res1: Int = 3

scala> t._2
res2: java.lang.String = Three

scala> t._3
res3: Person = Person(David)

Another cool way is to access them like this:

scala> val(x, y, z) = (3, "Three", new Person("David"))
x: Int = 3
y: String = Three
z: Person = Person(David)

Technically, this method involves a form of pattern matching, which is a good way to assign tuple elements to variables.

Returning a tuple from a method

This is a good place when you want to return multiple values from a method. For example, this is a method that returns tuples:

def getStockInfo = {
    // other code here ...
    ("NFLX", 100.00, 101.00)  // this is a Tuple3
}

You can now call this method and assign the variable name to the return value:

val (symbol, currentPrice, bidPrice) = getStockInfo

The REPL demonstrates how this works:

scala> val (symbol, currentPrice, bidPrice) = getStockInfo
symbol: String = NFLX
currentPrice: Double = 100.0
bidPrice: Double = 101.0

Creating a class for the return type of a method like this feels a little overkill, and tuples are very convenient.

Tuples aren't collections

Technically, Scala 2 X tuples are not collection classes, they are just a convenient small container. Because they are not collections, they have no methods such as map, filter, etc.

AN OOP EXAMPLE

https://docs.scala-lang.org/overviews/scala-book/oop-pizza-example.html

This lesson shares a sample OOP application written in Scala. This example shows the code you might write for the order entry system for a pizza restaurant.

As shown earlier in this book, you can create enumerations in Scala like this:

sealed trait Topping
case object Cheese extends Topping
case object Pepperoni extends Topping
case object Sausage extends Topping
case object Mushrooms extends Topping
case object Onions extends Topping

sealed trait CrustSize
case object SmallCrustSize extends CrustSize
case object MediumCrustSize extends CrustSize
case object LargeCrustSize extends CrustSize

sealed trait CrustType
case object RegularCrustType extends CrustType
case object ThinCrustType extends CrustType
case object ThickCrustType extends CrustType

One advantage of Scala is that even if we haven't discussed sealed trait or case objects, you can still figure out how this code works.

A few classes

Given these enumerations, you can now start creating some Pizza related classes for the order entry system. First, this is a Pizza class:

import scala.collection.mutable.ArrayBuffer

class Pizza (
    var crustSize: CrustSize,
    var crustType: CrustType,
    var toppings: ArrayBuffer[Topping]
)

Next, here's an Order class, where an Order consists of a mutable list of pizzas and a Customer:

class Order (
    var pizzas: ArrayBuffer[Pizza],
    var customer: Customer
)

Here's a Customer class to work with that code:

class Customer (
    var name: String,
    var phone: String,
    var address: Address
)

Finally, here's an Address class:

class Address (
    var street1: String,
    var street2: String,
    var city: String,
    var state: String,
    var zipCode: String
)

So far, these classes look like data structures -- like structures in C -- so let's add some behavior.

Adding behavior to Pizza

In most cases, the OOP Pizza class requires some methods to add and remove toppings and adjust the size and type of the shell. This is a "Pizza" class that adds methods to handle these behaviors:

class Pizza (
    var crustSize: CrustSize,
    var crustType: CrustType,
    val toppings: ArrayBuffer[Topping]
) {

    def addTopping(t: Topping): Unit = toppings += t
    def removeTopping(t: Topping): Unit = toppings -= t
    def removeAllToppings(): Unit = toppings.clear()

}

You can also argue that pizza should be able to calculate its own price, so you can add another method to this class:

def getPrice(
    toppingsPrices: Map[Topping, Int],
    crustSizePrices: Map[CrustSize, Int],
    crustTypePrices: Map[CrustType, Int]
): Int = ???

Please note that this is a completely legal method??? Syntax is often used as a teaching tool, and sometimes you use it as a method sketch tool to say, "this is what my method signature looks like, but I don't want to write a method body." A good thing at that time was that the code could be compiled.

Having said that, don't call that method. If you do, you will get a not implemented error, which can describe this situation very well.

Adding behavior to Order

You should be able to perform some operations on the order, including:

  • Add and remove pizza
  • Update customer information
  • Get order price

This is an Order class that allows you to do these things:

class Order (
    val pizzas: ArrayBuffer[Pizza],
    var customer: Customer
) {

    def addPizza(p: Pizza): Unit = pizzas += p
    def removePizza(p: Pizza): Unit = pizzas -= p

    // need to implement these
    def getBasePrice(): Int = ???
    def getTaxes(): Int = ???
    def getTotalPrice(): Int = ???

}

Again, for this example, we don't care how to calculate the order price.

Testing those classes

You can test these classes with a small "driver" class. By adding a printOrder method in the Order class and a toString method in the Pizza class, you will find that the displayed code is as shown in the advertisement:

import scala.collection.mutable.ArrayBuffer

object MainDriver extends App {

    val p1 = new Pizza (
        MediumCrustSize,
        ThinCrustType,
        ArrayBuffer(Cheese)
    )

    val p2 = new Pizza (
        LargeCrustSize,
        ThinCrustType,
        ArrayBuffer(Cheese, Pepperoni, Sausage)
    )

    val address = new Address (
        "123 Main Street",
        "Apt. 1",
        "Talkeetna",
        "Alaska",
        "99676"
    )

    val customer = new Customer (
        "Alvin Alexander",
        "907-555-1212",
        address
    )

    val o = new Order(
        ArrayBuffer(p1, p2),
        customer
    )

    o.addPizza(
        new Pizza (
            SmallCrustSize,
            ThinCrustType,
            ArrayBuffer(Cheese, Mushrooms)
        )
    )

    // print the order
    o.printOrder

}

Experiment with the code yourself

To experiment with this yourself, see the pizza oopexample project in the GitHub repository of this book, which you can find at this URL:

To compile this project, it will help (a) use IntelliJ IDEA or Eclipse, or (b) know how to use it Scala Build Tool.

Topics: Scala