LoginSignup
1
0

More than 5 years have passed since last update.

Scala の wildcard の使用例

Last updated at Posted at 2018-08-09

目標

Scala において,(_ <: AnyVal) のようなwildcard を用いた定義式がどううれしいかを論じる.

wildcard の簡単な説明

generic type を用いるとき,型安全性のため Covariant な型(A <: B のときのA)の操作に制限がある.例として,型安全のために, covariant type の compound type (List[A] や Set[A], Array[A])に別の covariant type を挿入できうる操作が定義できないことがある. (詳しくは使用例で)そこで,wild card を用いることにより,generic type に対しするメソッドを型安全となるよう柔軟に定義できる.

使用例とメリット

独自の Int クラスと Double クラス, List クラスを定義し,独自の List クラスに Int や Double を追加していくような実装を考える.ここで,独自の Int クラスと Double クラスはともに NumericVal クラスの covariant タイプである.各クラスの定義は次のようになる.

// 数値クラス
abstract class NumericVal (){}
class MyInt ()    extends NumericVal {val value = 0}
class MyDouble () extends NumericVal {val value = 0.0}

// リストクラス
class MyList[T](){
  var list:List[T] = List()
  def add(elem:T) {list = elem :: list}
}

この例では, generic type を用いて定義した独自のリストクラス MyList に MyInt, MyDouble を挿入するメソッドを, wildcard で型安全に定義できることを示す.
MyList クラスは, generic type T のリストを保持し, add メソッドを通じてリストに T のインスタンスを追加できる.

addElemToList メソッドでは,次のことを実現したいとする.
1. MyList[NumericVal] に MyInt や MyDouble のインスタンスを追加する.
2. MyList[MyInt] に MyInt のインスタンスを追加する.
3. MyList[MyDouble] に MyDouble のインスタンスを追加する.

しかし,これを型安全に定義するのは難しい.
もし次のように定義する場合,

 def addElemToList(elem:NumericVal, list:MyList[NumericVal]){
  list.add(elem)
}

SBT のコンパイラではMyList[MyInt] <: MyList[NumericVal]が成り立たないため(後述),要件2と3を満たさない.仮にMyList[MyInt] <: MyList[NumericVal] が成り立つとしても,次のように型安全でないメソッドが定義できうるため,型検査をパスしない.

val intList = new MyList[MyInt]()
val myDouble = new MyDouble()
addElemToList(myDouble, intList) // MyList[MyInt] に MyDouble が入っちゃう

そこで, wildcard を用いることにより,次のように型安全にメソッドを定義できる.


object Main extends App {

  def addElemToList[A<:NumericVal](elem:A, list:MyList[_ >:A]){
    list.add(elem)
  }

  // 要件1を満たす.
  var numericList = new MyList[NumericVal]()
  addElemToList(new MyInt(), numericList)
  addElemToList(new MyDouble(), numericList)
  // 要件2を満たす.
  var intList = new MyList[MyInt]()
  addElemToList(new MyInt(), intList)
  // 要件3を満たす.
  var doubleList = new MyList[MyDouble]()
  addElemToList(new MyDouble(), doubleList)
}

前述のとおり,SBT のコンパイラではMyList[MyInt] <: MyList[NumericVal]が成り立たない.これは次のエラーにより確認できる.

[error] /home/ytakahashi/project/classes/programingDesign/problem02/src/main/scala/example/Hello.scala:31:30: type mismatch;
[error]  found   : problem02.MyList[problem02.MyInt]
[error]  required: problem02.MyList[problem02.NumericVal]
[error] Note: problem02.MyInt <: problem02.NumericVal, but class MyList is invariant in type T.
[error] You may wish to define T as +T instead. (SLS 4.5)
[error]   addElemToList(new MyInt(), intList)
[error]                              ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 1 s, completed Aug 8, 2018 11:30:35 PM
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0