Search code examples
javascalascalacheck

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?


Solution

  • 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
        }
    
    }