Similarly to how Trove4j generates primitive supporting collections (i.e. no boxing for generics), maybe we could do the same to speed up the collections (at least for long and double).
We could generate them somehow (https://github.com/eiiches/specialize-java seem too primitive -- pun intended -- for this job, but Scala's (AFAIK pretty buggy specialized impl) might be a good start); or simply maintain them by hand.
There might be problems with inherited methods and lambdas -- or anything that needs generics inside the class, though.
However, it might still be worth doing it, as a quick rewrite of Array proves that boxing longs for storage and unboxing them for retrieval makes it about ~8x slower, i.e.
public static class CreateAndConsume extends Base {
@Benchmark
public long java_mutable() {
final ArrayList<Long> values = new ArrayList<>(CONTAINER_SIZE);
for (int i = 0; i < CONTAINER_SIZE; i++) {
values.add(ELEMENTS[i]);
}
long aggregate = 0;
for (int i = 0; i < values.size(); i++) {
aggregate ^= values.get(i);
}
assert aggregate == EXPECTED_AGGREGATE;
return aggregate;
}
@Benchmark
public long slang_persistent_generics() {
final Array<Long> values = Array.ofAll(ELEMENTS);
long aggregate = 0;
for (int i = 0; i < values.length(); i++) {
aggregate ^= values.get(i);
}
assert aggregate == EXPECTED_AGGREGATE;
return aggregate;
}
@Benchmark
public long slang_persistent_long() {
final LongArray values = LongArray.ofAll(ELEMENTS);
long aggregate = 0;
for (int i = 0; i < values.length(); i++) {
aggregate ^= values.get(i);
}
assert aggregate == EXPECTED_AGGREGATE;
return aggregate;
}
}
results in
CreateAndConsume slang_persistent_long/java_mutable 5.90x 7.83x 8.93x
CreateAndConsume slang_persistent_long/slang_persistent_generics 7.38x 8.30x 8.17x
and it even uses ~2-3x less memory than both:
java_mutable for 10 = 272 bytes
java_mutable for 100 = 1.9 KB
java_mutable for 1000 = 26.2 KB
slang_persistent_generics for 10 = 264 bytes
slang_persistent_generics for 100 = 1.9 KB
slang_persistent_generics for 1000 = 26.2 KB
slang_persistent_long for 10 = 112 bytes
slang_persistent_long for 100 = 832 bytes
slang_persistent_long for 1000 = 7.8 KB
@danieldietrich, @ruslansennov, @eduardmanas, @zsolt-donca, opinions?
I believe this will be not important in the future (see JEP218)
... albeit Java 10 is not due until at least 2019/20
This is how I see it:
Pros:
Cons:
My suggestion is to first complete the suite of JMH benchmarks and then try to make the existing collections as efficient as possible. After that, if we feel the pros outweigh the cons, then let's go for it!
Thank you for the suggestion. I intentionally not added them because of
I will close this issue because specialization for primitive types are out of focus for Javaslang.
@danieldietrich: https://www.youtube.com/watch?v=Tc9vs_HFHVo :)
Note: Lorinc did Vector optimizations that provide more performant primitive support _under the hood_, i.e. no specialization on the type level was necessary!