Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Functions.constant covariant in argument type. #1927

Closed
vincentk opened this issue Dec 22, 2014 · 6 comments
Closed

Make Functions.constant covariant in argument type. #1927

vincentk opened this issue Dec 22, 2014 · 6 comments

Comments

@vincentk
Copy link

Presently, a constant function is provided in the Functions class with a type signature as follows

public static <E> Function<Object, E> constant(@Nullable E value) 

Personally, I think that a type signature as follows would be superior

public static <Q, E> Function<Q, E> constant(@Nullable E value) 

the reason being that while functions in the "mathematical" sense are co-variant with regard to their argument types, generics in java are not (for well-known reasons).

It's probably not trivial to introduce such a change without triggering a compilation error here or there. Still I think it might be worth considering.

@lowasser
Copy link
Contributor

Generics aren't, but specific uses of generic types that happen to be covariant should be -- e.g. most places that accept a Function<F, T> should accept a Function<? super F, ? extends E> where appropriate.

Is there a place you cannot make this change to the user of the Function?

@vincentk
Copy link
Author

Here's my specific use case. I'd like to have an interface that returns a Function<A, B>. I'd like to have a dummy implementation of that, which always returns the same (constant) value. Naturally, I can build my own constant function easily (which I did), and yet it seems odd that I would need to do that.

@kevinb9n
Copy link
Contributor

Your solution is just to cast. It feels wrong because you have to suppress
a warning (and use a - gasp! - raw type!), but this is just the sort of
circumstance @SuppressWarnings is there for.

class Dummy implements Interface<A, B> {
@SuppressWarnings("unchecked") // safe contravariant cast
@OverRide Function<A, B> method() {
return (Function) Functions.constant(someB);
}
}

On Tue, Dec 23, 2014 at 5:27 AM, vincentk notifications@github.com wrote:

Here's my specific use case. I'd like to have an interface that returns a Function<A,
B>. I'd like to have a dummy implementation of that, which always returns
the same (constant) value. Naturally, I can build my own constant function
easily (which I did), and yet it seems odd I would need to do that.


Reply to this email directly or view it on GitHub
#1927 (comment).

Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb@google.com

@vincentk
Copy link
Author

There are no doubt many plausible workarounds (as it were, I am quite content with mine). It is also a very minor issue. I simply felt it noteworthy that a workaround would seem to be required in the first place. Please do feel free to close it if it isn't worth your time.

As "solutions" go though, my proposal would be to make ConstantFunction generic in the parameter type as follows:

  private static class ConstantFunction<D,E> implements Function<D, E>, Serializable {
    private final E value;

    public ConstantFunction(@Nullable E value) {
      this.value = value;
    }

    @Override
    public E apply(@Nullable D from) {
      return value;
    }

[snip]

and either change or provide an alternative to constant(T val):

    public static <D, E> Function<D, E> constantD(E value) {
        return new ConstantFunction<>(value);
    }

    public static <E> Function<Object, E> constant(E value) {
        return new ConstantFunction<>(value);
    }

Though again, I do agree that this is generics cosmetics, and perhaps not worth the possible API change/extension.

@kevinb9n
Copy link
Contributor

This same issue affects many dozens of Guava methods, and we didn't want to
handle each one differently, so we made a single decision several years
ago, with a lot of input from Bloch and Gafter. We decided that the
purpose of type parameters and wildcards in a library API is to ensure that
the method can be called with any parameter types that make logical
sense. Once that condition is met, we stop, instead of continuing to also
add type params/wildcards that serve only to let you "massage" the specific
result type you want to get. We did make a few mistakes such as
Predicates.alwaysTrue() where we didn't adhere to this rule, but we have
mostly followed it, and we are satisfied with the results.

@vincentk
Copy link
Author

Thanks for your explanation and time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants