Scala


General

Type annotations

Apparently, explicit type annotations are discouraged??

Conventions

https://docs.scala-lang.org/style/naming-conventions.html

Hello world

// Filename: hi.scala
@main def hi(args: String*): Unit =
  println("Hello world!")

Compilation:

$ scalac --version
Scala compiler version 3.3.1 -- Copyright 2002-2023, LAMP/EPFL

# Generate class files
$ scalac hi.scala

$ ls
'hi$package$.class'  'hi$package.class'  'hi$package.tasty'   hi.class   hi.scala   hi.tasty

# Run
$ scala hi
Hello world!

See:

case class

https://docs.scala-lang.org/tour/case-classes.html

Path-dependent type

Example from here:

case class Board(width: Int, height: Int) {
  case class Coord(x: Int, y: Int) {
    require(0 <= x && x <= width &&
            0 <= y && y <= height)
  }
  val occupied = scala.collection.mutable.Set[Coord]()
}

@main def eg(args: String*): Unit =
  val b = Board(10, 20)
  val c1 = b.Coord(3, 5)
  b.occupied += c1  // Add new coordinate to set of occupied
  // No error

  val c2 = b.Coord(11, 20)
  // Run-time error! Not compile-time... ??

Running this would give error:

$ scalac pathdeptype.scala; scala eg
java.lang.IllegalArgumentException: requirement failed
        at scala.Predef$.require(Predef.scala:324)
        at Board$Coord.<init>(pathdeptype.scala:5)
        at Board$Coord$.apply(pathdeptype.scala:3)
        at pathdeptype$package$.eg(pathdeptype.scala:17)
        at eg.main(pathdeptype.scala:11)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at dotty.tools.runner.RichClassLoader$.run$extension$$anonfun$1(ScalaClassLoader.scala:36)
        at dotty.tools.runner.ScalaClassLoader$.asContext(ScalaClassLoader.scala:80)
        at dotty.tools.runner.RichClassLoader$.dotty$tools$runner$RichClassLoader$$$asContext$extension(ScalaClassLoader.scala:18)
        at dotty.tools.runner.RichClassLoader$.run$extension(ScalaClassLoader.scala:36)
        at dotty.tools.runner.CommonRunner.run(ObjectRunner.scala:23)
        at dotty.tools.runner.CommonRunner.run$(ObjectRunner.scala:13)
        at dotty.tools.runner.ObjectRunner$.run(ObjectRunner.scala:48)
        at dotty.tools.runner.CommonRunner.runAndCatch(ObjectRunner.scala:30)
        at dotty.tools.runner.CommonRunner.runAndCatch$(ObjectRunner.scala:13)
        at dotty.tools.runner.ObjectRunner$.runAndCatch(ObjectRunner.scala:48)
        at dotty.tools.MainGenericRunner$.run$1(MainGenericRunner.scala:215)
        at dotty.tools.MainGenericRunner$.process(MainGenericRunner.scala:270)
        at dotty.tools.MainGenericRunner$.main(MainGenericRunner.scala:281)
        at dotty.tools.MainGenericRunner.main(MainGenericRunner.scala)

Type of Coord depends on the Board instance which instantiated the Coord.
ie, Coord type depends on Board value.

The name is 'path-dependent type' because type depends 'selector path' through objects. ʳ

See:

match .. case

Example from here:

val suffix = (age % 100) match
  case 11 | 12 | 13 => "th"
  case _ => (age % 10) match
    case 1 => "st"
    case 2 => "nd"
    case 3 => "rd"
    case _ => "th"

Predefs: require, assert, etc

Useful to represent invariants that is difficult to represent using types.

More: ensuring, assume, implicitly

See:

More

Emacs