dottyのドキュメントにある新機能を一通り試す(dotty-0.11.0-RC1)

# やることとか前提

* [Dotty Documentation](http://dotty.epfl.ch/docs/) の Reference 項の内容を頭から順番にやっていきます
    * 対象のdottyバージョンは dotty-0.11.0-RC1 です
    * 対象ドキュメントは、2018/12/03 時点のウェブサイトのものです。
        * が、2018/10 中旬に一度作ったのモノに追記して作っているので、古くなっている部分があるかもしれません
* サンプルコードは、ドキュメントそのままのモノと、独自に書いたモノが混ざっています
* コンパイル・実行可能なコードは、[githubのリポジトリ](https://github.com/seraphr/sandbox/tree/master/dotty)から取得可能です
    * この記事を書いているタイミングのgit hashは[673ed88640bf](https://github.com/seraphr/sandbox/tree/673ed88640bf4f867066fb9042c53d534a87b6d2/dotty)です

# New Types
## Literal Singleton Types

http://dotty.epfl.ch/docs/reference/singleton-types.html

何故かドキュメントへのリンクが目次に見当たりませんでした。
リテラルを、型として取り扱う事ができます。

```scala
object LiteralSingletonTypes {
  val t: 42 = 42
  var x: "Jedi" = "Jedi"

  trait Mat[N <: Singleton, M <: Singleton] {
    def add(aThat: Mat[N, M]): Mat[N, M]
  }

  val m1: Mat[2, 3] = ???
  val m2: Mat[2, 3] = ???
  val m3: Mat[4, 3] = ???

  m1.add(m2)
  // m1.add(m3) // コンパイルエラー
}
```

## Intersection Types

http://dotty.epfl.ch/docs/reference/intersection-types.html

`A`型でも`B`型でもある型を表します。
[`with`は`&`と等価となり、そのうち消える](http://dotty.epfl.ch/docs/reference/intersection-types-spec.html#relationship-with-compound-type-with)らしい。

```scala
object IntersectionTypes {
  trait A
  trait B

  // with も残るが、deprecatedになって、そのうち消える
  def withAB(ab: A with B): Unit = ()
  def withBA(ba: B with A): Unit = ()
  def andAB(ab: A & B): Unit = ()
  def andBA(ba: B & A): Unit = ()
}
```

## Union Types

http://dotty.epfl.ch/docs/reference/union-types.html

`A`型であるか、`B`型である型を表します。
残念ながら、現状`literal type + union type` は現状エラーとなります。[^1]

[^1]: 許すと、unsoundになるらしい…？ https://github.com/lampepfl/dotty/issues/1551

```scala
object UnionTypes {
  def method(a: Int | String): Unit = a match {
    case i: Int => println("int!")
    case s: String => println("string!")
  }

  // Singleton type Int(2) is not allowed in a union type
  // def method2(a: 1 | 2): Unit = ()
}
```

## Type Lambdas

http://dotty.epfl.ch/docs/reference/type-lambdas.html

`({type C[A] = Map[String, A]})#C` という記法から開放されます。
個人的には、上記記法では直接表現できなかった、`任意の型で型引数一つを埋める`ことが出来るようになったのが注目点（下記の`Map2`やMap`3`や`State#St`）。

```scala
object TypeLambdas {
  type Map0[K, V] = Map[K, V]
  type Map1 = [K, V] => Map[K, V]
  type Map2[K] = [V] => Map[K, V]
  type Map3 = [K] => [V] => Map[K, V]
}

object RunState {
  def main(args: Array[String]): Unit = {
    val tState: State.St[String][Int] = State {s => (s, 1)}
    val tInt = Functor.map(tState)(_ + 1).run("")._2
    println(tInt) // 2
  }
}

trait Functor[F[_]] {
  def map[A, B](fa: F[A])(f: A => B): F[B]
}

object Functor {
  def map[F[_]: Functor, A, B](fa: F[A])(f: A => B): F[B] = implicitly[Functor[F]].map(fa)(f)
}

case class State[S, A](run: S => (S, A))
object State {
  type St[S] = [A] => State[S, A]
  implicit def stateFunctor[S]: Functor[St[S]] = new Functor[St[S]] {
    def map[A, B](fa: St[S][A])(f: A => B): St[S][B] = State { s0 =>
      val (s1, a) = fa.run(s0)
      (s1, f(a))
    }
  }
}
```

## Match Types

http://dotty.epfl.ch/docs/reference/match-types.html

`type member`の引数ごとに、違う型を返すことが出来ます。
現行のScalaでも、型クラスを使うと似たようなことが出来ましたが、より直接的に表現できるようになります。

```scala
object MatchTypes {
  type Elem[X] = X match {
    case String => Char
    case Array[t] => t
    case Iterable[t] => t
  }

  //  Elem[String]       =:=  Char
  //  Elem[Array[Int]]   =:=  Int
  //  Elem[List[Float]]  =:=  Float
  //  Elem[Nil]          =:=  Nothing
}
```

再帰的に`match`することも可能です。

```scala
object RecursiveMatchTypes {
  // Tupleの結合
  type Concat[+Xs <: Tuple, +Ys <: Tuple] <: Tuple = Xs match {
    case Unit => Ys
    case x *: xs => x *: Concat[xs, Ys]
  }

  val t1: Concat[(String, Int), Unit] = ("a", 1)
  val t2: Concat[(String, Int), (String, Int)] = ("a", 1, "b", 2)

  // 独自Tupleでもやってみる
  sealed trait MyTuple
  class **:[A, B <: MyTuple] extends MyTuple
  object MyNil extends MyTuple

  // Tupleの一番右の型を取り出す
  type Last[X <: MyTuple] = X match {
    case h **: MyNil.type => h
    case h **: t => Last[t]
  }

  val double: Last[Int **: String **: Double **: MyNil.type] = 1.0
}
```

## Implicit Function Types

http://dotty.epfl.ch/docs/reference/implicit-function-types.html

`implicitな引数を持つ関数`を型で表すことができるようになります。

```scala
object ImplicitFunctionTypes {
  type ImplicitFunc = implicit String => Int
 
  def method(f: ImplicitFunc): Int = f("hoge")

  val result = method {
    // 暗黙的に、"hoge"が渡ってきている
    implicitly[String].length
  }
}
```

これを利用すると、暗黙的なコンテキストをimplicitに渡して動作するDSLを書きやすくなります。

```scala
object RunTableDSL {
  def main(args: Array[String]): Unit = {
    import TableDSL._

    val tTable = table {
      row {
        cell("1-1")
        cell("1-2")
        cell("1-3")
      }

      // cell("aa") // rowの外でcellを呼ぶと、implicitなRowが無いのでコンパイルエラー

      row {
        cell("2-1")
        cell("2-2")
        cell("2-3")
      }
    }

    println(tTable)
    // Table(
    //   Row(1-1       1-2     1-3)
    //   Row(2-1       2-2     2-3)
    // )
  }
}

object TableDSL {
  import scala.collection.mutable.ArrayBuffer
  type TableF = implicit Table => Table
  type RowF = implicit Row => Row

  def table(f: TableF): Table = {
    f(new Table)
  }

  def row(f: RowF)(implicit t: Table): Table = {
    t.addRow(f(new Row))
    t
  }

  def cell(s: String)(implicit r: Row): Row = {
    r.addCell(Cell(s))
    r
  }

  class Table {
    private val mRows = new ArrayBuffer[Row]

    def addRow(aRow: Row): this.type = {
      mRows += aRow
      this
    }

    override def toString(): String = {
      def rows = mRows.mkString("\n")

      s"Table(\n${rows}\n)"
    }
  }
  class Row {
    private val mCells = new ArrayBuffer[Cell]
    def addCell(aCel: Cell): this.type = {
      mCells += aCel
      this
    }

    override def toString(): String = {
      s"  Row(${mCells.map(_.v).mkString("\t")})"
    }
  }

  case class Cell(v: String)
}
```

## Dependent Function Types

http://dotty.epfl.ch/docs/reference/dependent-function-types.html

`method dependent types`に対応する記述が、関数型で可能となります。

```scala
object DependentFunctionTypes {
  trait Container {
    type Elem
    val get: Elem
  }

  def getElem(c: Container): c.Elem = c.get
  val getElemF: (c: Container) => c.Elem = _.get

  case class StringC(get: String) extends Container {
    type Elem = String
  }

  getElem(StringC("hoge")): String
  getElemF(StringC("fuga")): String
}
```

# Enums

## Enumerations

http://dotty.epfl.ch/docs/reference/enums/enums.html

列挙型が追加されます。

```scala
object Enums {
  enum Color {
    case Red, Green, Blue
  }

  // 大体以下と同じ
  sealed trait Color2
  object Color2 {
    case object Red extends Color2
    case object Green extends Color2
    case object Blue extends Color2
  }
}
```

列挙型には、いくつかの便利メソッドが定義されています。

```scala
object RunEnums {
  def main(args: Array[String]): Unit = {
    // enumValues などの便利メソッドが生えている
    Enums.Color.enumValues.foreach { e =>
      println(s"enum: ${e}, tag: ${e.enumTag}")
    }
    // enum: Red, tag: 0
    // enum: Green, tag: 1
    // enum: Blue, tag: 2

    
    Enums.Color.enumValue.foreach { (i, e) =>
      println(s"i: ${i}, enum: ${e}, tag: ${e.enumTag}")
    }
    // i: 0, enum: Red, tag: 0
    // i: 1, enum: Green, tag: 1
    // i: 2, enum: Blue, tag: 2


    Enums.Color.enumValueNamed.foreach { (n, e) =>
      println(s"name: ${n}, enum: ${e}, tag: ${e.enumTag}")
    }
    // name: Red, enum: Red, tag: 0
    // name: Green, enum: Green, tag: 1
    // name: Blue, enum: Blue, tag: 2

  }
}
```

## Algebraic Data Types

http://dotty.epfl.ch/docs/reference/enums/adts.html

`enum`を用いて、代数的データ型の記述を楽にすることができるようになります。

```scala
// 代数的データ型
object AlgebraicDataTypes {
  enum Option[+T] {
    case Some(x: T)
    case None
  }

  // 大体以下と同じ
  trait Option2[+T]
  object Option2 {
    case class Some[T](t: T) extends Option2[T]
    case object None extends Option2[Nothing]
  }
}
```

# Other New Features

## Multiversal Equality

http://dotty.epfl.ch/docs/reference/multiversal-equality.html

`==`による比較が、`Eq`型クラスによる比較に変更されます。
デフォルトでは、`eqAny`によって、現状と同じ挙動となります。[^2]

[^2]: とドキュメントには書いてあるが、現状の挙動は、常にstrictに見える

```scala
object MultiversalEquality {
  // import scala.language.strictEquality
  // ドキュメントによると↑をimportしない限り eqAnyが有効らしいんだけど、
  // 関係なく無効になってるっぽい
  implicit def eqAny[A, B]: Eq[A, B] = scala.Eq.eqAny[A, B]
  val t1 = "1" == 1 // Values of types String and Int cannot be compared with == or !=
  val t2 = 1 == 1
}
```

## Trait Parameters

http://dotty.epfl.ch/docs/reference/trait-parameters.html

trait がコンストラクタ引数を受け取れるようになります。

```scala
object TraitParameters {
  trait Greeting(val name: String) {
    def msg = s"How are you, $name"
  }

  class C(val s: String) extends Greeting(s) {
    println(msg)
  }
}
```

これによって、`traitの型引数が、型クラスのインスタンスになっている`という制約を（protected valなどにせず）直接書けるようになります。

```scala
object TraitParameters2 {
  trait Functor[F[_]] {
    def map[A, B](fa: F[A])(f: A => B): F[B]
  }
  object Functor {
    def map[F[_]: Functor, A, B](fa: F[A])(f: A => B): F[B] = implicitly[Functor[F]].map(fa)(f)
  }

  trait FunctorParam[F[_]: Functor] {
    def map[A, B](fa: F[A])(f: A => B): F[B] =
      Functor.map(fa)(f)
  }
}
```

## Inline

http://dotty.epfl.ch/docs/reference/inline.html

これまでの、`@inline`アノテーションよりも強力な、`inline`キーワードが追加されました。
`inline`は`val`と`def`の両方に宣言可能です。

```scala
object Inline {
  // inline val の右側は定数式でなければならない
  inline val flag = false
  // right-hand side of inline value readLine must be a constant expression
  // inline val readLine = System.in.read()

  inline def checkFlag[T](ifTrue: =>T, ifFalse: =>T): T = {
    if(flag) ifTrue else ifFalse
  }

  inline def inlineArg(inline v: Int): Int = v + 2
  val v = inlineArg(4)
  // argument to inline parameter must be a constant expression
  // inlineArg("4".toInt)
}
```

`inline`の展開は、単純なインライン展開でなく、コンパイラが必要なところだけを残してくれます。

```scala
object InlinePow {
  inline def power(x: Double, n: Int): Double =
    if (n == 0) 1.0
    else if (n == 1) x
    else {
      val y = power(x, n / 2)
      if (n % 2 == 0) y * y else y * y * x
    }

  def expr = "10.0".toDouble
  val pow10_10 = power(expr, 10)
  // 以下のようなコードにコンパイルされる
  // double x = expr();
  // double y = x;
  // double y = y * y;
  // double y = y * y * x;
  // this.pow10_10 = (y * y);
}
```

## Principled Meta Programming

http://dotty.epfl.ch/docs/reference/principled-meta-programming.html

`'`、`~`を用いた、コンパイル時メタプログラミングが追加されます。
`'`により、通常の値を`Expr`に変換します。
`~`により、`Expr`を通常の値に変換します。 [^3]

[^3]: ただし、メタ世界でしか利用できない

```scala
object MetaPrograming {
  import scala.quoted._

  def booleanExpr: Expr[Boolean] = '(true)
  inline def trueImpl = ~booleanExpr

  val tBooleanType: Type[Boolean] = '[Boolean]
  inline def trueOrFalse: Boolean = ~trueOrFalseImpl
  def trueOrFalseImpl: Expr[Boolean] = '{
    type Bool = ~tBooleanType
    val tTrue: Bool = true
    tTrue || false
  }
  
  // splice outside quotes or inline method
  // val tBool = ~tBooleanExpr
  // type Bool = ~tBooleanType
}
```

これを用いて、これまでの`def`マクロと比べて、遥かに簡単に、マクロを定義できます。
以下の例では、`map`メソッドを、ループで構築し、インライン展開するようなマクロを定義しています。

```scala
object MetaListMap {
  import scala.quoted._
  inline def map[A, B](aList: List[A])(f: A => B): List[B] = {
    ~mapImpl('[B], '(aList), '(f))
  }

  private def mapImpl[A: Type, B](
      aTB: Type[B],
      aList: Expr[List[A]], 
      f: Expr[A => B]) = '{

        var tList = ~aList
        val tLen = tList.length
        val tBuffer = new scala.collection.mutable.ListBuffer[~aTB]
        while(tList.nonEmpty) {
          tBuffer.append(~f('(tList.head)))
          tList = tList.tail
        }

        tBuffer.result
      }
}
```

```scala
object UseMetaListMap {
  def baseList = List(1,2,3)
  def mappedList = MetaListMap.map(baseList)(_ + 2)

  def main(args: Array[String]): Unit = {
    println(mappedList)
    // List(3, 4, 5)
  }
}
```

<details>
<summary>javap結果（長いので折りたたみ）</summary><div>

```
// mapがループで構成されている
//  public scala.collection.immutable.List<java.lang.Object> mappedList();
//     Code:
//        0: aload_0
//        1: invokevirtual #47                 // Method baseList:()Lscala/collection/immutable/List;
//        4: astore_1
//        5: aload_0
//        6: invokedynamic #64,  0             // InvokeDynamic #0:apply$mcII$sp:(Ljp/seraphr/sandbox/dotty/UseMetaListMap$;)Lscala/compat/java8/JFunction1$mcII$sp;
//       11: astore_2
//       12: aload_1
//       13: astore_3
//       14: aload_3
//       15: invokeinterface #70,  1           // InterfaceMethod scala/collection/LinearSeqOptimized.length:()I
//       20: istore        4
//       22: new           #72                 // class scala/collection/mutable/ListBuffer
//       25: dup
//       26: invokespecial #73                 // Method scala/collection/mutable/ListBuffer."<init>":()V
//       29: astore        5
//       31: aload_3                           *** if(tList.nonEmpty)
//       32: invokeinterface #79,  1           // InterfaceMethod scala/collection/TraversableOnce.nonEmpty:()Z
//       37: ifeq          90                  
//       40: aload         5                   *** このあたりから、appendの引数になるArray作成
//       42: getstatic     #32                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
//       45: iconst_1
//       46: newarray       int
//       48: dup
//       49: iconst_0
//       50: aload_3
//                                             *** start f(tList.head)
//       51: invokevirtual #85                 // Method scala/collection/immutable/List.head:()Ljava/lang/Object;
//       54: invokestatic  #91                 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
//       57: istore        6
//       59: aload_2
//       60: iload         6
//       62: invokestatic  #95                 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
//       65: invokeinterface #100,  2          // InterfaceMethod scala/Function1.apply:(Ljava/lang/Object;)Ljava/lang/Object;
//                                             *** end f(tList.head)
//       70: invokestatic  #91                 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
//       73: iastore
//       74: invokevirtual #38                 // Method scala/LowPriorityImplicits.wrapIntArray:([I)Lscala/collection/mutable/WrappedArray;
//                                             *** ここまで、appendのArray作成
//       77: invokeinterface #106,  2          // InterfaceMethod scala/collection/mutable/BufferLike.append:(Lscala/collection/Seq;)V
//       82: aload_3
//       83: invokevirtual #109                // Method scala/collection/immutable/List.tail:()Lscala/collection/immutable/List;
//       86: astore_3
//       87: goto          31                  *** ループ  
//       90: aload         5
//       92: invokevirtual #112                // Method scala/collection/mutable/ListBuffer.result:()Lscala/collection/immutable/List;
//       95: areturn
```

</div>
</details>

## TASTy Reflect

http://dotty.epfl.ch/docs/reference/tasty-reflect.html

`Principled Meta Programming`だけでは不可能な、構文木の分解と構築を可能とします。


```scala
object TastyReflect {
  import scala.quoted._
  import scala.tasty._

  inline def natConst(x: Int): Int = ~natConstImpl('(x))

  def natConstImpl(x: Expr[Int])(implicit reflection: Reflection): Expr[Int] = {
    import reflection._
    // ドキュメント上は unseal になっている。 最近のコミット( 1af9030c8a01727d )で unseal になったっぽい
    val xTree: Term = x.reflect
    xTree match {
      case Term.Literal(Constant.Int(n)) =>
        if (n <= 0)
          throw new QuoteError("Parameter must be natural number")
        n.toExpr
      case _ =>
        throw new QuoteError("Parameter must be a known constant")
    }
  }
}
```

```scala
object NatConst {
  val one = TastyReflect.natConst(1)

  // コンパイルエラー Parameter must be natural number
  // val error = TastyReflect.natConst(0)
}

// 以下のような感じのコードになる
// public final class NatConst$
// {
//   private final int one;
//   public int one()
//   {
//     return this.one;
//   }
//   public NatConst$()
//   {
//     this.one = 1;
//   }
// }
```

また、dottyがコンパイル時に出力しているtastyファイルに対してアクセスすることも可能です。
ただし、実行時の依存ライブラリに、`dotty-compiler`が必要になります。

```scala
// InspectTastyFile 用 object
// コンパイル単位をわけないと、no class file was found
object Hoge {
  val fuga = 1
}
```

```scala
object InspectTastyFile {
  import scala.tasty._
  import scala.tasty.file._

  class Consumer extends TastyConsumer {
    final def apply(reflect: Reflection)(root: reflect.Tree): Unit = {
      import reflect._
      println(root.showCode)
    }
  }
}

object InspectTastyFileMain {
  // Windows では、ファイルパスの取り扱いに失敗するらしく実行時エラー
  def main(args: Array[String]): Unit = {
    import scala.tasty.file._
    import InspectTastyFile.Consumer
    ConsumeTasty("", List("jp.seraphr.sandbox.dotty.Hoge"), new Consumer)

    // 以下がprintされる
    // package sandbox.dotty {
    //   object Hoge {
    //     val fuga: scala.Int = 1
    //   }
    // }
    
  }
}
```

## Opaque Type Aliases

http://dotty.epfl.ch/docs/reference/opaques.html

別の型として取り扱われる、type aliasが追加されます。

```scala
object OpaqueTypeAliases {
  // opaque type は、コンパニオンオブジェクト内でのみ、同じ型とみなされる
  opaque type UserId = String
  object UserId {
    def apply(base: String): UserId = base

    implicit class UserIdOps(id: UserId) {
      def asString: String = id
    }
  }

  opaque type ItemId = String
  object ItemId {
    def apply(base: String): ItemId = base

    implicit class UserIdOps(id: ItemId) {
      def asString: String = id
    }
  }
}

object UserOpaqueType {
  import OpaqueTypeAliases._
  val tString = "string"
  val tUserId = UserId("user1")
  val tItemId = ItemId("item1")

  // コメントアウトしているものはコンパイルエラー
  val tId1: UserId = tUserId
  // val tId2: String = tUserId
  // val tId3: ItemId = tUserId
  // val tId4: UserId = tItemId
  // val tId5: String = tItemId
  val tId6: ItemId = tItemId
  // val tId7: UserId = tString
  val tId8: String = tString
  // val tId9: ItemId = tString
  val tId10: String = tUserId.asString
  val tId11: String = tItemId.asString
}

```

## Implicit By-Name Parameters

http://dotty.epfl.ch/docs/reference/implicit-by-name-parameters.html

メソッドのimplicit引数を、名前呼びにすることが出来るようになります。
現状では、implicit探索が発散してしまうようなパターンの一部がコンパイル可能となります。

```scala
// scala 2.13にも入る
object ImplicitByNameParameters {
  trait Foo {
    def next: Foo
  }

  // rec を by-nameにしないとコンパイルエラー
  // in dotty 0.10
  // object Foo produces a diverging implicit search

  // in scala 2.12.6
  //  diverging implicit expansion for type ImplicitByNameParameters.Foo
  object Foo {
    implicit def foo(implicit rec: =>Foo): Foo =
      new Foo { def next = rec }
  }

  val foo = implicitly[Foo]
  def main(args: Array[String]): Unit = {
    println(foo == foo.next) // false
  }
}
```

## Automatic Tupling of Function Parameters

http://dotty.epfl.ch/docs/reference/auto-parameter-tupling.html
http://dotty.epfl.ch/docs/reference/auto-parameter-tupling-spec.html

`case` でパターンマッチをしなければならなかった、パターンの一部が`case`なしで書けるようになります。

```scala
object AutoParameterTupling {
  val tList = List((1,2), (2,3), (3,4))

  val tOld = tList.map {
    case (l, r) => l + r
  }

  // scala 2ではコンパイルエラー
  val tNew = tList.map {
    (l, r) => l + r
  }
  val tNew2 = tList.map(_ + _)

  // こちらは駄目
  // val f: (Int, Int) => Int = _ + _
  // tList.map(f)
}
```

## Named Type Arguments

http://dotty.epfl.ch/docs/reference/named-typeargs.html

メソッドの名前付き引数のように、名前を指定して型引数を埋めることが出来るようになります。

```scala
object NamedTypeArguments {
  def construct[Elem, Coll[_]](xs: Elem*): Coll[Elem] = ???

  val xs2 = construct[Coll = List, Elem = Int](1, 2, 3)

  // 一部だけ指定して残りを推論させられる！！
  val xs3 = construct[Coll = List](1, 2, 3)
}
```

## Erased Terms

http://dotty.epfl.ch/docs/reference/erased-terms.html

コンパイル時にのみ必要となる、implicit引数を、除去した状態でコンパイル出来るようになります。

```scala
object ErasedTerms {
  trait ON
  trait OFF

  case class Switch[S]() {
    def on(implicit erased ev: =:=[S, OFF]) = Switch[ON]()
    def off(implicit erased ev: S =:= ON) = Switch[OFF]()
  }

  Switch[OFF]()
    .on
    .off
    
  // コンパイル結果は以下のように evが消えている
  // ErasedTerms.Switch..MODULE$.apply().on().off();

  // erased 無しだと
  // ErasedTerms.Switch..MODULE$.apply()
  // .on(Predef..eq.colon.eq..MODULE$.tpEquals())
  // .off(Predef..eq.colon.eq..MODULE$.tpEquals());

}
```

## Kind Polymorphism

http://dotty.epfl.ch/docs/reference/kind-polymorphism.html

あらゆるkind[^4]の型を受け取る型引数を宣言出来るようになります。

[^4]: 型引数の数

```scala
// "-Ykind-polymorphism" が必要
object KindPolymorphism {
  trait Foo[+A <: AnyKind] {
    def rank: Int
  }

  case class FooImpl(rank: Int) extends Foo[Nothing]
  case class Triple[A, B, C]()

  object Foo {
    implicit def foo1: Foo[List] = FooImpl(1)
    implicit def foo2: Foo[Map] = FooImpl(2)
    implicit def foo3: Foo[Triple] = FooImpl(3)
  }

  def foo[A <: AnyKind](implicit ev: Foo[A]): Int = ev.rank

  def main(args: Array[String]): Unit = {
    println(foo[List])    // => 1
    println(foo[Map])     // => 2
    println(foo[Triple])  // => 3
  }
}
```

# Changed Features

## Lazy Vals

http://dotty.epfl.ch/docs/reference/changed/lazy-vals.html

`lazy val`に対して、スレッドセーフな実装が生成されなくなります。

```scala
object VolatileLazyVals {
  // lazy val がスレッドセーフじゃなくなりました
  lazy val hoge = 10
  
  // thread safeにしたいときは volatileつけましょう
  @volatile
  lazy val fuga = 10
}
```

## Programmatic Structural Types

http://dotty.epfl.ch/docs/reference/changed/structural-types.html

JavaVM以外のプラットフォームで、うまく構造的部分型が取り扱えなかった問題に対応するため、構造的部分型が、Javaのリフレクションに依存したものから、より抽象的なものに分離されました。
構造的部分型は、`Selectable`型に依存するようになります。

```scala
object StructuralTypes {
  // JavaVM以外のプラットフォームで、うまく構造的部分型が取り扱えなかった問題に対応するため
  // 構造的部分型が、Javaのリフレクションに依存したものから、より抽象的なものに分離されました。
  // implicit に Selectable が見えていないと、コンパイルエラーになります。
  import scala.reflect.Selectable.reflectiveSelectable

  // Selectableは以下のような型
  // trait Selectable extends Any {
  //   def selectDynamic(name: String): Any
  //   def selectDynamicMethod(name: String, paramClasses: ClassTag[_]*): Any =
  //     new UnsupportedOperationException("selectDynamicMethod")
  // }

  type HasClose = {
    def close(): Unit
  }

  class Hoge {
    def close(): Unit = ()
  }

  val tHoge: HasClose = new Hoge
  tHoge.close()
}
```

## Changes in Type Checking

http://dotty.epfl.ch/docs/reference/changed/type-checking.html

ドキュメントが空っぽなので、謎。

## Changes in Type Inference

http://dotty.epfl.ch/docs/reference/changed/type-inference.html

ドキュメントが空っぽなので、謎。
だけど、いくつか把握しているものがあるので列挙します。

### method independent typeが、同じ引数リスト内で使えるようになった

```scala
  object MethodIndependentType {
    trait A {
      type T
    }

    object B extends A {type T = String}
    object C extends A {type T = Int}

    def method(a: A, t: a.T): Unit = ()
    method(B, "")
    method(C, 1)
  }
```
### 同じ引数リスト内で、前の引数の推論結果を使用可能になった

```scala
  object SameArgList {
    def foldLeft[A, B](c: List[A], zero: B, f: (B, A) => B): B = ???

    // scala2.12 ではコンパイルエラー missing parameter type
    foldLeft(List(1), "", _ + _)
  }
```

### 別の後ろの引数リストでの型推論結果が、前の引数リストにフィードバックされるようになった

```scala
  object LubDiffArgList {
    def fold[A, B](o: Option[A])(zero: B)(f: A => B): B = ???

   // scala2.12 ではコンパイルエラー error: type mismatch
    val list = fold(Option(1))(Nil)(List(_))
  }
```

### さようなら AUXパターン

```scala
  // さようなら AUXパターン
  object ByeByeAuxPattern {
    trait HasSize[A] {
      type Size
      def size(a:A): Size
    }

    trait Monoid[A] {
      val zero: A
      def append(l: A, r: A): A
    }

    // scala2.12 ではコンパイルエラー error: illegal dependent method type
    def method[A](a1: A, a2: A)(implicit S: HasSize[A], M: Monoid[S.Size]): S.Size =
      M.append(S.size(a1), S.size(a2))
  }
```

## Changes in Implicit Resolution

http://dotty.epfl.ch/docs/reference/changed/implicit-resolution.html

### メンバの implicit val には、型を明示しないといけない

```scala
implicit val hoge: Int = 10
```

### スコープのネストが、探索順位に影響するようになった

```scala
  // scala2.12 ではコンパイルエラー
  trait Z
  def f(implicit i: Z) = {
    def g(implicit j: Z) = {
      implicitly[Z]
    }
  }
```

### implicit探索の失敗伝播

再帰的なimplicit 探索で、implicitな候補が複数見つかって失敗した時に、その失敗が伝播するようになりました。
以下の`implicitly[C]`は scala 2.12ではコンパイルが通る（def cが選ばれる）が、dottyではエラーとなります。

```scala
  trait I {
    class A
    class B extends C
    class C
    implicit def a1: A
    implicit def a2: A
    implicit def b(implicit a: A): B
    implicit def c: C

    // implicitly[C]

    // 上記の影響で、「Aが失敗したらBが成功する」というのが実現できなくなったためか、Notが導入
    // らしいが、scala2でうまく行って、dottyでうまく行かない、具体例が作れなかった…
    implicitly[scala.implicits.Not[C]]
  }
```

### implicit searchが発散した場合の取り扱いが変わった

implicit searchが発散した場合（implicitの展開が再帰的に行われてしまうような場合など）の失敗が、通常の探索の失敗と同じ扱いになりました(= 他の候補の探索を継続する)。
scala 2では発散した場合（殆どの場合）失敗していた。[^5]

[^5]: らしいが、scala2でうまく行いかなくて、dottyでうまく行く、具体例が作れなかった…


## Implicit Conversions

http://dotty.epfl.ch/docs/reference/changed/implicit-conversions.html
http://dotty.epfl.ch/docs/reference/changed/implicit-conversions-spec.html

`abstract class ImplicitConverter[-T, +U] extends Function1[T, U]`が導入され、型の暗黙的変換は、`ImplicitConverter`が無いとダメになりました。
と以前のドキュメントには書いてあったんだけど、2018/12/03時点のドキュメント見ると、また変わりそう？
とりあえず、`0.11.0-RC1`時点では、まだ挙動は変わってなさそう？

```scala
object ImplicitConversions {

  import scala.language.implicitConversions
  // def ng(implicit ev: Int => String): String = 10
  def ok(implicit ev: ImplicitConverter[Int, String]): String = 10
}
```

## Vararg Patterns

http://dotty.epfl.ch/docs/reference/changed/vararg-patterns.html

可変長のパターンマッチの記法が変わりました。
また、パターンマッチの定義時、`unapplySeq`と同じことが、`unapply`で出来るようになりました。

```scala
object VarargPatterns {
  
  List(1,2,3,4) match {
    // case List(1,2, _*) => 
    // case List(1,2, xs @ _*) => 
    case List(1,2, _: _*) => 
    case List(2,3, xs: _*) => 
    case _ =>
  }

  // unapplyで unapplySeqと同じことができるようになった
  class Person(val name: String, val children: Person *)
  object Person {
    def unapply(p: Person) = Some((p.name, p.children))
    // def unapplySeq(p: Person) = Some((p.name, p.children))
  }
  def childCount(p: Person) = p match {
    case Person(_, ns : _*) => ns.length
  }
}
```

## Option-less pattern matching

http://dotty.epfl.ch/docs/reference/changed/pattern-matching.html

パターンマッチの定義時の制約が全般に緩くなりました。
ただ、ドキュメントによると、また（よりシンプルに）変わりそうな雰囲気？

### boolean パターン

```scala
  // unapplyでBooleanを返す
  object Even {
    def unapply(s: String): Boolean = s.size % 2 == 0
  }
```

### Product Pattern

```scala
  // unapplyでProductを継承して def / valで_Nの名前を持つオブジェクトを返す
  class FirstChars(s: String) extends Product {
    def _1 = s.charAt(0)
    def _2 = s.charAt(1)

  // Not used by pattern matching: Product is only used as a marker trait.
    def canEqual(that: Any): Boolean = ???
    def productArity: Int = ???
    def productElement(n: Int): Any = ???
  }
  object FirstChars {
    def unapply(s: String): FirstChars = new FirstChars(s)
  }
```

### Name-based Seq Pattern

```scala
  // unapplySeqで以下のXを取得できるオブジェクトを返す
  type T1
  type T2 <: T1
  type T3 <: T1
  type X = {
    def lengthCompare(len: Int): Int // or, `def length: Int`
    def apply(i: Int): T1
    def drop(n: Int): scala.Seq[T2]
    def toSeq: scala.Seq[T3]
  }
  object CharList {
    def unapplySeq(s: String): Option[Seq[Char]] = Some(s.toList)
  }
```

### Name-based Pattern

```scala
  // unapplyで isEmpty と get を持っているオブジェクトを返す
  // もしくは isEmptyと _N を持っているオブジェクトを返す
  class Nat(val x: Int) {
    def get: Int = x
    def isEmpty = x < 0
  }
```

## Automatic Eta Expansion

http://dotty.epfl.ch/docs/reference/changed/eta-expansion.html

eta-expansion時の`_`が不要になりました。
ただし、空の引数リストを持つメソッドは、自動展開されません。

```scala
object EtaExpansion {
  // _ が要らなくなった。　将来的にdeprecatedになる

  def m(x: Boolean, y: String)(z: Int): List[Int] = List()
  val f1 = m                // (Boolean, String) => Int => List[Int]
  val f2 = m(true, "abc")   // Int => List[Int]

  // 空の引数リストのメソッドは、自動的には展開されない
  // Auto-Applicationと競合するため
  def m2(): Int = 10
  // val f3 = m2
}
```

## Changes in Compiler Plugins

http://dotty.epfl.ch/docs/reference/changed/compiler-plugins.html

省略

# Dropped Features

## Delayedinit

http://dotty.epfl.ch/docs/reference/dropped/delayed-init.html

`DelayedInit`がなくなり、それに伴い`App`クラスも、旧`Application`クラス相当のモノになります。[^6]

[^6]: コマンドライン引数にアクセス出来ない & JIT効かない

そのため、普通に `main`メソッドを定義しましょう。

## Macros

http://dotty.epfl.ch/docs/reference/dropped/macros.html

今までのマクロは消えます。
`inline`によるマクロが実装されました。
また、コンパイル前のソースコードを生成を行う`meta`キーワードによるメタプログラミングが、[Scalameta](https://scalameta.org/)で実装されます。[^7]

[^7]: 2018/10 時点で軽く調べた範囲だと、本当にどうなるのかはよく分からなかった…

## Existential Types

http://dotty.epfl.ch/docs/reference/dropped/existential-types.html

`forSome`による存在型がなくなり、`_`による、ワイルドカードのみとなります。

```scala
object ExistentialTypes {
  // _ のみになる
  type A = List[_]

  // 一応 forSomeがなくなるとできなくなることはあるが、まず困らない
  // 以下は、Scala 2.12のコードだが、 これの T1が定義できなくなる
  // trait C[A] {
  //   def accept(a: A): Unit = ()
  // }
  // case object C1 extends C[Int]
  
  // type T1 = C[C[A]] forSome { type A }
  // type T2 = C[C[A] forSome { type A }] // == C[C[_]]
  
  // def t1: Unit = {
  //   val v: T1 = ???
  //   v.accept(C1) // type mismatch;  found: C1.type  required: C[A]
  // }
  
  // def t2: Unit = {
  //   val v: T2 = ???
  //   v.accept(C1) // OK
  // }
}
```

## General Type Projection

http://dotty.epfl.ch/docs/reference/dropped/type-projection.html

abstract type に対する type projectionが禁止されます。[^8]

[^8]: unsoundとのこと。 https://github.com/lampepfl/dotty/issues/1050

```scala
object GeneralTypeProjection {
  type A = {type X}
  trait B {type X}
  class C {type X}
  type D = C

  trait Hoge[AA <: A, BB <: B, CC <: C, DD <: D] {
    type AX = A#X
    type BX = B#X
    type CX = C#X
    type DX = D#X

    // 以下は全てダメ scala2.12では全部OK
    //type AAX = AA#X
    //type BBX = BB#X
    //type CCX = CC#X
    //type DDX = DD#X
  }
}
```

## Procedure Syntax

http://dotty.epfl.ch/docs/reference/dropped/procedure-syntax.html

ついに、Procedure Syntaxが消えます。[^9]

[^9]: scalaを触り始めた2011年には既に非推奨だったな…

```scala
object ProcedureSyntax {
  // def hoge {}
  def hoge = {}
}
```

## Early Initializers

http://dotty.epfl.ch/docs/reference/dropped/early-initializers.html

おそらく、使ったことのある人がめちゃくちゃ少ない`Early Initializers`が消えます。
`trait parameters`を使いましょう。

```scala
object EarlyInitializers {
  // 初期化順序をいじる構文。
  // trait parameters 使えば良い


  trait A {
    val a: String
    val b = a // 普通に継承すると、bがnullになる！
  }
  // class C extends { val a = "hoge"} with A
}
```

## Class Shadowing

http://dotty.epfl.ch/docs/reference/dropped/class-shadowing.html

super type内で定義されているのと同名の型を定義できなくなりました

```scala
object ClassShadowing {
  // super type と同名の型を定義できなくなった

  trait Super {
    class A
  }

  trait Sub extends Super {
    // class A
  }
}
```

## Limit 22

http://dotty.epfl.ch/docs/reference/dropped/limit22.html

関数型や、Tuple型の22制限がなくなりました。

```scala
object Limit22 {
  trait A
  def f: (
    A, A, A, A, A,
    A, A, A, A, A,
    A, A, A, A, A,
    A, A, A, A, A,
    A, A, A, A, A,
    A, A, A, A, A) => A = ???

  def t: (
    A, A, A, A, A,
    A, A, A, A, A,
    A, A, A, A, A,
    A, A, A, A, A,
    A, A, A, A, A,
    A, A, A, A, A) = ???
}
```

## XML Literals

http://dotty.epfl.ch/docs/reference/dropped/xml.html

XMLリテラルがなくなりました。

```scala
object XMLLiterals {
  // 代わりにXML string interpolation
  // らしいが、多分まだ実装されてない
  // https://github.com/scala/scala-xml/issues/248
  
  // val x = xml"""<A></A>"""
}
```

## Auto-Application

http://dotty.epfl.ch/docs/reference/dropped/auto-apply.html

空の引数リストを持つメソッドを、`()`なしで呼ぶ（自動的に`()`が挿入される）ことができなくなりました。
ただし、Javaで定義されたメソッドや、Scala 2で定義されたメソッドは、AutoApplicationが残ります。


```scala
object AutoApplication {
  def method() = ()
  // val t = method // コンパイルエラー

  // Java で定義されたメソッドは AutoApplicationが残る
  val t = 1.toString

  // scala 2で定義されたメソッドもAutoApplicationが残る
  // Numeric#Ops の toIntは、何故か`()`が付いている
  def toInt[N](n: N)(implicit ev: Numeric[N]): Int = {
    import ev._
    n.toInt
  }
}
```

## Weak Conformance

http://dotty.epfl.ch/docs/reference/dropped/weak-conformance.html

Javaのprimitiveな数値型と同等の変換を行うために定義されていた[^10]WeakConformanceが削除されました。
代わりに、変換しても情報の欠落がないときだけ、型を拡張するようになります。

[^10]: 多分…

```scala
object WeakConformance {
  inline val b = 33
  def f(): Int = b + 1
  List(b, 33, 'a')      : List[Int]
  List(b, 33, 'a', f()) : List[Int]
  List(1.0f, 'a', 0)    : List[Float]
  List(1.0f, 1L)        : List[Double]
  List(1.0f, 1L, f())   : List[AnyVal] // fは定数では無いので、情報欠落が無いことを保証できない
  List(1.0f, 1234567890): List[AnyVal] // 1234567890 は Floatでは表現出来ない
}
```

# 終わりに

思ったより長かった・・・