Giter Club home page Giter Club logo

Comments (7)

jlink avatar jlink commented on July 20, 2024

Looks like a bug I’ll check it.

from jqwik.

jlink avatar jlink commented on July 20, 2024

I did some research. The problem you're observing here is not related to the type paramater but to the fact that 'A' also fits type Object (or List<Object>). Instances of Object are only equal if they are the exact same instance. So you can also observe this behaviour with:

@Property
void aInValuePos(
	@ForAll Function<Integer, Object> f,
	@ForAll Integer i
) {
	Object first = f.apply(i);
	Object  second = f.apply(i);
	Assertions.assertThat(first).isEqualTo(second);
}

A generated function, however, does not store all results, but generates a hash from the parameters which is than used as a random seed to generate the actual value. This will generate an equal (but not same) object when called with the same parameters.

You can mitigate the problem by making the type variable more specific, e.g.
<A extends Number>

Storing all generated values would use up additional memory. I could implemented this as an optional feature. Would that be an important improvement for you?

from jqwik.

jlink avatar jlink commented on July 20, 2024

Having had one more night to think it over, I'd even say that always returning the exact same object would be wrong, ie. would leave out behaviour that can definitely happen. In a language like Java where you can have objects with identity and changing state it's common behaviour that functions or functional interfaces create those kind of objects - and create them freshly whenever they are being invoked. Consider for example all those factory methods we use in the context of Spring et al.

If you want to constrain the type of objects to be created for A you could use a provider method like this:

@Property
<A> void aInValuePos(
	@ForAll Function<Integer, @From("valuesWithEquality") A> f,
	@ForAll Integer i
) {
	Assertions.assertThat(f.apply(i)).isEqualTo(f.apply(i));
}

@Provide
Arbitrary valuesWithEquality() {
	return Arbitraries.oneOf(
		Arbitraries.strings(),
		(Arbitrary) Arbitraries.strings().list(),
		(Arbitrary) Arbitraries.integers(),
		... // Add whatever you think could be the target type
	);
}

If you need those range of types regularly you might consider to register a default arbitrary provider.

So I close this issue as "works as designed". Feel free to reopen it if you still see a bug or want to make a feature request out of it.

from jqwik.

chisui avatar chisui commented on July 20, 2024

I understand that this is the way Java objects behave, but it would nice be nice to be able to restrict or filter which types A may take in this circumstance, without requiring A to be of a concrete subtype. equals and hashcode are part of the contract of Object so they should be implemented correctly. This may not be possible or meaningful all the time. Unfortunately Java doesn't have something like Haskells Eq or Ord (or Hashable) typeclasses. It would be nice to be able to annotate type parameters so that it's clear that only classes that implement equals and hashcode correctly should be chosen for A. Something like:

@Property
<@Eq A, @Eq B> void aInValuePos(
	@ForAll Function<A, B> f,
	@ForAll A a
) {
	Assertions.assertThat(f.apply(a)).isEqualTo(f.apply(a));
}

But I guess that would be essentially two different features. First the ability to register arbitrary providers on typeparameters and secondly the providers for @Eq and @Hashable. This would be pretty easy using Object.class.equals(targetClass.getMethod("equals", Object.class).getDeclaringClass()).

Those are some pretty specific requirements though. I can understand if you don't think that this is something that you want to support. Although being able to annotate typeparameters would be nice regardless.

from jqwik.

jlink avatar jlink commented on July 20, 2024

The first required feature is rather simple since annotations are already being considered for the usage part of the type variable, thus @Eq in

@Property
<A, B> void aInValuePos(
	@ForAll Function<@Eq A, @Eq B> f,
	@ForAll A a
)...

can be used for choosing an arbitrary.

The providers for @Eq and @Hashable are the bigger problem since with the current design of arbitrary provision the providers themselves would have to know about @Eq and @Hashable which they obviously should not. Let me think about it for a while...

from jqwik.

chisui avatar chisui commented on July 20, 2024

The advantage of declaring the Annotations at the variable declaration site would be that you could constrain all usages of that variable.

It would also be kind of inconsistent. In this example:

@Property
<A> void p(
	@ForAll @Eq A a,
	@ForAll A b
)...

would a and b resolve to different types essentially? a resolves to only types that implement equals correctly, but b would resolve to any Object?


Regarding the problem that the provider shouldn't know about @Eq etc. Some kind of filter mechanism would be useful. You could register filters for annotations that would filter the arbitraries returned by the providers. It would also be nice if there was a way for an arbitrary provider to communicate that it can handle some of these filter annotations directly in a more efficient manner.

from jqwik.

jlink avatar jlink commented on July 20, 2024

I extracted part 1 into an issue of its own: #74

As for filtering arbitraries I haven't (yet) come up with an idea how to do that without breaking existing arbitrary providers or force them to know about a filter annotations. The problem is that neither ArbitraryProvider instances nor Arbitrary instances tell anything about themselves or the kind of objects they are going to create at runtime. So the question is: How would a filter function determine if it wants to let an arbitrary - or arbitrary provider - get through or not?

from jqwik.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.