Why does Gen.Params include a size & why does Gen[T] return Option[T]?

165 views
Skip to first unread message

Ben Hutchison

unread,
Feb 2, 2013, 12:28:02 AM2/2/13
to scala...@googlegroups.com
Two possibly related design questions about Scalacheck that I've never understood the motivation for properly:

- Why does Gen.Params include a size? Why not assume a generator can provide an infinite stream of values? 

- Why does Gen[T] return Option[T]? Why would a Gen usefully return None - because it's size is exceeded, or otherwise?

-Ben

Nate Bauernfeind

unread,
Feb 2, 2013, 11:28:53 AM2/2/13
to scala...@googlegroups.com
Gen.Params has a size as it is used to bound generated collection sizes. By default a collection won't receive a collection of greater than 100 elements. You can figure this out browsing around the source near here: http://code.google.com/p/scalacheck/source/browse/trunk/src/org/scalacheck/Gen.scala?r=370#199

Gen[T] returns Option[T] because of the use case around filtering a generator.

They give this example: val smallEvenInteger = Gen.choose(0,200) suchThat (_ % 2 == 0)

suchThat is just an alias for filter which is defined here: http://code.google.com/p/scalacheck/source/browse/trunk/src/org/scalacheck/Gen.scala?r=370#53

Which takes advantage of the ability to return None as a way of saying that generated value was invalid.


Nate


-Ben

--
You received this message because you are subscribed to the Google Groups "scalacheck" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scalacheck+...@googlegroups.com.
To post to this group, send email to scala...@googlegroups.com.
Visit this group at http://groups.google.com/group/scalacheck?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Ben Hutchison

unread,
Feb 3, 2013, 2:30:29 AM2/3/13
to scala...@googlegroups.com
Thanks for the explanation and pointers...

IMO the use of Option[T] to support filter seems a high price to pay to model a blocked generator in the type-system. I prefer an exception myself, for what seems an anomalous condition. Contrast with eg Traversable.head.

Also, the desire to remain completely faithful to the static types in this matter is somewhat at odds with the use of Gen.Params.size, in that Gens of non-collection types still receive a size parameter and yet ignore it. 

An alternative design which I was playing with yesterday is to separate Gen into a GenFactory[Config, T] and a Gen[T] interface. The former used by code that configures a Gen (passing customizable params of type Config), the latter by code that consumes the Gen's value stream.

-Ben

Tony Morris

unread,
Feb 3, 2013, 2:46:30 AM2/3/13
to scala...@googlegroups.com
This (GenFactory) is the Gen monad transformer. I think this is more flexible too.
-- 
Tony Morris
http://tmorris.net/

Rickard Nilsson

unread,
Apr 1, 2013, 9:35:12 AM4/1/13
to scala...@googlegroups.com, Ben Hutchison
Hi,

Better late than never :)

Den 2013-02-03 08:30:29 skrev Ben Hutchison <brhut...@gmail.com>:

> Thanks for the explanation and pointers...
>
> IMO the use of Option[T] to support filter seems a high price to pay to
> model a blocked generator in the type-system. I prefer an exception
> myself,
> for what seems an anomalous condition. Contrast with eg Traversable.head.

Is it really a high price? I think ScalaCheck's various generator
combinators hides the Option type quite well. You really shouldn't have to
see that in your code, even if you define custom generators. The current
implementation works nicely with Scala's for-comprehensions, which I don't
think exceptions would do. You can use Scala's built-in filtering with
ScalaCheck's generators:

trait A
case class B(n: Int)
case class C(s: String)

val g: Gen[String] = for {
C(s) <- Gen.oneOf(C("foo"), B("42))
} yield s


> Also, the desire to remain completely faithful to the static types in
> this
> matter is somewhat at odds with the use of Gen.Params.size, in that Gens
> of
> non-collection types still receive a size parameter and yet ignore it.
>
> An alternative design which I was playing with yesterday is to separate
> Gen
> into a GenFactory[Config, T] and a Gen[T] interface. The former used by
> code that configures a Gen (passing customizable params of type Config),
> the latter by code that consumes the Gen's value stream.

The size parameter is loosely defined, so a generator implementer could
choose to interpret it any way she likes. Non-collection types can use the
size in a meaningful way too (most data types actually have some kind size
concept). A GenFactory could be nice, but it also adds complexity.

/ Rickard


> -Ben
>
> On Sunday, 3 February 2013 03:28:53 UTC+11, Nate Bauernfeind wrote:
>>
>> Gen.Params has a size as it is used to bound generated collection sizes.
>> By default a collection won't receive a collection of greater than 100
>> elements. You can figure this out browsing around the source near here:
>> http://code.google.com/p/scalacheck/source/browse/trunk/src/org/scalacheck/Gen.scala?r=370#199
>>
>> Gen[T] returns Option[T] because of the use case around filtering a
>> generator.
>>
>> Under conditional generators here:
>> https://github.com/rickynils/scalacheck/wiki/User-Guide
>> They give this example: val smallEvenInteger = Gen.choose(0,200)
>> suchThat
>> (_ % 2 == 0)
>>
>> suchThat is just an alias for filter which is defined here:
>> http://code.google.com/p/scalacheck/source/browse/trunk/src/org/scalacheck/Gen.scala?r=370#53
>>
>> Which takes advantage of the ability to return None as a way of saying
>> that generated value was invalid.
>>
>>
>> Nate
>>
>> On Fri, Feb 1, 2013 at 11:28 PM, Ben Hutchison
>> <brhut...@gmail.com<javascript:>
>> > wrote:
>>
>>> Two possibly related design questions about Scalacheck that I've never
>>> understood the motivation for properly:
>>>
>>> - Why does Gen.Params include a size? Why not assume a generator can
>>> provide an infinite stream of values?
>>>
>>> - Why does Gen[T] return Option[T]? Why would a Gen usefully return
>>> None
>>> - because it's size is exceeded, or otherwise?
>>>
>>> -Ben
>>>
>>> --
>>> You received this message because you are subscribed to the Google
>>> Groups
>>> "scalacheck" group.
>>> To unsubscribe from this group and stop receiving emails from it, send
>>> an
>>> email to scalacheck+...@googlegroups.com <javascript:>.
>>> To post to this group, send email to
>>> scala...@googlegroups.com<javascript:>
>>> .
Reply all
Reply to author
Forward
0 new messages