Scala: Difference between revisions

From bibbleWiki
Jump to navigation Jump to search
Line 233: Line 233:
       case e: NumberFormatException => Left("Error: " + e.getMessage)
       case e: NumberFormatException => Left("Error: " + e.getMessage)
   }
   }
}
</syntaxhighlight>
=Pattern Matching=
==Introduction==
Just like Ruby sigh!! Switch statements without breaks.
<syntaxhighlight lang="scala">
val number = 5
number match {
  case 0 => "zero"
  case 5 => "five"
  case 9 => "nine"
  case _ => "default" // Must be last
}
</syntaxhighlight>
==Matching On Attributes==
We can have attributes as matches and ignore some content
<syntaxhighlight lang="scala">
case class Track(title: String, artist: String, trackLength: Int)
myTrack match {
  case Track(_,_, 100) => "Long Track"
  case Track(_,"Bowie", _) => "Bowie"
  case _ => "No Track"
}
</syntaxhighlight>
==Matching On Sequence==
We can match on sequences by using wildcards to denote we do not card about data beyond a certain value
<syntaxhighlight lang="scala">
val numbers = List(1,2,3,4,5,6,7)
numbers match {
  case List(_, second, _*) => second
  case _ => -1
}
}
</syntaxhighlight>
</syntaxhighlight>

Revision as of 13:29, 11 January 2021

Introduction

Some features of the language

  • Functional and Object Orientated
  • Use of immutable Data Structure
  • Rich Collections Library
  • Better Concurrency Support

To get this to work I downloaded scala and intellij.

Functional Programming

Some definitions

  • Immutability is when we can not allowed to change a variable. Not changing a value means parallelism will work better
  • Expression are something yields a value. e.g. x+y and have not side effects
  • Statements is code which does something. e.g. do(something) and have side effects
  • Function is a a relation between a set of inputs and a set of outputs with the property that each input is related to exactly one output.
    • Pure always has the same output, easier to test, parallelisation
    • Impure may not have the same output

High Order Functions

High Order Functions are function which take functions as an argument High Order functions allow you to provide some of the method as an argument to extract the part which is different
So given the following to get apples

def getApples(basket: List[Fruilt]) = getFruits(fruitBasket,
  (fruit: Fruit) => fruit.name = "apple")


Can be replaced with a more generic

def getFruits(basket: List[Fruilt], filterByFruit: Fruit => Boolean) = 
    for (fruit <- basket if filterByFruit(fruit)) yield fruit


Scala provide many other HOFs not KnightRider such as

  • map
  • reduce
  • filter
  • fold

Language Features

val and var

Like Kotlin, scala supports val and var where only vars can be changed

Conditions

If conditions are expressions and not statements. We generally do not need the return statement. I think this is like Ruby from memory e.g.

val arguments = Array("Monday")
val day = if (!arguments.isEmpty) arguments(0) else "Sunday"

Loops

Imperative

Where we do something

val letters = List("a","b","c","d","e")
for(letter <- letters) {
   println(letter)
}

We can add filters on the end e.g. to print even numbers

for(letter <- letters if (number %2) == 0) {
   println(letter)
}

And not just one, many, which I think is looking really really ugly

for(
 letter <- letters 
 if (number %2) == 0) 
 if (number > 2) 
{
   println(letter)
}

We can iterate within an iteration though using the same approach e.g. we could have

for(number <- numbers) {
  for(letter <- letters) {
     println(number + " => " + letter)
  }
}

But with the new way this could be written with curly braces

for{ 
  number <- numbers 
  letter <- letters 
 } println(number + " => " + letter)

Functional

Where we return values. Using the example above we could yield a List[String] of values.

for{ 
  number <- numbers 
  letter <- letters 
 } yield number + " => " + letter

Functions

Introduction

Functions are very similar to other languages

def foo(arg: Type): ReturnType = {
  // Stuff
}

Anonymous Functions

Scala supports this e.g.

val plusOne = (x: Int) => x + 1

We can use the name function above with

plusOne(99)

Weird Option for Arrow Functions

If we use the argument in an arrow function once and only once we can drop replace the argument with an _ and drop the arrow. So

fruitBasket.filter(fruit => fruit.name)
// Can be replaced with
fruitBasket.filter(_.name)

Classes

Introduction

They can contain fields and methods like most languages. Like Kotlin we can initialize on the constructor

class Employee {
   private var salary: Int = 100 
   def getSalary() = salary
   def setSalary(newSalary) = {
      salary = newSalary
   } 
}
var john = new Employee

Companion Objects (Static Functions)

A bit like kotlin but a little different in that they are coded separate and can access the private fields of the class

object MathCompanion {
   def sum(a: Int, b: Int): Int = a + b
   def getPrivateMember: Int = new MathCompanion().max
}

class MathCompanion {
   private val max = 100
}

Apply

We can add a special apply method to the companion object to allow construction without the new keyword. This provides a functional way to create an object I think like Ruby.

object MathCompanion {
   def apply(firstname: String) = new Person(firstname)
}
class Person(firstname: String) {
...
}
val joe = Person("Fred")

Case Classes

This modifier

  • Implements apply method
  • Creates immutable arguments to the constructor
  • Copy method to make modified copies
  • Add Hash code, equals and toString()
  • Pattern Matching
case class Course(title: String, author: String)
val scalaCourse = Course("Scala Test", "Joe Humanshu")

Traits and Main

A trait encapsulates method and field definitions, which can then be reused by mixing them into classes. Unlike class inheritance, in which each class must inherit from just one superclass, a class can mix in any number of traits.

Traits are used to define object types by specifying the signature of the supported methods. Scala also allows traits to be partially implemented but traits may not have constructor parameters.

A trait definition looks just like a class definition except that it uses the keyword trait. The following is the basic example syntax of trait.

trait Equal {
   def isEqual(x: Any): Boolean
   def isNotEqual(x: Any): Boolean = !isEqual(x)
}

class Point(xc: Int, yc: Int) extends Equal {
   var x: Int = xc
   var y: Int = yc
   
   def isEqual(obj: Any) = obj.isInstanceOf[Point] && obj.asInstanceOf[Point].x == y
}

object Demo {
   def main(args: Array[String]) {
      val p1 = new Point(2, 3)
      val p2 = new Point(2, 4)
      val p3 = new Point(3, 3)

      println(p1.isNotEqual(p2))
      println(p1.isNotEqual(p3))
      println(p1.isNotEqual(2))
   }
}

Whilst learning scala we are directed to use the App trait as it contains the main function e.g.

object Hello extends App {
  println("Fred Was Ere")
}

Error Handling

Null Handling

Maybe tired of typing this but like Ruby, Scala supports the Option approach to null handling i.e. you can return an Option[String]. From here use getOrElse and write

val result = employees.find(_=="Value Not Found).getOrElse("Nobody home")

Exception

Standard languages support try/catch/finally approoach.

try {
} catch(Exception e) {
} finally {
}

Scala can use pattern matching so examine the result.

val outcome = Try(10/0)
outcome match {
   case Success(value) => println("Time for bed")
   case Failure(er) => println("Computation failed, " + e.getMessage)
}

Either

Either works like Option except it is a tuple where you can place the result in one side and the error in the other.

def stringToInt(in: String): Either[String, Int] = {
   try {
      Right(in.toInt)
   } catch {
      case e: NumberFormatException => Left("Error: " + e.getMessage)
   }
}

Pattern Matching

Introduction

Just like Ruby sigh!! Switch statements without breaks.

val number = 5
number match {
   case 0 => "zero"
   case 5 => "five"
   case 9 => "nine"
   case _ => "default" // Must be last
}

Matching On Attributes

We can have attributes as matches and ignore some content

case class Track(title: String, artist: String, trackLength: Int)
myTrack match {
   case Track(_,_, 100) => "Long Track"
   case Track(_,"Bowie", _) => "Bowie"
   case _ => "No Track"
}

Matching On Sequence

We can match on sequences by using wildcards to denote we do not card about data beyond a certain value

val numbers = List(1,2,3,4,5,6,7)
numbers match {
   case List(_, second, _*) => second
   case _ => -1
}

VS Code

I used https://shunsvineyard.info/2020/11/20/setting-up-vs-code-for-scala-development-on-wsl/ for installing with VS Code.