I am defining a type Option<T> in Java that should behave as much as possible as Rust's equivalent.
It has a method, Option::flatten, that is only implemented if the inner T is some other Option<T>. I am thinking of something like this:
public class Option<T> {
/* fields, constructors, other methods */
#Bound(T=Option<U>)
public <U> Option<U> flatten() {
if (isNone()) return None();
else return this.unwrap();
}
}
But the syntax is of course completely fictional. Is there some way to make this work in Java? I know static methods are an option, but they can't be called like a normal method which is the only goal of this type.
This is not supposed to be a standalone thing, but rather a part of a larger Java implementation of Rust iterators I'm currently working on.
The problem with trying to come up with a non-static method such as flatten is that in Java one cannot conditionally add more methods to a class based on whether the type parameter of the class fulfills a certain constraint.
You can, however, make it a static method and constrain its arguments to whatever you need.
class Option<T> {
// ...
public static <U> Option<U> flatten(Option<Option<U>> option) {
if (option.isNone()) return None();
return option.unwrap();
}
}
Which would work for valid implementations of None, isNone and unwrap.
A more complete example follows.
public static class Option<T> {
private final T value;
private Option(T x) {
this.value = x;
}
public static <T> Option<T> of(T x) {
java.util.Objects.requireNonNull(x);
return new Option<>(x);
}
public static <T> Option<T> None() {
return new Option<>(null);
}
public T unwrap() {
java.util.Objects.requireNonNull(this.value);
return this.value;
}
public boolean isNone() {
return this.value == null;
}
public static <U> Option<U> flatten(Option<Option<U>> option) {
if (option.isNone()) return Option.None();
return option.unwrap();
}
#Override
public String toString() {
if (this.isNone()) {
return "None";
}
return "Some(" + this.value.toString() + ")";
}
}
Usage:
var myOption = Option.of(Option.of(5));
System.out.println("Option: " + myOption);
System.out.println("Flattened: " + Option.flatten(myOption));
Output:
Option: Some(Some(5))
Flattened: Some(5)
I think the way you want to handle this is not to actually have a flatten() method, but have different handling in your constructor. Upon being created, the constructor should check the type it was handed. If that type is Option, it should try and unwrap that option, and set its internal value to the same as the option it was handed.
Otherwise, there isn't really a way for an object to 'flatten' itself, because it would have to change the type it was bounded over in the base case. You could return a new object from a static method, but are otherwise stuck.
I want to point out some of the potential headaches and issues regarding this re-implementation of Optional<T>.
Here's how I would initially go about it:
public class Option<T> {
/* fields, constructors, other methods */
public <U> Option<U> flatten() {
if (isNone()) return None();
T unwrapped = this.unwrap();
if (unwrapped instanceof Option) {
return (Option<U>) unwrapped; //No type safety!
} else {
return (Option<U>) this;
}
}
}
However, this code is EVIL. Note the signature of <U> Option<U> flatten() means that the U is going to be type-inferenced into whatever it needs to be, not whatever a potential nested type is. So now, this is allowed:
Option<Option<Integer>> opt = /* some opt */;
Option<String> bad = opt.flatten();
Option<Option<?>> worse = opt.<Option<?>>flatten();
You will face a CCE upon using this for the other operations, but it allows a type of failure which I would say is dangerous at best. Note that any Optional<Optional<T>> can have #flatMap unwrap for you: someOpt.flatMap(Function.identity());, however this again begs the question of what caused you to arrive at a wrapped optional to begin with.
Another answer (by #NathanielFord) notes the constructor as an option, which seems viable as well, but will still face the runtime check upon construction (with it simply being moved to the constructor):
public class Option<T> {
/* fields, constructors, other methods */
public Option<T>(T someValue) { ... }
public Option<T>(Option<T> wrapped) {
this(wrapped.isNone() ? EMPTY_OBJECT : wrapped.unwrap());
}
public Option<T> flatten() {
return this; //we're always flattened!
}
}
Note as well, the re-creation of Optional<T> by
#E_net4thecommentflagger has the potential for a nasty future bug: Optional.ofNullable(null).isNone() would return true! This may not be what you want for some potential use-cases, and should #equals be implemented in a similar manner, you'd end up with Optional.ofNullable(null).equals(Optional.None()), which seems very counter-intuitive.
All of this to say, that while Rust may require you to deal with these nested optionals, you are writing code for Java, and many of the potential restrictions you faced before have changed.
Related
I realize that it is not possible to derive from primitive objects as they are declared final. How do I work around this restriction? I am programming with the JPA Criteria API. Almost everywhere I handle with my own methods having Integer/String parameters to compare against entity fields representing database table row values. On any of these parameters I would like to accept QueryParameter<Integer> or QueryParameter<String>. Doing so I would have to create the method a second time accepting query parameters instead of the literals. However, thinking about value lists (as in the QueryBuilder's in(...) method) with permutating literals and query parameters, makes it hard or even impossible to implement.
Let us assume I had an entity Car with a method withFeatures(StringRepresentation ... features) and there would be literals and query parameters had derived from the same super-class StringRepresentation which itself would have be derived from the primitive type String. I would like to do so:
myCar.withFeatures("Seat Heating", "Metallic Color", "Trailer Hitch");
myCar.withFeatures(new QueryParam<String>("MyFavourit"));
myCar.withFeatures("Seat Heating", new QueryParam<String>("LoveThatColor"), "Trailer Hitch");
Has anyone an approach or even kind of a solution for this?
I'd use a builder pattern with one method for each type of criterion.
class Car {
private Set<String> features = new HashSet();
public Car withFeature(String f) {
features.add(f);
return this;
}
public Car withFeature(QueryParameter<String> q) {
features.add(q.getStringRepresentation()); // or whatever
return this;
}
...
}
So you can say:
myCar.withFeature("Seat Heating")
.withFeature(new QueryParam<String>("MyFavourit");
with permutating literals and query parameters, makes it hard or even impossible to implement
You could leverage CharSequence for strings, but I'm not sure that's a god idea...
import lombok.RequiredArgsConstructor;
public class Test {
public static void main(String[] args) {
withFeatures("test", new StringQueryParam("test2"));
}
#SafeVarargs
public final static <T extends CharSequence> void withFeatures(T ...params) {
// Wrap in StringQueryParam if not an instance of QueryParam<String>
}
interface QueryParam<T> {
}
#RequiredArgsConstructor
static class StringQueryParam implements QueryParam<String>, CharSequence {
private final CharSequence value;
#Override
public int length() {
return value.length();
}
#Override
public char charAt(int index) {
return value.charAt(index);
}
#Override
public CharSequence subSequence(int start, int end) {
return value.subSequence(start, end);
}
}
}
Having less verbose static factory methods (e.g. QueryParam.of, QueryParam.all, etc. for query params) mixed with builders or ways to combine them effectively could help.
e.g.
// Assuming Lists.union util method
withFeatures(Lists.union(
QueryParam.all("a", "b"),
QueryParam.of("c")
));
// With static imports
withFeatures(union(params("a", "b"), param("c"));
// With ParamsBuilder
withFeatures(ParamsBuilder.of("a", "b").add(QueryParam.of("c").build())));
Hopefully that gives you some ideas on how to design the API! You may as well use a more complicated, but flexible route where the entire criteria is just an AST so that QueryParam really just is a type of Expression in the AST allowing to create composites, etc. If you look at QueryDSL everything is a DslExpression and you have visitors to execute operations against the tree.
I spent some time to solve that problem taking in the hints from the Java Community so far.
Of course I am a follower of Java's concept of type safety (thanks to plalx). Hence, my solution will probably has to do with parameterized types.
And also I do admiring the concept of design patterns like many others (thanks to tgdavies). Hence, I use the builder pattern with one method for each type of criterion. I will accept to implement car feature methods for
using plain old literals of String
as well as specifying parameters of String
That is:
myCar.withFeatures("Seat Heating", "Metallic Color", "Trailer Hitch");
as well as specifying (let's say) query parameters or String parameters of some kind with a slightly more complex way by using a static method sp(...)
myCar.withFeatures(sp("MyFavourit"));
and of course a mixture of both, introducing another static method sr(...) for string representation:
myCar.withFeatures(sr("Seat Heating"), sp("LoveThatColor"), sr("Trailer Hitch"));
The mixture of both is important in cases where we want to use variable arguments in method signatures to specify those representations, in this case car features.
As one can see, it is almost the usage I stated above when posting this question.
How can I achieve this?
At first I designed an interface to implement my different String representations against:
public interface ValueTypeRepresentation<T> {
public Class<T> getClazz();
public QueryParameter<T> getQueryParameter();
public RepresentationType getRepresentationType();
public T getValue();
}
The methods are to determine whether the representation is a literal or a parameter, and to get the literal's value resp. the parameter itself to later on use its name.
The clazz member is to ease the Java Generic Type Inference purposes because I will be using parameterized types to implement different type representations. As I said, String ist just the starter of the show.
Then I designed an abstract class to derive the concrete classes of representations of different primitive objects from:
abstract class AbstractValueTypeRepresentation<T> implements ValueTypeRepresentation<T> {
private Class<T> clazz;
private RepresentationType representationType = RepresentationType.VALUE;
private QueryParameter<T> queryParameter;
private T value;
public AbstractValueTypeRepresentation(Class<T> clazz, T value) {
this.clazz = clazz;
this.representationType = RepresentationType.VALUE;
this.value = value;
}
public AbstractValueTypeRepresentation(QueryParameter<T> qp) {
this.clazz = qp.getClazz();
this.representationType = RepresentationType.PARAM;
this.queryParameter = qp;
}
#Override
public Class<T> getClazz() {
return clazz;
}
#Override
public QueryParameter<T> getQueryParameter() {
return queryParameter;
}
#Override
public RepresentationType getRepresentationType() {
return representationType;
}
#Override
public T getValue() {
return value;
}
}
To distinguish a literal of that type from the query parameter of that type, I introduced this enumeration:
public enum RepresentationType {
PARAM, VALUE;
}
Then I designed the first concrete representation, here for my StringRepresentation (derived from the abstract class above):
public class StringRepresentation extends AbstractValueTypeRepresentation<String> {
public static StringRepresentation sr(String s) {
return new StringRepresentation(s);
}
public static StringRepresentation sp(String name) {
return new StringRepresentation(new QueryParameter<String>(String.class, name));
}
public StringRepresentation(String value) {
super(String.class, value);
}
public StringRepresentation(QueryParameter<String> queryParameter) {
super(queryParameter);
}
}
Obviously this is easy to extend to representations of Integer, Float, LocalDate, etc.
let's say that I have several Creature subclasses, and that they have each have some sort of getGroup() method that returns a List<Creature>.
What I mean by "some sort of" .getGroup() method is that the name of this function varies between subclasses. For instance, Wolfs travel in packs, so they have a getPack() member. Fish travel in schools, so they have a .getSchool() member, Humans have a getFamily() member, and so on.
.getGroup() doesn not exist in Creature, and it cannot be added to the interface. None of these clases can be edited.
I'm writing a method to print the number of Creatures in their group. How would I do this?
Essentially, I'm looking to condense these two functions into the same thing:
public void PrintSchoolSize(Fish dory) {
System.out.print(dory.getSchool().size());
}
public void PrintHiveSize(Bee bee) {
System.out.print(bee.getColony().size());
}
...into the following function:
public void printGroupSize( Class<? extends Creature> cree,
FunctionThatReturnsList getGroup() ) {
System.out.print(cree.getGroup().size();
}
I'd imagine I need to pass in a second argument (function pointer?) to void printGroupSize. Any help is very appreciated, thanks!
EDIT Thank you all for the help. This is just a simplification of the real problem I'm trying to solve. Long, overly complex problems are tougher to answer, so I posed this simpler scenario.
The only answer lies in using a generic function (if that exists). The classes I'm actually working with don't have a common interface, but they all have a function that returns a List.
What you describe in your question is not much related to Java's sense of "generic methods". You could implement it with reflection (see Class.getMethod()), but I promise you that you really don't want to go there.
It would be better for Creature to declare a possibly-abstract method getGroup() that each subclass would override. You may do that in addition to providing methods with subclass-specific names, if you wish. Code that wants to obtain the group (or its size) without knowing the specific type of creature would invoke that creature's getGroup() method. That's an application of polymorphism, which seems to be what you're actually after.
If getGroup cannot be added to the Creature interface why not add another interface to your creatures?
public interface HasGroup {
Group getGroup();
}
Would mean you can create the method:
public void printGroupSize(HasGroup cree) {
System.out.print(cree.getGroup().size();
}
The simplest way is to had a getGroup() method to the Creature interface and implement it in each subclass, but it seems you cannot do that.
If you can modify the subclasses, I would actually create a new interface CreatureGroupable with a getGroupSize() and/or getGroup(). Each subclass of Creature shall implement this interface, e.g.
public interface CreatureGroupable {
CreatureGroup getGroup();
}
public enum CreatureGroup {
WOLF_PACK("pack", 30),
GEES_FLOCK("flock", 20),
FISH_SCHOOL("school", 1000),
HUMAN_FAMILY("family", 4),
...
private final String name;
private final int size;
private CreatureGroup(String name, int size) {
this.name = name;
this.size = size;
}
public String getName() { return name; }
public int getSize() { return size; }
}
public class Wolf implements Creature, CreatureGroupable {
// methods from Creature, constructor, ...
public CreatureGroup getGroup() {
return CreatureGroup.WOLF_PACK;
}
This way, if you have a List<Creature> you can access the group of each one and do whatever you have to do, e.g.
public void printGroups(List<Creature> creatures) {
for (Creature c : creatures) {
CreatureGroup group = c.getGroup();
System.out.println("A " + group.getName() +
" has roughly " group.getSize() +
" individuals.");
}
}
If you want more flexibility, you may not use an enum and just a standard interface and class hierarchy for the groups.
Thanks to everyone for the help. Since I'm not allowed to edit any of the aforementioned classes/interfaces (I can only write external functions), I wrote the following function
public List<? extends Creature> getGroup(Object obj) {
if(obj.getClass() == Bee.class)
return ((Bee)obj).getColony();
if(obj.getClass() == Fish.class)
return ((Fish) obj).getSchool();
/* repeat for the other classes */
return null;
}
...and used it here, as so:
public void printGroupSize( Class<? extends Creature> cree ) {
System.out.print(getGroup(cree).size());
}
I have verified that this solution does indeed work, since all of the get*****() functions return a List<Creature>. This solution also shrinks my codebase significantly, and is easier to maintain than the current structure.
When you use the Visitor pattern and you need to get a variable inside visitor method, how to you proceed ?
I see two approaches. The first one uses anonymous class :
// need a wrapper to get the result (which is just a String)
final StringBuild result = new StringBuilder();
final String concat = "Hello ";
myObject.accept(new MyVisitor() {
#Override
public void visit(ClassA o)
{
// this concatenation is expected here because I've simplified the example
// normally, the concat var is a complex object (like hashtable)
// used to create the result variable
// (I know that concatenation using StringBuilder is ugly, but this is an example !)
result.append(concat + "A");
}
#Override
public void visit(ClassB o)
{
result.append(concat + "B");
}
});
System.out.println(result.toString());
Pros & Cons :
Pros : you do not need to create a class file for this little behavior
Cons : I don't like the "final" keyword in this case : the anonymous class is less readable because it calls external variables and you need to use a wrapper to get the requested value (because with the keyword final, you can't reassign the variable)
Another way to do it is to do an external visitor class :
public class MyVisitor
{
private String result;
private String concat;
public MyVisitor(String concat)
{
this.concat = concat;
}
#Override
public void visit(ClassA o)
{
result = concat + "A";
}
#Override
public void visit(ClassB o)
{
result = concat + "B";
}
public String getResult()
{
return result;
}
}
MyVisitor visitor = new MyVisitor("Hello ");
myObject.accept(visitor);
System.out.println(visitor.getResult());
Pros & Cons :
Pros : all variables are defined in a clean scope, you don't need a wrapper to encapsulate the requested variable
Cons : need an external file, the getResult() method must be call after the accept method, this is quite ugly because you need to know the function call order to correctly use the visitor
You, what's your approach in this case ? Preferred method ? another idea ?
Well, both approaches are valid and imo, it really depends on whether you would like to reuse the code or not. By the way, your last 'Con' point is not totally valid since you do not need an 'external file' to declare a class. It might very well be an inner class...
That said, the way I use Visitors is like this:
public interface IVisitor<T extends Object> {
public T visit(ClassA element) throws VisitorException;
public T visit(ClassB element) throws VisitorException;
}
public interface IVisitable {
public <T extends Object> T accept(final IVisitor<T> visitor) throws VisitorException;
}
public class MyVisitor implements IVisitor<String> {
private String concat;
public MyVisitor(String concat) {
this.concat = concat;
}
public String visit(ClassA classA) throws VisitorException {
return this.concat + "A";
}
public String visit(ClassB classB) throws VisitorException {
return this.concat + "B";
}
}
public class ClassA implements IVisitable {
public <T> T accept(final IVisitor<T> visitor) throws VisitorException {
return visitor.visit(this);
}
}
public class ClassB implements IVisitable {
public <T> T accept(final IVisitor<T> visitor) throws VisitorException {
return visitor.visit(this);
}
}
// no return value needed?
public class MyOtherVisitor implements IVisitor<Void> {
public Void visit(ClassA classA) throws VisitorException {
return null;
}
public Void visit(ClassB classB) throws VisitorException {
return null;
}
}
That way, the visited objects are ignorant of what the visitor wants to do with them, yet they do return whatever the visitor wants to return. Your visitor can even 'fail' by throwing an exception.
I wrote the first version of this a few years ago and so far, it has worked for me in every case.
Disclaimer: I just hacked this together, quality (or even compilation) not guaranteed. But you get the idea... :)
I do not see an interface being implemented in your second example, but I believe it is there. I would add to your interface (or make a sub interface) that has a getResult() method on it.
That would help both example 1 and 2. You would not need a wrapper in 1, because you can define the getResult() method to return the result you want. In example 2, because getResult() is a part of your interface, there is no function that you 'need to know'.
My preference would be to create a new class, unless each variation of the class is only going to be used once. In which case I would inline it anonymously.
From the perspective of a cleaner design, the second approach is preferrable for the same exact reasons you've already stated.
In a normal TDD cycle I would start off with an anonymous class and refactored it out a bit later. However, if the visitor would only be needed in that one place and its complexity would match that of what you've provided in the example (i.e. not complex), I would have left it hanging and refactor to a separate class later if needed (e.g. another use case appeared, complexity of the visitor/surrounding class increased).
I would recommend using the second approach. Having the visitor in its full fledged class also serves the purpose of documentation and clean code. I do not agree with the cons that you have mentioned with the approach. Say you have an arraylist, and you don't add any element to it and do a get, surely you will get a null but that doesn't mean that it is necessarily wrong.
One of the points of the visitor pattern is to allow for multiple visitor types. If you create an anonymous class, you are kind of breaking the pattern.
You should change your accept method to be
public void accept(Visitor visitor) {
visitor.visit(this);
}
Since you pass this into the visitor, this being the object that is visited, the visitor can access the object's property according to the standard access rules.
So, I have some code that looks approximately like (truncated for brevity - ignore things like the public member variables):
public class GenericThingy<T> {
private T mValue;
public final T[] mCandidates;
public GenericThingy(T[] pCandidates, T pInitValue) {
mCandidates = pCandidates;
mValue = pInitValue;
}
public void setValue(T pNewValue) {
mValue = pNewValue;
}
}
public class GenericThingyWidget {
private final GenericThingy<?> mThingy;
private final JComboBox mBox;
public GenericThingyWidget (GenericThingy<?> pThingy) {
mThingy = pThingy;
mBox = new JComboBox(pThingy.mCandidates);
//do stuff here that makes the box show up
}
//this gets called by an external event
public void applySelectedValue () {
mThingy.setValue(mBox.getSelectedItem());
}
}
}
My problem is that the mThingy.setValue(mBox.getSelectedItem()); call generates the following error:
The method setValue(capture#4-of ?) in the type Generics.GenericThingy<capture#4-of ?> is not applicable for the arguments (Object)
I can get around this by removing the <?> from the declaration of mThingy and pThingy in GenericThingyWidget - which gives me a "GenericThingy is a raw type. References to GenericThingy should be parameterized" warning.
I also tried replacing the setValue call with
mThingy.setValue(mThingy.mCandidates[mBox.getSelectedIndex()]);
which I genuinely expected to work, but that produced a very similar error:
The method setValue(capture#4-of ?) in the type Generics.GenericThingy<capture#4-of ?> is not applicable for the arguments (capture#5-of ?)
Is there any way to do this without generating "raw type" warnings ("unchecked cast" warnings I'm OK with) and without making GenericThingyWidget into a generic type? I'd think I could cast the return of mBox.getSelectedItem() to something, but I can't figure out what that would be.
As a bonus question, why does the replacement call to mThingy.setValue not work?
You lack information in GenericThingyWidget.
The ? you put means : any class extending object. Which means any, not some particular one but I don't know which one. Java can't relate one ? to another, they can not be related one to the other in a class hierarchy tree. So
mThingy.setValue(mThingy.mCandidates[mBox.getSelectedIndex()]);
this tries to put an object of any class in the setValue, which is waiting for any other class, but the ? can not tell Java these two any should be the same class.
Without parameterizing GenericThingyWidget, I don't see any way to work around it.
What I would do : parameterize GenericThingyWidget, and create a Factory static parameterized method :
public static <T> GenericThingyWidget<T> make(T someObject){
...
}
I see two possibilities.
With a private addition to GenericThingyWidget— Goetz's capture helper pattern:
public void applySelectedValue() {
helper(mThingy, mBox.getSelectedIndex());
}
private static <T> void helper(GenericThingy<T> pThingy, int pIndex) {
pThingy.setValue(pThingy.mCandidates[pIndex]);
}
Or, quick-and-dirty, with a modification to the API of GenericThingy:
public void setValue(int value) {
mValue = mCandidates[value];
}
As a bonus question, why does the replacement call to mThingy.setValue not work?
The article by Brian Goetz probably explains this better than I will, but I'll give it a try.
mThingy.setValue(mThingy.mCandidates[mBox.getSelectedIndex()]);
The compiler knows that mThingy has some type parameter, but it doesn't know what the that type is, because it is a wildcard. It creates a placeholder for this type—"capture#4-of ?". The compiler also knows that mCandidates has some type, but it doesn't know what it is either. It creates brand new "capture" type—"capture#5-of ?" While you and I can reason that these should be the same type, the compiler (at least for now) can't jump to that conclusion. Thus, you get the error message.
The capture helper gets around that. Although the compiler doesn't know what the type is, it knows it has a type, so it allows you to pass it to the helper method. Once inside the helper method, there are no wildcards, and the compiler doesn't have to do any reasoning about whether the wildcards really refer to the same type.
Update
OK, try this:
public class GenericThingy<T> {
private Class<T> mClazz;
private T mValue;
public final T[] mCandidates;
public GenericThingy(Class<T> clazz, T[] pCandidates, T pInitValue) {
mClazz = clazz;
mCandidates = pCandidates;
mValue = pInitValue;
}
public void setValue(Object newValue) throws ClassCastException {
mValue = mClazz.cast(newValue);
}
}
What you need to to is parameterize GenericThingyWidget like so:
public class GenericThingyWidget<T> {
private final GenericThingy<? super T> mThingy;
private final JComboBox mBox;
public GenericThingyWidget (GenericThingy<? super T> pThingy) {
mThingy = pThingy;
mBox = new JComboBox(pThingy.mCandidates);
//do stuff here that makes the box show up
}
//this gets called by an external event
public void applySelectedValue () {
mThingy.setValue((T) mBox.getSelectedItem());
}
}
}
Technically, you don't need the ? super T for your example, and would be fine with just a T, and perhaps it would be better in real code if you ever want to get from the GenericThingy instead of just inserting into it.
As KLE said, You can just de-parameterize GenericThingy (replace all the T's with objects). In fact, I think you have to unless you plan to pass the class of T to the constructor of GenericThingyWidget, and then dynamically cast from your mbox.getSelectedItem(), since as far as I can tell, getSelectedItem() only returns Object.
Why is the compiler unable to infer the correct type for the result from Collections.emptySet() in the following example?
import java.util.*;
import java.io.*;
public class Test {
public interface Option<A> {
public <B> B option(B b, F<A,B> f);
}
public interface F<A,B> {
public B f(A a);
}
public Collection<String> getColl() {
Option<Integer> iopt = null;
return iopt.option(Collections.emptySet(), new F<Integer, Collection<String>>() {
public Collection<String> f(Integer i) {
return Collections.singleton(i.toString());
}
});
}
}
Here's the compiler error message:
knuttycombe#knuttycombe-ubuntu:~/tmp/java$ javac Test.java
Test.java:16: <B>option(B,Test.F<java.lang.Integer,B>) in
Test.Option<java.lang.Integer> cannot be applied to (java.util.Set<java.lang.Object>,
<anonymous Test.F<java.lang.Integer,java.util.Collection<java.lang.String>>>)
return iopt.option(Collections.emptySet(), new F<Integer, Collection<String>>() {
^
1 error
Now, the following implementation of getColl() works, of course:
public Collection<String> getColl() {
Option<Integer> iopt = null;
Collection<String> empty = Collections.emptySet();
return iopt.option(empty, new F<Integer, Collection<String>>() {
public Collection<String> f(Integer i) {
return Collections.singleton(i.toString());
}
});
}
and the whole intent of the typesafe methods on Collections is to avoid this sort of issue with the singleton collections (as opposed to using the static variables.) So is the compiler simply unable to perform inference across multiple levels of generics? What's going on?
Java needs a lot of hand holding with its inference. The type system could infer better in a lot of cases but in your case the following will work:
print("Collections.<String>emptySet();");
First you can narrow down your problem to this code:
public class Test {
public void option(Collection<String> b) {
}
public void getColl() {
option(Collections.emptySet());
}
}
This does not work, you need a temporary variable or else the compiler cannot infer the type. Here is a good explanation of this problem: Why do temporary variables matter in case of invocation of generic methods?
Collections.emptySet() is not a Collection<String> unless Java knows that it needs a Collection<String> there. In this case, it appears that the compiler is being somewhat silly about the order that it tries to determine types, and tries to determine the return type of Collections.emptySet() before trying to determine the intended template parameter type for B is actually String.
The solution is to explictly state that you need Collections.<String>emptySet(), as mentioned by GaryF.
It looks like a typecasting issue - i.e., that it's being required to cast Object (in Set<Object>, which would be the type of the empty set) to String. Downcasts are not, in the general case, safe.