Date: Thu, 28 Mar 2024 11:30:11 +0000 (UTC) Message-ID: <911943488.1135.1711625411861@34fc92c9345b> Subject: Exported From Confluence MIME-Version: 1.0 Content-Type: multipart/related; boundary="----=_Part_1134_1370989947.1711625411861" ------=_Part_1134_1370989947.1711625411861 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Content-Location: file:///C:/exported.html
A number of people describe Valhalla rec= ently as being "primarily about performance". While it is un= derstandable why people might come to that conclusion -- many of the motiva= tions for Valhalla are, in fact, rooted in performance considerations -- th= is characterization misses something very important. Yes, performance= is an important part of the story -- but so are safety, <= strong>abstraction, encapsulation, expres= siveness, maintainability, and compatible= library evolution.
The major goals of Valhalla are:&= nbsp;
Java's approach of "(almost) everything is an object"= em> was a reasonable match for the hardware and compilation technology of t= he mid-nineties, when the cost of a memory fetch and an arithmetic operatio= n were of comparable magnitude. But since then, these costs have dive= rged by a factor of several hundred. At the same time, memory costs have co= me to dominate application provisioning costs. These two consideratio= ns combine to make the graph-of-small-objects data representation, which ty= pical Java programs result in, suboptimal in both program performance and p= rovisioning cost.
The root cause of this is a partly accid= ental one: object identity. Every object has an identity, but not all= objects need an identity -- many objects represent values, s= uch as decimal numbers, currency amounts, cursors, or dates and times, and = do not need this identity. This need to preserve identity foils many = otherwise powerful optimizations.
Our solution for this is value types; value types = are aggregates, like traditional Java classes, that renounce their identity= . In return, this enables us to create data structures that are f= latter (because values can be inlined into objects, arrays, and other = values, just as primitives are today) and denser (because we don't= waste space on object headers and pointers, which can increase memory usag= e by up to 4x), with a programming model more like objects -- supporting no= minal substructure, behavior, subtyping, and encapsulation. "Codes like= a class, works like an int."
If you view values as being "faster obje= cts", you could indeed view this fundamental aspect of Valhalla as being pr= imarily about efficiency. But equally, you could view them as "progra= mmable primitives", in which case it also becomes about better abstraction,= encapsulation, readability, maintainability, and type safety.
Which is the real point -- that we need = not force users to choose between abstraction/encapsulation/safety and perf= ormance. We can have both. Whether you call that "cheaper objec= ts" or "richer primitives", the end result is the same.
Generics are currently limited to abstra= cting only over reference types. Sometimes this is merely a performan= ce cost (one can always appeal to boxing), but in reality this not only inc= reases the cost, but decreases the expressiveness, of libraries.
Methods like Arrays.fill() have to be written nine times; t= his is nine methods to write, nine methods to test, and nine methods for th= e user to wade through in the docs.
Real-world libraries like Streams often resort to hand-code= d specializations like IntStream; not only is this an inconvenience for the= writer, but was also a significant constraint in the design of the stream = library, forcing some undesirable tradeoffs. And this approach rarely provi= des total coverage; users complain that we have IntStream and LongStream bu= t not CharStream. (For generic types with multiple type variables, li= ke Map, the number of specializations starts to explode out of control.)&nb= sp; The functional interfaces introduced in Java 8 are another consequence = of the limitations of generics; because generics are boxed and erased, we h= ad to provide a large number of hand-specialized versions (and still, not a= ll the ones people want.) You don't need Predicate if you have can si= mply say Function<T, boolean> and not suffer boxing or erasure.
Everyone would be better off if we could= write a generic class or method once -- and abstract over all the possible= data types, not just reference types. (This includes not only primit= ives and values, but also void. Treating void uniformly is no mere "a= bstract all the things"; HashSet is based on HashMap, for implementation co= nvenience, but suffers a lot of wasted space as a result; we could use a Ha= shMap<T, void>. And the XxxConsumer functional interfaces are r= eally just Function<T, void> -- we don't need separate abstractions h= ere.)
Being able to write things once -- rathe= r than having an ad-hoc explosion of types and implementations (which often= propagates into further explosion at the client site) -- means simpler, mo= re expressive, more regular, more testable, more composible libraries. = ; Without giving up performance when dealing with primitives and values, as= boxing does today.
Which is to say, again, just at the data= -abstraction layer instead of the data-modeling layer: we need not force us= ers to choose between abstraction/encapsulation/safety and performance.
The breadth and quality of Java librarie= s is one of the core assets of the Java ecosystem. We don't want peop= le to have to replace their libraries to migrate to a value-ful world; nor = do we want existing libraries to be "frozen in time." (Imagine if we did la= mbdas and streams, but didn't do default methods, that allowed the Collecti= on classes to evolve to take advantage of them -- Collections would have in= stantly looked ten years older.) There should be a straightforward path to = extending existing libraries -- especially core JDK libraries -- to support= ing values and enhanced generics, in a way that makes them "look built in".= This may require additional linguistic tools to allow libraries to e= volve while providing compatibility with older clients and subclasses that = have not yet migrated.
Just providing these features for new li= braries is not enough; if widely used libraries can't compatibly evolve to = take advantage of this new world, they are effectively consigned to a slow = death. This might be OK for some classes -- deprecating OldX and replacing = it with NewX -- but only when uses of the OldX types aren't strewn through = lots of other libraries. That rules out starting fresh with Collectio= ns, Streams, JSR-310, and many other abstractions, without rewriting the wh= ole JDK (and many third party libraries). So instead, we have to prov= ide a compatible path for such libraries (and their clients) to modernize.<= /span>
So, to summarize: Valhalla may be motiva= ted by performance considerations, but a better way to view it as enhancing= abstraction, encapsulation, safety, expressiveness, and maintainability --= without giving up performance.