Say goodbye to implicits

Magda Stożek

Contextual abstractions in Scala 3

implicits よさらば

Scala 3 のコンテキスト抽象

Agenda

  1. About implicits
  2. Problems in Scala 2
  3. Use cases - Scala 2 vs Scala 3

implicit の概要、Scala 2 での問題点
Scala 2 と Scala 3 での実践での相違点

Implicits make us powerful

  • providing context
  • adding functionality
  • type classes
  • implicit conversions
  • dependency injection
  • expressing capabilities
  • computing new types
  • proving relationships between types

implicits は私達を強化する。
コンテキストの提供、機能の追加、型クラス、暗黙の変換など。

Implicits make us miserable

  • implicit parameter
  • implicit argument
  • implicit value
  • implicit object
  • implicit def
  • implicit class
  • implicit import incantations
  • sneaky conversions

implicits は私達をみじめにする。
おまじない的 import 文。こそこそした変換。

Scala 3

Scala 2

  1. Providing context
  2. Adding functionality
  3. Type classes
  4. Conversions

vs

Scala 3

コンテキストの提供、機能の追加、型クラスなどについて
Scala 2 と Scala 3 の比較

1. Providing context

- implicit vals

implicit val ec: ExecutionContext = ExecutionContext.global
Future {
  def apply[T](body: => T)(implicit executor: ExecutionContext): Future[T] = {...}
}

Scala 2

val myFuture: Future[Int] = Future {
  println("Finding the answer...")
  42
}

?

?

コンテキストの提供
Scala 2 は implicit val を使う

1. Providing context

- using/given

val myFuture: Future[Int] = Future {
  println("Finding the answer...")
  42
}

Scala 3

given ec: ExecutionContext = ExecutionContext.global
Future {
  def apply[T](body: => T)(using executor: ExecutionContext): Future[T] = {...}
}

?

?

コンテキストの提供
Scala 3 は using と given を使う

2. Adding functionality

object other_package {
  case class Book(title: String, pages: Int)
}
val book = Book("Winnie-the-Pooh", 160)
myBook.qualifiesForChallenge   //true

val book = Book("Too short", 5)
myBook.qualifiesForChallenge   //false
implicit class Qualifier(b: Book) {
  def qualifiesForChallenge: Boolean = b.pages > 20
}

?

- implicit classes

Scala 2

機能の追加
Scala 2 は implicit クラスを使う

2. Adding functionality

- extension methods

object other_package {
  case class Book(title: String, pages: Int)
}
val book = Book("Winnie-the-Pooh", 160)
myBook.qualifiesForChallenge   //true

val book = Book("Too short", 5)
myBook.qualifiesForChallenge   //false

?

extension (b: Book)
  def qualifiesForChallenge = b.pages > 20

Scala 3

機能の追加
Scala は拡張メソッドを使う

3. Type classes

  trait Scorable[T] {
    def score(t: T): Int
  }
val book = Book("Dune", 600)
val initialScore = CurrentScore(0).addItem(book)    // CurrentScore(600)

val article = Article("Understanding type classes")
val newScore = initialScore.addItem(article)        // CurrentScore(601)

- implicit val/object/def (with implicit parameters)

  implicit val scorableBook = new Scorable[Book] {
    override def score(b: Book): Int = b.pages
  }

  implicit val scorableArticle = new Scorable[Article] {
    override def score(t: Article): Int = 1
  }

  case class CurrentScore(value: Int) {
    def addItem[T](item: T)(implicit scoring: Scorable[T]): CurrentScore =
      CurrentScore(value + scoring.score(item))
  }

Scala 2

型クラス: 暗黙のパラメータの場合
Scala 2 は implicit val/object/def など

?

3. Type classes

- given instances (with using)

  given Scorable[Book] with {
    override def score(b: Book): Int = b.pages
  }

  given Scorable[Article] with {
    override def score(t: Article): Int = 1
  }

  case class CurrentScore(value: Int) {
    def addItem[T](item: T)(using scoring: Scorable[T]): CurrentScore =
      CurrentScore(value + scoring.score(item))
  }
  trait Scorable[T] {
    def score(t: T): Int
  }
val book = Book("Dune", 600)
val initialScore = CurrentScore(0).addItem(book)    // CurrentScore(600)

val article = Article("Understanding type classes")
val newScore = initialScore.addItem(article)        // CurrentScore(601)

Scala 3

型クラス: using の場合
Scala 3 は given インスタンス

?

4. Conversions

- implicit def

case class Item(value: String) extends AnyVal

def print(item: Item): Unit = println(s"*** ${item.value} ***")
val book = Book("Dune", 600)

print(book)

?

implicit def bookToItem(book: Book): Item = Item(book.title)

Scala 2

暗黙の変換
Scala 2 は implicit def

4. Conversions

- Conversion class

case class Item(value: String) extends AnyVal

def print(item: Item): Unit = println(s"*** ${item.value} ***")
val book = Book("Dune", 600)

print(book)

?

given Conversion[Book, Item] with
  def apply(book: Book): Item = Item(book.title)

Scala 3

暗黙の変換
Scala 3 は Conversion 型クラス

Summary

  • intention, not mechanism
  • given/using
  • extension methods
  • Conversion class

機序ではなく意図を表した構文

Thank you

given Finished[Presentation] with {
  override def ask(q: Question): Unit = q.ask()
}

ご清聴ありがとうございました