Reputation: 33395
I have written a purely functional collection class - a bag aka multiset - and it works fine, but generates a number of warnings for unchecked assignment, both in the class definition itself and in use, particularly in and using FBag.make
. As far as I can see, the problem arises primarily from the fact that functional collections want static factory methods instead of public constructors, and static methods cannot access the generic type.
Is there an elegant way to avoid this, or do I just have to bite the bullet, accept that this is a type erasure issue, and suppress the warnings?
Code follows. (I'm aware this implementation is asymptotically inefficient. N is expected to be small; if that changes, I will change the implementation.)
import java.util.Collection;
import java.util.Iterator;
public class FBag<E> implements Iterable<E> {
public static final FBag EMPTY = new FBag<>(null, null);
private final FBag<E> next;
private final E val;
private FBag(E val, FBag<E> next) {
this.val = val;
this.next = next;
}
public FBag<E> add(E val) {
return new FBag<>(val, this);
}
@Override
public Iterator<E> iterator() {
return new Iter<>(this);
}
public static FBag make(Collection c) {
var p = EMPTY;
for (var a : c) {
p = p.add(a);
}
return p;
}
public static FBag make(Object[] c, int from, int to) {
var p = EMPTY;
for (var i = from; i < to; i++) {
p = p.add(c[i]);
}
return p;
}
public FBag<E> remove(E val) {
if (this == EMPTY) {
return this;
}
if (this.val == val) {
return next;
}
return new FBag<>(this.val, next.remove(val));
}
private static class Iter<E1> implements Iterator {
private FBag<E1> p;
Iter(FBag<E1> p) {
this.p = p;
}
@Override
public boolean hasNext() {
return p != EMPTY;
}
@Override
public Object next() {
assert p != EMPTY;
var r = p.val;
p = p.next;
return r;
}
}
}
Upvotes: 3
Views: 391
Reputation: 393841
For the static
member EMPTY
, I believe there is no way around using the raw type. You can see the same in Collections.EMPTY_LIST
:
@SuppressWarnings("rawtypes")
public static final List EMPTY_LIST = new EmptyList<>();
@SuppressWarnings("unchecked")
public static final <T> List<T> emptyList() {
return (List<T>) EMPTY_LIST;
}
Therefore, all you can do here is suppress the warning:
@SuppressWarnings("rawtypes")
public static final FBag EMPTY = new FBag<>(null, null);
@SuppressWarnings("unchecked")
public static final <T> FBag<T> empty() {
return (FBag<T>) EMPTY;
}
On the other hand, for the static
methods you can declare their own generic type variables.
public static <E> FBag<E> make(Collection<E> c) {
FBag<E> p = empty ();
for (E a : c) {
p = p.add(a);
}
return p;
}
public static <E> FBag<E> make(E[] c, int from, int to) {
FBag<E> p = empty ();
for (int i = from; i < to; i++) {
p = p.add(c[i]);
}
return p;
}
(I replaced the var
s with explicit declarations, since I don't have Java 10 installed, and I didn't want to post unchecked code).
Upvotes: 2
Reputation: 311403
static
method can have their own generic declarations, which you can use to create an Fbag<T>
from a Collection<T>
or T[]
:
public static <T> FBag<T> make(Collection<? extends T> c) {
var p = EMPTY;
for (var a : c) {
p = p.add(a);
}
return p;
}
public static <T> FBag<T> make(T[] c, int from, int to) {
var p = EMPTY;
for (var i = from; i < to; i++) {
p = p.add(c[i]);
}
return p;
}
Upvotes: 2