Tuesday, June 15, 2010

Simplified case class Generator for Scalacheck

I just wrote a fairly handy generator for making very simple vanilla case classes. It basically uses the apply method defined in the companion of them to make things pretty simple. I am not sure if something similar is in the library already.

basically you can just type in your specification.

implicit val arbPoint = ArbFunc(Point.apply _)

and then arbitrary points will be provided as needed

If I posted the code here i have feeling it would get severely mangled so I put it in a gist:


I think it is a simpler way to make the generators for case classes where you don't care that much about constraining the members of the case class.

posted to the mailing list, waiting for moderation.

Monday, June 14, 2010

Working around Dependent Method Types with Structural Types

Until dependent method types move out of experimental status in the scala compiler (they can be enabled with -Xexperimental) we have been using Structural Typing to work around their absence.

Here's how were doing it:

First, Given:

trait AToB {
    type B
    def b : B

and an implementation:

trait AToInt extends AToB {
    final override type B = Int

object AToInt {
    def apply(x : Int) = new AToInt {
        final override val b = x

We would like to write a function with given any AToB
returns the type of B specified by that A:

if we had dependent method types we could write this as

def bOf[A <: AToB](a : A) : a.B = a.b

however this gives the error:

error: illegal dependent method type
          def bOf[A <: AToB](a : A) : a.B = a.b

To work around this however and still preserve type safety we have been doing this:

def bOf[AA <: AToB {type B = BB}, BB](a : AA) : BB = a.b

Basically we are using a structural type to fix the abstract type B in AToB to a concrete
type BB. This will enforce the type constraint that we want. There is one annoyance that remains
however and I haven't figured out a solution for it yet, the compiler is inferring the wrong type
for BB.

val x : Int = bOf(AToInt(5))

gives the compiler error:

error: inferred type arguments [java.lang.Object with AToInt,Nothing] do not conform to method bOf's type parameter bounds [AA <: AToB{type B = BB},BB]

yuck, the work around is to say:

val x : Int = bOf[AToInt, AToInt#B](AToInt(5))

Which will compile correctly.

A few more examples which will not compile:

trait AToString extends AToB {
    final override type B = String

object AToString {
    def apply(x : String) = new AToString {
        final override val b = x

//Will not compile
val x : String = bOf[AToInt, AToInt#B](AToInt(5))
//Will compile
val x : String = bOf[AToString, AToString#B](AToString("Good Times"))
//Will not compile
val x : Int = bOf[AToString, AToString#B](AToString("Good Times"))