Hackathonから帰ったあと、@
marblejenkaさんがappengineのlower levelなネタを
作ってるのを聞いてたので、appengineのライブラリ以外をscalaで作ったらどうなるんだろ、
と思ってApiProxyのHookを書いてみた。
簡単だろ、と思ってたら意外なところでハマってしまった。
最初こんな感じで書いた。
01 | class Hook D elegate( val d elegate : D elegate[ _ < : Environemnt]) |
02 | extends D elegate[Environment] { |
04 | def makeSyncCall(e : Environment, |
05 | s : String,m : String,r : Array[Byte]) : Array[Byte] = { |
06 | d elegate.makeSyncCall(e,s,m,r) |
09 | def makeAsyncCall(e : Environment, |
10 | s : String,m : String,r : Array[Byte], |
11 | c : ApiConfig) : Future[Array[Byte]] = { |
12 | d elegate.makeAsyncCall(e,s,m,r,c) |
15 | def log(e : Environment,r : LogRecor d ) = { |
アウト。
コンパイル時に型が違いますエラーをdelegate.makeXXX,logの呼び出しで喰らう。
Delegateが共変ではないってことになるのかな。
渡すdelegateはApiProxy.getDelegateで取得することを想定しているのだけど、
これ仮型引数が分からない。scalaのエラーによると、<? extends Environment>
ってのは分かってるんだけど、型として<? extends Environment>ってのは用意できない。
まあJavaで同じことしてもエラーになるんだけど、ApiProxy.getDelegateはraw type
、イレイジャ通って戻ってくるので、キャストして呼べるんだよね。
1日悩んで、どうしたらいいんだろと考えてひらめいた。
01 | class Hook D elegate[E < : Environment]( val d elegate : D elegate[E]) |
05 | s : String,m : String,r : Array[Byte]) : Array[Byte] = { |
06 | d elegate.makeSyncCall(e,s,m,r) |
09 | def makeAsyncCall(e : E,s : String,m : String,r : Array[Byte], |
10 | c : ApiConfig) : Future[Array[Byte]] = { |
11 | d elegate.makeAsyncCall(e,s,m,r,c) |
14 | def log(e : E,r : LogRecor d ) = { |
これならOK。
コンストラクタの引数を元に仮型引数を決定できるので渡されたdelegateを
元に推論すればいいじゃん!とひらめいたのでした。
・直接このHookのmakeSyncCallは呼び出せない
・Hook内でEnvironmentをいじれない
けれども。
多分Javaだとタイプセーフにはできないような気がする。
0 件のコメント:
コメントを投稿