Previous: ResourcesUp: Scala

X In Y Minutes

Table of Contents

My take on the x in y minutes saga for Scala 2 (Also see the Scala language specification: https://www.scala-lang.org/files/archive/spec/2.13/).

First of all, the following are implicitly imported in every scala file:

import java.lang._
import scala._
import scala.Predef._

1. Naming

Note in Scala 2 val and defs cannot appear as toplevel definitions.

object Naming {

  // Ordinarily, we wouldn't need to provide the type of x here since it can
  // be determined via type inference, but here we voluntarily provide a
  // 'type ascription'
  val x: Int = 3

  // Here Show is a Single Abstract Method (SAM) type
  trait Show[A] {
    def show(a: A): String
  }

  // Since Scala 2.12 function literals are accepted as valid SAM expressions:
  implicit val intShow: Show[Int] = n => s"here is my integer: $n"

  // A type alias
  type MyInt = Int

  // Beware, implicit classes and defs will still apply to Int!
  import scala.concurrent.duration._
  implicit def myIntToDuration(n: MyInt): Duration = Duration(n, SECONDS)

  val myDuration: Duration = 3
}

2. Sorting

Also worth looking up are the notions of partial orderings, total orderings and well-orderings.

object Sorting {

  // Ordered is the equivalent to (and indeed extends) java's Comparable, ie it
  // represents 'natural' orderings
  case class DummyInt(x: Int) extends Ordered[DummyInt] {
    def compare(that: DummyInt): Int = x - that.x
  }

  // Similarly, Ordered is the equivalent to java's Comparator, note both are
  // available without import, as they are Members of the scala package
  case class DummyLong(x: Long) extends AnyVal
  // Ordering can be considered a contravariant functor, with 'on' providing the
  // equivalent of contramap
  implicit val dummyLongOrdering: Ordering[DummyLong] =
    Ordering[Long].on(dummyLong => dummyLong.x)

  val myList = List(DummyInt(10), DummyInt(1), DummyInt(-2), DummyInt(7))
  println(myList.sorted)
  // List(DummyInt(x = -2), DummyInt(x = 1), DummyInt(x = 7), DummyInt(x = 10))

  // Note the signature of sorted is sorted[B >: A](implicit ord: Ordering[B])
  // but the companion of Ordered provides an implicit conversion from Ordered[A]
  // to Ordering[A] (https://www.scala-lang.org/api/current/scala/math/Ordered$.html)

  // An ordering on DummyLong induces an ordering on Seqs of DummyLongs
  // (the lexicographic ordering), we can obtain it via the import
  import scala.math.Ordering.Implicits._

  // This import also brings into scope '<' (and others) to use with Orderings
  println(List(DummyLong(10)) < List(DummyLong(10), DummyLong(1)))
  // true
}

3. Types

object Types {
  // A singleton type is a type which depends on a literal
  // See: https://docs.scala-lang.org/sips/42.type.html
  val lsSingle: List[1] = List(1, 1)

  // Let's introduce TypeTags!  Consider the following:
  sealed trait BankBalance
  case class Savings(value: Int) extends BankBalance
  case class Debt(value: Int) extends BankBalance

  def check[A <: BankBalance](xs: List[A]) = xs match {
    case l: List[Debt] => s"Debts of size ${l.sum}!"
    case _: List[BankBalance] => "OK"
  }

  // The method above produces the compiler warning:
  // 'the type test for List[test.Debt] cannot be checked at runtime'
  // This is because of type erasure.

  // We can use TypeTags to fix this:
  import scala.reflect.runtime.universe._

  def check2[A <: BankBalance : TypeTag](xs: List[A]) = typeOf[A] match {
    case t if t =:= typeOf[Debt] => s"Debts of size ${l.sum}!"
    case t if t <:< typeOf[BankBalance] => "OK"
  }
}

4. Collections

object collections {
  // A standard Java array
  val a = Array(1, 2, 3)

  // Beware == on Array returns true iff the arrays point to the same reference
  a == Array(1, 2, 3)
  // false
}

Author: root

Created: 2024-12-14 Sat 19:47

Validate