Matthew Hague Matthew Hague - 2 months ago 6
Scala Question

Scalacheck new Buildable Instances

I have the following code for ScalaCheck. The idea is to automatically generate sets of integers using Java HashSet as the container. The following code used to work a few years ago, but no longer compiles.

import java.util.HashSet

import scala.collection._

import org.scalacheck.Properties
import org.scalacheck.Prop._
import org.scalacheck.util.Buildable

package simpletest {

class SimpleSpecification extends Properties("Simple") {

implicit def buildableHashSet[T] : Buildable[T,HashSet[T]] = new Buildable[T, HashSet[T]] {
def builder = new mutable.Builder[T,HashSet[T]] {
val al = new HashSet[T]
def +=(x: T) = {
al.add(x)
this
}
def clear() = al.clear()
def result() = al
}
}

property("simple") =
forAll{(a: HashSet[Int]) =>
a.size() == 1
}

}
}


It fails now with

...simpletest/SimpleSpecification.scala:26: could not find implicit value for parameter a1: org.scalacheck.Arbitrary[java.util.HashSet[Int]]
forAll{(a: HashSet[Int]) =>


I have searched extensively for instructions on using Buildable, but can only find a passing reference in the scalacheck user guide. As far as i can tell, my usage matches that in Buildable.scala (pointed to by the user guide). Does anyone have any ideas what has changed in the past few years, and how to update my code to get it working again?

Answer

forAll() requires implicit Arbitrary[HashSet[Int]]. It can be defined using Gen.containerOf() with implicit Buildable[T,HashSet[T]] and HashSet[T] => Traversable[T].

The code would look like:

package simpletest

import java.util.HashSet

import org.scalacheck.Arbitrary.arbitrary
import org.scalacheck.Prop._
import org.scalacheck.util.Buildable
import org.scalacheck.{Arbitrary, Gen, Properties}

import scala.collection.JavaConverters._
import scala.collection._
import scala.language.implicitConversions


class SimpleSpecification extends Properties("Simple") {

  implicit def buildableHashSet[T]: Buildable[T, HashSet[T]] = new Buildable[T, HashSet[T]] {
    def builder = new mutable.Builder[T, HashSet[T]] {
      val al = new HashSet[T]

      def +=(x: T) = {
        al.add(x)
        this
      }

      def clear() = al.clear()

      def result() = al
    }
  }

  implicit def hashSetTraversable[T](hashSet: HashSet[T]): Traversable[T] = {
    hashSet.asScala
  }

  implicit val intHashSetGen: Arbitrary[HashSet[Int]] =
    Arbitrary(Gen.containerOf[HashSet, Int](arbitrary[Int]))

  property("simple") =
    forAll { (a: HashSet[Int]) =>
      a.size() == 1
    }

}
Comments