implement Testable for Fn*
abr-egn opened this issue · 13 comments
Using rustc 1.0.0-nightly (3d0d9bb6f 2015-01-12 22:56:20 +0000):
fn reverse<T: Clone>(xs: &[T]) -> Vec<T> {
let mut rev = vec!();
for x in xs.iter() {
rev.insert(0, x.clone())
}
rev
}
#[test]
fn reverse_identity() {
fn prop(xs: Vec<i32>) -> bool {
xs == reverse(reverse(xs.as_slice()).as_slice())
}
quickcheck(prop);
}
produces
error: the trait `quickcheck::tester::Testable` is not implemented for the type `fn(collections::vec::Vec<i32>) -> bool {tests::reverse_identity::prop}`
quickcheck(false)
compiles; this appears to be specific to the fn impls, including the zero-arg fn.
Errm, try: quickcheck(prop as fn(Vec<i32>) -> bool)
.
That does work, thank you. I'm a bit baffled that it's required since it's trivially inferrable type information...
I'm pretty sure it's a known bug, but I can't find it in the Rust issue tracker at the moment. I think this happened when Rust moved everything over to unboxed closures. Unfortunately, I can't remember why this happens.
The PR that introduced this, I think, is rust-lang/rust#19891. I too remember seeing something that indicated this coercion is supposed to exist at some point but can't find it either.
Afaik, functions now implement the Fn(…) -> …
traits. So I think it would actually be cleaner if quickcheck would impl<F: Fn(…) -> …> Testable for F
instead of coercing to a trait object.
Edit: that does not work together with the coherence rules, does it?
I've tried really hard to work around this (by pursuing impls with Fn
instead of fn
) and I haven't been able to come up with a solution yet.
I think I'm currently blocked on this by this bug: rust-lang/rust#25041 (Well, I think it's a bug. It sure feels like it.)
cc me
Just to clarify: we are currently blocked on being able to quickcheck an arbitrary closure? (Important to be able to nest to stage generation of values, as in Haskell QuickCheck and Scala ScalaCheck.)
@FranklinChen Yup. I might be missing another solution to the problem, but the straight-forward path is to implement Testable
on closure types, and the bug in rust-lang/rust#25041 seems to be preventing that.
While this still doesn't seem possible at the type level yet, you can reduce a bit of boilerplate by using _
when casting to the function pointer:
fn prop(xs: Vec<i32>) -> bool {
xs == reverse(&reverse(&xs[..])[..])
}
quickcheck(prop as fn(_) -> _);
This is a bit nicer as you only have to duplicate the number of arguments, not the types.
@shepmaster Ah, thanks for that tip. Could a macro automate that?
As far as I can tell, this is just never going to work. See rust-lang/rust#25041 for more discussion, where it seems to me the issue has been interpreted as "confusing" rather than a bug to fix. Some reasons are given but I don't quite understand them. I don't see any movement to resolve it, so after half a decade, I'm giving up and calling this wontfix
.
I would very much love to make quickcheck work with closures though. So if there are any fresh ideas, we can re-open is this issue.