7 ms·
GC performance isn't the only thing you need to care about here. Iterating over an ArrayList<T> in Java already makes you chase pointers all over the place due
by pdpi 4y ago
GC performance isn't the only thing you need to care about here. Iterating over an ArrayList<T> in Java already makes you chase pointers all over the place due to Java's lack of value types, which wrecks cache locality. ArrayList<Optional<T>> just makes you chase two pointers for each object instead.
- CHY872 4y agoJava uses thread local allocation buffers such that objects allocated one after another are typically contiguous in RAM. Most modern Java gcs are also compacting, meaning that the heap ends up approximately breadth first ordered after GC. What this means is that in practice, pointer chasing is less of an issue than you’d expect. Even a linked list will end up with decent cache locality. Obviously this won’t always work, but it generally works a lot better than the same structure in a systems language. https://shipilev.net/jvm/anatomy-quarks/11-moving-gc-locality/ https://shipilev.net/jvm/anatomy-quarks/11-moving-gc-localit...
- vips7L 4y agoList<Optional<T>> is pure insanity fwiw. Filter out your empties before making the list.
- bobbylarrybobby 4y agoWhat if you have an in-memory DataFrame? Not hard to end up with something that looks like List<Optional<T>> (say, NullableSeries<T>) as one of the columns.
- pdpi 4y agoSure, but Optional<T> is what we were already discussing, and List<T> is the collection type that most obviously requires no indirection. Feel free to replace Optional<T> with any other sort of sum type and the point still stands — you always have one extra object between the list and the "actual value".
- yakubin 4y ago> List<T> is the collection type that most obviously requires no indirection. Collections in Java as of now (before project Valhalla) are actually collections of pointers to objects, so at least one level of indirection. Another level of indirection is List itself, which is an interface, so the compiler can’t ahead of time devirtualise method calls, only after JIT detects which List implementation it’s dealing with at runtime.
- kaba0 4y agoVirtual calls are trivial optimizations and doesn’t really matter here either way as it only has to happen once, no matter the list size.
- pdpi 4y agoSorry, I wasn't clear: Tree maps have built-in indirection, hash maps can use open addressing but they can also use chaining, which has indirection. An array-backed list is the only collection type that obviously requires no indirection in concept. In a world where Java has value types, you could build ArrayList<T> with no indirection (other than polymorphism/dispatch).
- masklinn 4y agoNothing insane about it, e.g. you might be using some sort of SoA structure and that specific component is optional.
- vips7L 4y agoIf you're using an SoA pattern you're already optimizing for performance and, imo, should be using null to begin with.
- pdpi 4y agoThat's the point, though. Java's Optional<T> always incurs that extra cost, but e.g. Kotlin's T? doesn't have that (because ? just allows null), and Rust has an optimisation for Option<Box<T>> that reduces the representation to a single pointer (and the empty case is a null pointer). You absolutely can have that level of optimisation while still having the optional type.