These are chat archives for scalikejdbc/ja

27th
Oct 2014
localTxFor で型書かないのはやっぱりしっくりこない。withLocalTx は私は腑に落ちた感あるので強い反対がなければこれでいきたいです。
Toshiyuki Takahashi
@tototoshi
Oct 27 2014 02:02
withLocalTx でも型を書かないと結局おなじじゃないですか?
localTxFor もいまいちだけど withLocalTx だと Slick や Anorm の withTransaction とかぶるのがちょっと。(じぇねららいずlocalTxで良い気がしてきた)
Kazuhiro Sera
@seratch
Oct 27 2014 02:03
かぶったら微妙って言うのがあまりピンと来ないです
generalized は自分が使いたくないから無しw
Toshiyuki Takahashi
@tototoshi
Oct 27 2014 02:04
なるほど
同じような名前だけど withTransaction の with は transaction にかかって、withLocalTx の with は型にかかるのかーと。
Kazuhiro Sera
@seratch
Oct 27 2014 02:21
型にかかってるというのはそういう捉え方もあるのかという感じだけど
withLocalTx は型指定なしで違和感ない、localTxFor は型指定ありで違和感ない、localTxForReturnType はいずれのケースでも誤解がないように説明的にしているという意図の違いがありますね。
Kazuhiro Sera
@seratch
Oct 27 2014 02:26
withLocalTx と localTx の違いが分かりにくい感はあるかな。
localTxFor をドキュメントでは常に型を書くようにしてそれを推奨する記法とする考え方もある。
あるいは localTxForReturnType を標準として def localTxFor = localTxForReturnType として短縮形も許すという折衷案も。
理詰めだけでなく実際に使ってみた感覚で判断した方がよさそう。
Kazuhiro Sera
@seratch
Oct 27 2014 03:02
実際にテストコード書いていてこれが良い気がしてきています >ocalTxForReturnType を標準として def localTxFor = localTxForReturnType として短縮形も許す
kenji yoshida
@xuwei-k
Oct 27 2014 11:39
いずれにせよ、色々メソッド追加してる時点で覚えること増えてわかりにくい、と個人的には感じてるので、とにかく既存のメソッドの動作と名前はできるだけ変えずにそのまま残して欲しい感ある。けど、それほど強く主張したいわけでもないので、まぁいいか
Manabu Nakamura
@gakuzzzz
Oct 27 2014 11:42
より良いアイデアを提示できなのでコメントできないでいる……
Toshiyuki Takahashi
@tototoshi
Oct 27 2014 12:59
特に良いアイディアもないし何もしなくて良いんじゃないですか。core API として欲しいかっていうと、別にそうでもないし。
Kazuhiro Sera
@seratch
Oct 27 2014 13:00
それって TxBoundary ごと revert ということ?
あるいは localTxFor を内部 API にとどめるか。
この機能自体は意義があるとは思うが。
Manabu Nakamura
@gakuzzzz
Oct 27 2014 13:04
現実に困ってる人がすでに居ますしね
Toshiyuki Takahashi
@tototoshi
Oct 27 2014 13:06
困ってる人がいると言っても今までいなかったわけだし、そこまで良くある悩みなのかがわからないです。実際自分は困ったことないし、困る前にあきらめてヘルパーみたいなの作ると思うので。
Kazuhiro Sera
@seratch
Oct 27 2014 13:07
できることなら入れたい機能ではあるが、かといって焦って変な名前とかつけたくないというのは確かにあります。だから珍しくこんな感じでみんなの意見を聞いてるという状況。
でも思いつかないならまだ時期尚早ということはあると思う。
Toshiyuki Takahashi
@tototoshi
Oct 27 2014 13:08
自分もできることなら入れたいとは思いますが。
Toshiyuki Takahashi
@tototoshi
Oct 27 2014 13:17
  def localTxForTry[A](f: DBSession => Try[A]): Try[A] = {
    import scala.util._
    using(DB(ConnectionPool.borrow())) { db =>
      val tx = new Tx(db.conn)
      val session = DBSession(db.conn, tx = Some(tx))
      val result = f(session)
      if (result.isSuccess) {
        tx.commit()
      } else {
        tx.rollback()
      }
      result
    }
  }
自分で作るとこんな感じなんですかね
Kazuhiro Sera
@seratch
Oct 27 2014 13:23
あと念のため例外をケアする必要はあります。
あれですね、元々例外を前提にしたものがあって、Try とか Either も考慮しようぜっていう課題にそもそもしっくりくる解決案がないということか。少なくともそういう知見がない。
Toshiyuki Takahashi
@tototoshi
Oct 27 2014 13:28
それ思ってました。localTxForReturnType で本当に解決なのかがよくわからなくなってます。
Kazuhiro Sera
@seratch
Oct 27 2014 13:30
Spring だったら、いいから RuntimeException 投げろやっていう..
Toshiyuki Takahashi
@tototoshi
Oct 27 2014 13:30
例外便利...
Kazuhiro Sera
@seratch
Oct 27 2014 13:30
Spring じゃないか、Java ワールド.
Manabu Nakamura
@gakuzzzz
Oct 27 2014 13:33
ちなみに futureLocalTx が入ったのはどういう経緯だったんですか?
Kazuhiro Sera
@seratch
Oct 27 2014 13:33
あれは merge request で。
あ、pull か。
Manabu Nakamura
@gakuzzzz
Oct 27 2014 13:34
あーなるほど
Kazuhiro Sera
@seratch
Oct 27 2014 13:35
tryLocalTx とか増やしてもいいと思ってる私は特に抵抗なかった。
あと Future に関しては Scala なので特別扱いもおかしくないかと。
Manabu Nakamura
@gakuzzzz
Oct 27 2014 13:38
なるほど。
現状改めて見て見たらけっこうメソッド多い……
http://static.javadoc.io/org.scalikejdbc/scalikejdbc-core_2.11/2.1.2/index.html#scalikejdbc.DB$
Toshiyuki Takahashi
@tototoshi
Oct 27 2014 13:42
なんで DB.localTx + Try/Either とかで困ったことないのか考えたけれど、
トランザクションの中で例外ばんばん出るようなプログラム書いてない、もしくはそういう書き方をしてないからかな。
Kazuhiro Sera
@seratch
Oct 27 2014 13:48
多いですかね。役割からするとそうでもないと思います。WithConnection 系は Anorm から乗り換え支援なので、そのうちなくしたいですが。
でもまあ無理になくすほどでもない。
きっとなくさないだろう。
なくしたいというか需要はもうあんまりないんじゃないかなーと言いたかったようです。
Manabu Nakamura
@gakuzzzz
Oct 27 2014 13:53
あー withConnection はそういう目的だったんですね。なるほど
Kazuhiro Sera
@seratch
Oct 27 2014 13:56
乗り換えないにせよ Anorm をクエリビルダとして使い
プレイじゃないコネクション提供者が欲しいケースもあろうということも。実際、海外のお蔵入りになった書籍のサンプルコードにそういう用途で登場していたし、そういうブログ記事も見たことありますね。
SHOGO
@shogogg
Oct 27 2014 14:46
scalikejdbc からクエリを投げるメソッドって、どうしても例外が発生するので Try[A] で返すようにする → それを localTx の中で呼び出すと例外が throw されないから rollback されない、っていうのは珍しいんでしょうか。そもそも Try[A] を使うのがオススメできない……ってことでしょうか。
Toshiyuki Takahashi
@tototoshi
Oct 27 2014 14:50
  DB.localTx { implicit session =>
    Try {
      sql"INSERT ...".update.apply()
    }
  }
こういうかんじですか?
Kazuhiro Sera
@seratch
Oct 27 2014 15:02
2.1 時点での scalikejdbc は例外のみがトランザクション境界なので localTx 内で例外を捕捉したいという使い方にミスマッチがあるということだと思います。ニーズとしては十分理解できるので検討しているところですが API の設計がうまく決まらず悩んでいます。
Kazuhiro Sera
@seratch
Oct 27 2014 15:08
scalikejdbc/scalikejdbc@42ae2df
2.1 では TxBoundary をライブラリユーザに解放するのはやめて内部的に使うだけにしようかと。

で 2.2 からは

def localTx[A](execution: DBSession => A)(implicit context: CPContext = NoCPContext): A

def localTx[A](execution: DBSession => A)(
  implicit context: CPContext = NoCPContext, txBoundary: TxBoundary = ExceptionTxBoundary): A

に変える。

Future は妥当だと思うので default で提供するが Try、Either は import して使ってもらう。
はどうでしょう?
Kazuhiro Sera
@seratch
Oct 27 2014 15:15
あるいは Future もデフォルトで提供しなければ互換性が保たれるので、そっちをとってもよい。futureLocalTx は上記なら deprecated にしてもよいが、デフォルトで提供しないならそのまま。
あー……、ユーザー定義のエラーでロールバックしたいのにTxBoundaryのimport忘れたら、エラーにならずanyTxBoundaryが使われてしまうか。
Manabu Nakamura
@gakuzzzz
Oct 27 2014 15:17
2.1で開放しないっていうのはありかと思います。
2.2の案は一周もどって最初の案に戻ってきた感。
そう、それがあるんですよね< import 忘れ
Try と Either に関してはどっちがデフォルトの方が嬉しいんだろう……
Kazuhiro Sera
@seratch
Oct 27 2014 15:18
ならラップしたものを用意してほしい気はする。
Manabu Nakamura
@gakuzzzz
Oct 27 2014 15:20
確かに。
ExceptionTxBoundary がデフォルトになるのを設定で無効化とかできるといいのかな
Kazuhiro Sera
@seratch
Oct 27 2014 15:21
お、そんなのできるんですか。
Manabu Nakamura
@gakuzzzz
Oct 27 2014 15:21
macro で設定ファイル読めば……
Kazuhiro Sera
@seratch
Oct 27 2014 15:21
いらないですよー
Manabu Nakamura
@gakuzzzz
Oct 27 2014 15:21
ですよねー
kenji yoshida
@xuwei-k
Oct 27 2014 15:32
Try はよくわからないけど、少なくとも Either は、Left をエラー以外に使うこともありえるだろうし、"デフォルトのtypeclassのインスタンス存在していて、それが逆に邪魔!" とかにはならないようにはしたほうが良さそう
Manabu Nakamura
@gakuzzzz
Oct 27 2014 15:35
そういう意味では scalikejdbc/scalikejdbc@42ae2df の import で on/off 切り替えられる方が良さそうですね
Tsukasa Kitachi
@kxbmap
Oct 27 2014 17:35
この方向ならFutureデフォルト提供せずにfutureLocalTxもdeperecatedにする、もありと思う。今後はlocalTxにFutureTxBoundaryをimportして使ってねーと
Tsukasa Kitachi
@kxbmap
Oct 27 2014 17:42
FutureとTryはエラー処理の観点では同じな感じがする。どっちもFailureでコミットしたい人はいないと思う
デフォルトは両方提供するか両方しないかのどちらかって気がしてる
Tsukasa Kitachi
@kxbmap
Oct 27 2014 17:50
Eitherはデフォルトにすべきでないし、ライブラリ内にある必要もないかも
Tsukasa Kitachi
@kxbmap
Oct 27 2014 18:10
import scala.util.Either
import scala.util.Left

trait Ctx[A] {
  def hello: String
}

object Ctx {
  implicit def anyCtx[A]: Ctx[A] = new Ctx[A] {
    override def hello: String = "AnyCtx"
  }
}

sealed trait Error
case object ErrorA extends Error
case object ErrorB extends Error

object Error {
  implicit def errorCtx[A]: Ctx[Either[Error, A]] = new Ctx[Either[Error, A]] {
    override def hello: String = "ErrorCtx"
  }
}

object Main extends App {

  def hello[A](a: A)(implicit tx: Ctx[A]): Unit = println(s"$a : ${tx.hello}")

  hello(42)
  hello(Left(ErrorA))
  hello[Either[Error, Int]](Left(ErrorB))
}
42 : AnyCtx
Left(ErrorA) : AnyCtx
Left(ErrorB) : ErrorCtx
Manabu Nakamura
@gakuzzzz
Oct 27 2014 18:14
Ctx が invariant だとそうなりますねー
Tsukasa Kitachi
@kxbmap
Oct 27 2014 18:17
[-A]ならおkか
まー言いたかったのはTryじゃなくてEither使うのってユーザー定義のエラーを使いたい場合だろうから、コンパニオンに専用でimplicit定義してくださいでいいんじゃないかと
Tsukasa Kitachi
@kxbmap
Oct 27 2014 18:24
関係ないけどdeclaration-site varianceはいいものだ…… Javaのアレのめんどくささときたらない
Kazuhiro Sera
@seratch
Oct 27 2014 22:33

Eitherはデフォルトにすべきでないし、ライブラリ内にある必要もないかも

これは一理ありますね。この方向かな。

FutureとTryはエラー処理の観点では同じな感じがする。どっちもFailureでコミットしたい人はいないと思う。デフォルトは両方提供するか両方しないかのどちらかって気がしてる

デフォルトで提供すべきでないというのはユーザが上書きしたいときに困るからだけど、こいつらを上書きしたいケースが本当にあるだろうか?私はないような気がする。もしそう判断できるなら、両方デフォルトの方が使い勝手としては「気が利いていてよい」と思う。

Kazuhiro Sera
@seratch
Oct 27 2014 23:13
一方、後方互換を優先してデフォルトを一切提供せず import の方法をドキュメントに明示する方がよいのかもしれない。ライブラリの仕様としてもデフォルトは例外だけというのはシンプル。