case class Configuration(val n: Int)
class Printer(conf: Configuration) {
def print(String str) = {
println(this.makeStr(str));
}
def private makeStr(String str): String = { // ①
str * conf.n // インスタンス変数confの値を使ってる
}
}
普通にオブジェクト指向っぽく書くと、①のPrinter.makeStrみたいにインスタンス変数の状態を使って処理をすることがよくあると思うんだけど、関数型でよく言われる参照透過性的に、これはあまりよろしくない。たぶん、好まれるのは
private def makeStr(str: String, conf: Configuration): String
みたいに、インスタンス変数で持ってるのにもかかわらず、呼び出しもとから、ちゃんとConfigurationをわたしてあげる形が関数型的には好まれる。
ただ、これって、すごく冗長で、オブジェクト指向と関数型って相性あんまよくないんじゃないのかなーとか思ってた。(これだけを取り上げて相性よくないは言いすぎだけど・・・)
でも、Scalaはimplicit使うとこれを解決できる。この解決方法がいい手法なのかどうかは正直わからないけど・・・
上の例のPrinterをimplicit使って書き直すと
class Printer(implicit val conf: Configuration) {
def print(String str) = {
println(this.makeStr(str));
}
private def makeStr(String str)(implicit conf: Configuration): String = {
str * conf.n
}
}
こうすると呼び出しもとのprintからわざわざconfを渡す記述をしなくても暗黙でconfが渡されし、たぶん参照透過性的にも悪くない。
結論
implicitって、よく暗黙的型変換を例にして語られることがあるけど、他にもいろんな使い方がある。
正直、implicit使いまくるのあんま好きじゃないけど・・・