TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Overhead of Returning Optional Values in Java and Rust (2021)

179 pointsby krisgenreabout 2 years ago

15 comments

kasperniabout 2 years ago
Optional is being being converted to a value class as part of Project Valhalla. I reran the benchmarks with the latest Valhalla branch [1] and added a test that used OptionalLong instead of Optional&lt;Long&gt;.<p>Without Valhalla<p>- OptionBenchmark.sumSimple avgt 5 328,110 us&#x2F;op<p>- OptionBenchmark.sumNulls avgt 5 570,800 us&#x2F;op<p>- OptionBenchmark.sumOptional avgt 5 2223,887 us&#x2F;op<p>- OptionBenchmark.sumOptionalLong avgt 5 1201,987 us&#x2F;op<p>With Valhalla<p>- OptionBenchmark.sumSimpleValhalla avgt 5 327,927 us&#x2F;op<p>- OptionBenchmark.sumNullsValhalla avgt 5 584,967 us&#x2F;op<p>- OptionBenchmark.sumOptionalValhalla avgt 5 572,833 us&#x2F;op<p>- OptionBenchmark.sumOptionalLongValhalla avgt 5 326,949 us&#x2F;op<p>OptionalLong is now as fast as simple sum. And SumOptional is now as fast as SumNulls. So the overhead of using OptionalLong and Optional&lt;Long&gt; seems to have gone away with Valhalla.<p>It would be great if boxing could be eliminated as well. But few people writes code like what is being benchmarked (in hot loops) in practice.<p>[1] <a href="https:&#x2F;&#x2F;github.com&#x2F;openjdk&#x2F;valhalla">https:&#x2F;&#x2F;github.com&#x2F;openjdk&#x2F;valhalla</a>
评论 #35135379 未加载
评论 #35134757 未加载
评论 #35136488 未加载
marginalia_nuabout 2 years ago
I think in general these types of benchmarks makes boxed numbers look bad only because they&#x27;re being compared to <i>adding integers</i>, which is a ridiculously fast operation to start with. Accomplishing half that speed despite &quot;dereferencing a pointer&quot; is kinda insane in the light of &#x27;Latency Numbers Every Programmer Should Know&#x27;.<p>(The reason it works is because Java doesn&#x27;t actually allocate new Longs for small numbers, it fetches them from a table of constants; it&#x27;s always the same 256 objects that are being dereferenced. I don&#x27;t know their memory layout, but I&#x27;d half expect them to be sequential in memory as that&#x27;s would be much a low hanging fruit optimization. Optional&lt;Long&gt;&#x27;s performance is what you&#x27;d expect without these optimizations. Also in this scenario you really should use OptionalLong instead of Optional&lt;Long&gt; but that&#x27;s beside the point ;-)
评论 #35133728 未加载
评论 #35133515 未加载
评论 #35133963 未加载
评论 #35133494 未加载
Someoneabout 2 years ago
I think part of the problem is that Java’s Optional isn’t a<p><pre><code> Either[null, T] </code></pre> but a<p><pre><code> Either[null, boxed T, boxed null] </code></pre> ‘Boxed null’ is what the documentation (<a href="https:&#x2F;&#x2F;docs.oracle.com&#x2F;javase&#x2F;8&#x2F;docs&#x2F;api&#x2F;java&#x2F;util&#x2F;Optional.html" rel="nofollow">https:&#x2F;&#x2F;docs.oracle.com&#x2F;javase&#x2F;8&#x2F;docs&#x2F;api&#x2F;java&#x2F;util&#x2F;Optional...</a>) calls “an empty Optional”<p>That means that, for example, an <i>Optional[Byte]</i> can have 258 different values and cannot, in general, be compiled to a ”pointer to byte” because that has only 257 different values.<p>Edit: reading <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=35133241" rel="nofollow">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=35133241</a>, the plan is to change that. I fear that, by the time they get around to that, lots of code will handle the cases <i>null</i> and <i>Optional containing null</i> differently, making that a breaking change.
评论 #35133429 未加载
评论 #35133415 未加载
评论 #35142059 未加载
评论 #35137597 未加载
jeroenhdabout 2 years ago
&gt; A special “I would never write Rust like that” variant that returns the value in a Box on the heap. This is because a friend of mine, after seeing my results, told me I was cheating, because all Rust versions so far used registers&#x2F;stack to return the value, and Java was at a disadvantage due to returning on the heap (by default). So here you are.<p>Why would Rust be cheating here? Java cannot make these types of optimizations yet (though they are likely coming with Project Valhalla) but that doesn&#x27;t mean Rust should be similarly handicapped in benchmarks.<p>Java has many smart optimizations and advantages over Rust (being garbage collected for one, making it much easier to write code in, and runtime reflection, a blessing and a curse) and with tricks like rearranging objects to make more effective use of CPU caches you can end up writing Java that&#x27;s very close in performance to native, precompiled code.<p>However, when it comes to raw performance, you shouldn&#x27;t expect the standard JVM to come close to Rust. There is inherent overhead in the way the language and the runtime are designed. There is no &quot;cheating&quot; here, the algorithms are the same and some languages just produce more efficient code in these scenarios. You wouldn&#x27;t slow down the JVM to make the benchmark fair for a Python implementation either!<p>A more interesting comparison may be compiling Java to native assembly (through Graal for example) so Java too can take advantage of not having to deal with reflection and using SIMD instructions.<p>Alternatively, a Java vs C# rundown would also be more interesting, as both languages serve similar purposes and solve similar problems. C#&#x27;s language-based approach to optional values has the potential to be a lot faster than Java&#x27;s OOM-based approach but by how much remains to be seen.<p>Java vs Kotlin may also be interesting to benchmark to see if the Kotlin compiler can produce faster code than Java&#x27;s Optional; both run inside the same JVM so the comparison may be even better.
评论 #35133572 未加载
评论 #35134197 未加载
评论 #35134333 未加载
ithkuilabout 2 years ago
Rust has an interesting optimization for Option&lt;T&gt; when T has enough &quot;room&quot; for encoding a marker for &quot;None&quot;: <a href="https:&#x2F;&#x2F;google.github.io&#x2F;comprehensive-rust&#x2F;std&#x2F;box-niche.html" rel="nofollow">https:&#x2F;&#x2F;google.github.io&#x2F;comprehensive-rust&#x2F;std&#x2F;box-niche.ht...</a><p>e.g. Option&lt;NonZeroU64&gt; is effectively encoded and operated on as u64, but it gives the type system a way to make sure you correctly handle the case where &quot;0&quot; means something special for you
评论 #35133461 未加载
cryptosabout 2 years ago
The issue will probably be solved this year with value types in Java. <a href="https:&#x2F;&#x2F;openjdk.org&#x2F;jeps&#x2F;8277163" rel="nofollow">https:&#x2F;&#x2F;openjdk.org&#x2F;jeps&#x2F;8277163</a>, <a href="https:&#x2F;&#x2F;www.baeldung.com&#x2F;java-valhalla-project" rel="nofollow">https:&#x2F;&#x2F;www.baeldung.com&#x2F;java-valhalla-project</a>, <a href="https:&#x2F;&#x2F;blogs.oracle.com&#x2F;javamagazine&#x2F;post&#x2F;java-jdk-18-evolution-valhalla-panama-loom-amber" rel="nofollow">https:&#x2F;&#x2F;blogs.oracle.com&#x2F;javamagazine&#x2F;post&#x2F;java-jdk-18-evolu...</a>
评论 #35133200 未加载
rocquaabout 2 years ago
The rust NonZeroU64 solution has a subtle &#x27;bug&#x27; that happens not to matter.<p>The function<p><pre><code> fn get_optional_non_zero(n: u64) -&gt; Option&lt;NonZeroU64&gt; let i = n &amp; 0xFF; if i == MAGIC { None } else { NonZeroU64::new(i) } } </code></pre> Actually returns None for n = 0 or n is any multiple of 256.<p>The resulting usage in the sum still yields the same result, because skipping zeros in an addition doesn&#x27;t matter, but it is a subtle difference between this get-function compared to all of the others. It also doubles the number of None cases the code needs to handle.
TwentyPostsabout 2 years ago
&gt; A special “I would never write Rust like that” variant that returns the value in a Box on the heap. This is because a friend of mine, after seeing my results, told me I was cheating, because all Rust versions so far used registers&#x2F;stack to return the value, and Java was at a disadvantage due to returning on the heap (by default). Uhh, okay? This sounds a bit silly to me. It&#x27;s good to add the additional comparison, sure, but &quot;cheating&quot; is just not the right word. The point of this article is ostensibly to compare the built-in Option types, not heap allocation. The fact that Java allocates any Options on the heap is part of that comparison (and reflects badly on Java, fwiw).<p>Either way, glad to see that Rust is doing a good job eliminating the overhead. I&#x27;m not sure if arithmetic is the right kind of benchmark here, but it&#x27;d probably be difficult to measure the performance overhead across &quot;real&quot; codebases, so focusing on a tight loop microbenchmark is probably fine.
MrBuddyCasinoabout 2 years ago
Handling nulls by wrapping references in Optionals (at least if they can&#x27;t be optimised away) is IMO strictly inferior to static analysis by the compiler as in Kotlin and forcing correct error handling. Its really all you need! The problem is not nullable references, after all Optionals can contain nulls, the problem is documenting if a value can be null via the type system and correctly handling those cases.<p>Hoping Java will get this one day, but probably not...
评论 #35133334 未加载
评论 #35133128 未加载
评论 #35133466 未加载
评论 #35133208 未加载
评论 #35133693 未加载
评论 #35133360 未加载
评论 #35133207 未加载
评论 #35136121 未加载
diffuse_labout 2 years ago
My guess is that C# will be much better, since it has support for Value types.<p>Wasn&#x27;t Java supposed to get support for Value types some time ago?
评论 #35133603 未加载
评论 #35133776 未加载
评论 #35133116 未加载
评论 #35134273 未加载
评论 #35133113 未加载
Yujfabout 2 years ago
Why is the author talking about null in the intro, which implied using pointers and thus boxed objects and then running benchmarks on integers? That makes no sense to me.
评论 #35132959 未加载
评论 #35132968 未加载
layer8about 2 years ago
Note that Java’s <i>Optional</i> was never intended to be a general-purpose Maybe type or general-purpose replacement for <i>null</i>, unlike Rust’s <i>option</i>. As Brian Goetz explains in <a href="https:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;26328555&#x2F;623763" rel="nofollow">https:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;26328555&#x2F;623763</a>:<p>“<i>Our intention was to provide a limited mechanism for library method return types where there needed to be a clear way to represent &quot;no result&quot;, and using null for such was overwhelmingly likely to cause errors.<p>For example, you probably should never use it for something that returns an array of results, or a list of results; instead return an empty array or list. You should almost never use it as a field of something or a method parameter.<p>I think routinely using it as a return value for getters would definitely be over-use.</i>”
评论 #35137263 未加载
评论 #35137682 未加载
dgb23about 2 years ago
It’s interesting to see how different languages deal with nulls and similar constructs.<p>In some languages like TS, PHP or Kotlin have proper unions that you just handle with branching.<p>Rust lets you pattern match againt a construct that holds a value or doesn’t. Option is an actual thing there that you need to unpack in order to look inside.<p>In Clojure nils are everywhere. They tell you that “you’re done” in an eager recursion, or that a map doesn’t have something etc. Many functions return something or nil, and depending on what you’re doing you care about the value vs the logical implication.<p>nils flow naturally through your program and it’s not something you are worried about, as many functions do nil punning. Well as long as you don’t directly deal with Java - then you have to be more careful.
评论 #35133737 未加载
chrismorganabout 2 years ago
(2021)<p>Discussion at publication time: <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=28887908" rel="nofollow">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=28887908</a>
gjadiabout 2 years ago
Interesting.<p>This article resonate in me with the recent articles of Casey Muratori about non-pessimistic code:<p>Within the realm of the module, don&#x27;t use pessimistic code (avoid Boxing) _but_ that doesn&#x27;t prevent you to provide a safe API. E.g. the result of the loop could be wrapped if that made sense.