FLINTERS Engineer's Blog

FLINTERSのエンジニアによる技術ブログ

EitherTもういいや、時代はZIO

みやしーです。
弊社FLINTERSが2024年1月6日に会社設立10周年ということで、みんなでブログを毎日書いています。この記事は113日目の記事だそうです。すごいですね

さっそく本題へ

対象読者

  • Scalaをやっている
  • 失敗と成功のいずれかを表すには Either[E, A] を使うことを知っている
  • 非同期処理を表すには Future[A] を使うことを知っている

これまでのあらすじ

  • Either と Future は同時に使うことが多いじゃん
  • Either と Future は同時に使う… EitherT の出番か!?
  • いや、EitherTなんかちょっとまどろっこしいな

わかるなあ

いやー EitherT 便利だと思ってたんですけどね。4年前の私は EitherT大好きって感じの記事を書いてキャッキャしていたし。

でも、非同期処理と失敗と成功を同時に表現できるすごい型があればそれで良くない?って思うわけですよ。

そうです

時代はZIO

ZIO !!!

ZIOっていうのは、大体 Future[Either[E, A]] のことです!

便利ですね。現場からは以上です。

続き

ちょっと嘘つきました。
ドキュメントには 「(この例えは正確とは言えないが)ZIOは R => Either[E, A] だ」と書いてますね。
Future[Either[E, A]] とは色々違いますが、まあでも大体こんなもんです。

続き2

ZIO型には3つの型パラメータがあり、 ZIO[R, E, A] のようになっています。
このうち EAEither[E, A] と同様に失敗と成功を表すものです。

なお、 R は関数の引数として使うようなものですが、使わないなら Any を入れておけばOKです。

Either を使ったコードは、ZIOでは次のように書きます。

val a: Either[String, Int] = Right(42)
val b: Either[String, Int] = Left("failed!")
import zio.ZIO
val a: ZIO[Any, String, Int] = ZIO.succeed(42)
val b: ZIO[Any, String, Int] = ZIO.fail("failed!")

.map, .flatMap のようなおなじみの処理や、 .mapError によるエラーの値の変換ができます。
その他もろもろ、Either で出来ることは ZIO でもできます。

また、 Future に関してはというと、 Future と ZIO で非同期に関する考え方が違う点がいくつかあります。

Future ではこのようなコードがあったとき

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
val a: Furure[Int] = Future {
  // なんか色々通信したりする処理
  42
}
  • 型は、同期的な処理は A で、非同期的な処理は Future[A] と区別する
  • なんか ExecutionContext とかようわからんものを指定する必要がある
  • Future型のインスタンスが作成されたタイミングで非同期処理が開始される

ですよね。

ZIO の場合は、なんかこんな感じのコードになるのですが

val a: ZIO[Any, Throwable, Int] = ZIO.attemptBlocking {
  // なんか色々通信したりする処理
  42
}
  • 型は、同期的だろうと非同期だろうと ZIO[R, E, A] である
  • .attemptBlocking.blocking などのメソッドを使うことで、いい感じに実行してくれる
  • ZIO型のインスタンスが作成されたタイミングではまだ処理は実行されない

といった違いがあります。

まとめ

まあ、そんなこんなで Future[Either[E, A]] と ZIO にはいくつかの違いはあるのですが、 ZIO っていう型一つで両方のことができます。

Future[Either[E, A]] を用意して EitherT でラップして〜みたいなこと、もうやらんでいいです。

Either も Future もアプリケーション書いてたら絶対使うわけでして、 ということはみんな ZIO を使ったらいいよってことですよね。

めでたしめでたし。