Scala

From PeformIQ Upgrade
Revision as of 10:49, 13 May 2021 by PeterHarding (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Scala Notes

Use of '_'

From - https://stackoverflow.com/questions/8000903/what-are-all-the-uses-of-an-underscore-in-scala

import scala._                   // Wild card -- all of Scala is imported
import scala.{ Predef => _, _ }  // Exception, everything except Predef
def f[M[_]]                      // Higher kinded type parameter
def f(m: M[_])                   // Existential type
_ + _                            // Anonymous function placeholder parameter
m _                              // Eta expansion of method into method value
m(_)                             // Partial function application
_ => 5                           // Discarded parameter
case _ =>                        // Wild card pattern -- matches anything
val (a, _) = (1, 2)              // same thing
for (_ <- 1 to 10)               // same thing
f(xs: _*)                        // Sequence xs is passed as multiple parameters to f(ys: T*)
case Seq(xs @ _*)                // Identifier xs is bound to the whole matched sequence
var i: Int = _                   // Initialization to the default value
def abc_<>!                      // An underscore must separate alphanumerics from symbols on identifiers
t._2                             // Part of a method name, such as tuple getters
1_000_000                        // Numeric literal separator (Scala 2.13+)

So...

Existential types

def foo(l: List[Option[_]]) = ...

Higher kinded type parameters

case class A[K[_],T](a: K[T])

Ignored variables

val _ = 5

Ignored parameters

List(1, 2, 3) foreach { _ => println("Hi") }

Ignored names of self types

trait MySeq { _: Seq[_] => }

Wildcard patterns

Some(5) match { case Some(_) => println("Yes") }

Wildcard patterns in interpolations

"abc" match { case s"a$_c" => }

Sequence wildcard in patterns

C(1, 2, 3) match { case C(vs @ _*) => vs.foreach(f(_)) }

Wildcard imports

import java.util._

Hiding imports

import java.util.{ArrayList => _, _}

Joining letters to operators

def bang_!(x: Int) = 5

Assignment operators

def foo_=(x: Int) { ... }

Placeholder syntax

List(1, 2, 3) map (_ + 2)

Method values

List(1, 2, 3) foreach println _

Converting call-by-name parameters to functions

def toFunction(callByName: => Int): () => Int = callByName _

Default initializer

var x: String = _   // unloved syntax may be eliminated

Other

Match Expressions

def getClassAsString(x: Any): String = x match {
    case s: String => s + " is a String"
    case i: Int => "Int"
    case f: Float => "Float"
    case l: List[_] => "List"
    case p: Person => "Person"
    case _ => "Unknown"
}
def isTrue(a: Any) = a match {
    case 0 | "" => false
    case _ => true
}
// Version 1 - compiles to a tableswitch
import scala.annotation.switch

class SwitchDemo {
    val i = 1
    val x = (i: @switch) match {
        case 1  => "One"
        case 2  => "Two"
        case _  => "Other"
    }
}
expr match {
  case List(1,_,_) => "A List with three elements"
  case List(_ *) => "A List with zero or more elements"
  case Map(_,_) => "A Map with any Key and Value type"
  case _ => "Anythiong else"
}

Getters and Setters

According to the Scala docs:

Scala does not follow the Java convention of prepending set/get to mutator and accessor methods (respectively). Instead, the following conventions are used:

  • For accessors of properties, the name of the method should be the name of the property.
  • In some instances, it is acceptable to prepend “is” on a boolean accessor (e.g. isEmpty). This should only be the case when no corresponding mutator is provided.
  • For mutators, the name of the method should be the name of the property with “_=” appended.


So:

class Foo {
  def bar = ...
  def bar_=(bar: Bar) {
    ...
  }
  def isBaz = ...
}


val nums = List(1,2,3,4,5,6,7,8,9)

nums filter (_ % 2 == 0)
nums reduce (_ + _)
nums.exists (_ > 5)
nums.takeWhile(_ < 8)

As used in Swift for un-named or unused values:

def getProps = {
   Config.getHost, Config.getPort, Config.getIp, Config.getMask
}

val (host, port, ignore1, ignore2) = getProps

val (host, port, _, _) = getProps

Types

type StringMatcher = String => (String => Boolean)

def starts: StringMatcher = (prefix:String) => _ startsWith prefix

...or...

def starts: StringMatcher = (prefix:String) => (s) => s startsWith prefix

Generating Random Strings

One liner:

Random.alphanumeric.take(10).mkString

From - https://alvinalexander.com/scala/creating-random-strings-in-scala/

import scala.annotation.tailrec

/**
 * Examples of different ways to write "random string" methods in Scala.
 * See the main method for examples of how each method is called.
 * Created by Alvin Alexander, https://alvinalexander.com
 */
object RandomStringExamples {
  
  def main(args: Array[String]) {
    println("1:  " + randomString(10))
    println("2:  " + randomStringArray(10))
    println("3:  " + randomStringRecursive(10).mkString)
    println("3:  " + randomStringRecursive2(10).mkString)
    println("4:  " + randomStringTailRecursive(10, Nil).mkString)
    println("5:  " + randomStringRecursive2Wrapper(10))
    println("6:  " + randomAlphaNumericString(10))
    println("6:  " + randomAlphaNumericString(10))
    println("6:  " + randomAlphaNumericString(10))
    println("x2: " + x2(10, ('a' to 'z') ++ ('A' to 'Z')))
  }

  // 1 - a java-esque approach
  def randomString(length: Int) = {
    val r = new scala.util.Random
    val sb = new StringBuilder
    for (i <- 1 to length) {
      sb.append(r.nextPrintableChar)
    }
    sb.toString
  }

  // 2 - similar to #1, but using an array
  def randomStringUsingArray(length: Int): String = {
    val r = new scala.util.Random
    val a = new Array[Char](length)
    val sb = new StringBuilder
    for (i <- 0 to length-1) {
      a(i) = r.nextPrintableChar
    }
    a.mkString
  }

  // 3 - recursive, but not tail-recursive
  def randomStringRecursive(n: Int): List[Char] = {
    n match {
      case 1 => List(util.Random.nextPrintableChar)
      case _ => List(util.Random.nextPrintableChar) ++ randomStringRecursive(n-1)
    }
  }

  // 3b - recursive, but not tail-recursive
  def randomStringRecursive2(n: Int): String = {
    n match {
      case 1 => util.Random.nextPrintableChar.toString
      case _ => util.Random.nextPrintableChar.toString ++ randomStringRecursive2(n-1).toString
    }
  }

  // 4 - tail recursive, no wrapper
  @tailrec
  def randomStringTailRecursive(n: Int, list: List[Char]):List[Char] = {
    if (n == 1) util.Random.nextPrintableChar :: list
    else randomStringTailRecursive(n-1, util.Random.nextPrintableChar :: list)
  }

  // 5 - a wrapper around the tail-recursive approach
  def randomStringRecursive2Wrapper(n: Int): String = {
    randomStringTailRecursive(n, Nil).mkString
  }
  
  // 6 - random alphanumeric
  def randomAlphaNumericString(length: Int): String = {
    val chars = ('a' to 'z') ++ ('A' to 'Z') ++ ('0' to '9')
    randomStringFromCharList(length, chars)
  }
  
  // 7 - random alpha
  def randomAlpha(length: Int): String = {
    val chars = ('a' to 'z') ++ ('A' to 'Z')
    randomStringFromCharList(length, chars)
  }

  // used by #6 and #7
  def randomStringFromCharList(length: Int, chars: Seq[Char]): String = {
    val sb = new StringBuilder
    for (i <- 1 to length) {
      val randomNum = util.Random.nextInt(chars.length)
      sb.append(chars(randomNum))
    }
    sb.toString
  }

  def x(length: Int, chars: Seq[Char]): String = {
    val list = List.range(1, length)
    val arr = new Array[Char](length)
    list.foreach{ e => arr(e) = chars(util.Random.nextInt(chars.length)) }
    list.mkString
  }
  
  // create a fake list so i can use map (or flatMap)
  def x2(length: Int, chars: Seq[Char]): String = {
    val tmpList = List.range(0, length)
    val charList = tmpList.map{ e => chars(util.Random.nextInt(chars.length)) }
    return charList.mkString
  }

}