java
Java reiser til Valhall, hvor verditypene gror
Verdityper og prosjektet Valhalla skal modernisere Java, med bedre ytelse i minnet som resultat. Og det er vanskeligere enn det høres ut – nærmere bestemt som «seks sammenfiltrede ph.d-avhandlinger», mener oppfinneren av språket.
Java har ikke lenger samme dominans innen programmering som tidligere. Særlig Python og Javascript har inntatt tronen i flere popularitetsmålinger for programmeringsspråk.
Men språket er fortsatt det foretrukne valget for forretningsprogrammering i mange bransjer. Bedømt ut fra det store antallet varianter av åpen kildekode-utgaven OpenJDK, ser det ikke til at Java er på vei ut av døren foreløpig.
Oracle, som eier Java som varemerke og står i spissen for utviklingen av språket, har i mange år vært bekymret for at språket framstår som nedstøvet sammenlignet med nyere, moderne språk. Det har tidligere resultert i strategien «Java first», som handler om at språket skal moderniseres og være konkurransedyktig når det gjelder ytelse og utviklerproduktivitet.
Verdityper gjør kål på langsom hukommelse
Oracles topputvikler for Java, Brian Goetz, har gjennom flere år stått i spissen for prosjektet Valhalla, som blant andre tiltak skal innføre verdityper i Java. Det har ikke vært så vanskelig i selve språket, men komplisert på kjøresiden. For nylig har Goetz og kolleger løftet på sløret en smule om de kommende forbedringene.
Øvelsen handler blant annet om å få gjort kål på et sentralt problem i moderne maskinvare, som ikke fantes i Javas barndom, da oppfinneren James Gosling gjorde de grunnleggende designvalgene:
At det i dag tar i størrelsesordenen tusenvis av ganger så lang tid å hente en verdi fra minnet i store lager – heapspace – som det tar CPU-en å utføre en operasjon.
Derfor er moderne CPU-er utstyrt med sitt eget minne, L1-, L2- og L3-cache, slik at kjøremiljøet kan hente en skikkelig klump med data på en gang, i stedet for å fordele byrden over mange små og langsomme innlesninger.
I Java kan et objekts felter – objektets graf – prinsipielt sett være spredt over hele heapspace, og dermed fungerer ikke cache-trikset.
Derfor er det bruk for objekter hvor data er stuet sammen, slik at de kan kopieres på én gang til CPU-cachen eller opprettes på stakken, som er der kjøremiljøet holder styr på funksjonskall og lokale variabler.
Dette er det mye enklere å oppnå med verdityper enn med dagens klasser i Java.
En annen mulighet med verdiklasser er å «inline» dem, altså skrive dem direkte inn i bytekoden, som er de instruksjonene som den virtuelle Java-maskinen JVM behandler. Dermed må ikke objektet opprettes, og det må heller ikke opprettes minne i det langsomme heapspace.
Kostbar identitet
Javas nåværende objekter har identitet – hvert objekt er unikt. Det muliggjør fasiliteter som for eksempel mutasjon av felter og låsing, opplyses det i et foreløpig utkast til verdiklasser.
Men mange klasser utnytter ikke disse fasilitetene, og andre har ikke behov for identitet.
«Deres feltverdier kan settes permanent under instansieringen, […] og deres foretrukne begrep om ekvivalens skjelner ikke mellom separat tildelte instanser med matchende feltverdier.»
Slik objekter er altså «ens», feltene deres matcher hverandre. Dette har betydning i samlinger, som lister, «maps» og «sets».
Under kjøring kan støtte av identitet være kostbart, heter det i utkastet.
«Det krever generelt at et objekts data er plassert på et bestemt sted i hukommelsen, pakket med metadata for å støtte hele objektets funksjonalitet.»
Felter aksesseres ved hjelp av minneinnlesninger. Dette er, som tidligere nevnt, langsomme operasjoner.
«Når objekter deles mellom programkomponenter, ender datastrukturer og «garbage collector»-prosesser i sammenfiltrede, ikke-lokale flettverk av objekter som er opprettet på ulike tidspunkter. Noen ganger kan JVM-implementeringer optimalisere rundt disse begrensningene, men de resulterende forbedringene av ytelsen kan være uforutsigbare og upålitelige.»
De kommende verdiklasser gir utviklere mulighet til å velge vekk objektidentitet, og til gjengjeld få mange av de fordelene som primitive typer gir, uten å gi avkall på de andre fasilitetene som Java-klasser tilbyr.
Verdiklasser er alminnelige referansetyper, akkurat som dagens Java-objekter, og drar nyttet av eksisterende JVM-optimaliseringer. Visse eksisterende klasser i bibliotekene, slik som LocalDate, er allerede merket som «value-based» for å avskrekke brukerne mot å benytte instansers identitet.
Begrensninger for verdiklasser
I utkastet kan en verdiklasse se slik ut:
En verdiklasse er underlagt en rekke begrensninger:
Klassen er «final» og kan dermed ikke nedarves, og den kan ikke være abstrakt. Alle felter er «final», slik at de kan tildeles nøyaktig én gang av «constructors» eller med initialisering. Superklassen er enten «Object» eller en tilstandsløs, abstrakt klasse. «Constructors» kan ikke kalle super(), hvor superklassens «constructor» utføres, og ingen instansmetoder kan være «syncronized», altså låst ved parallell kjøring.
Men ellers ligner en verdiklasse i høy grad på de gammeldagse identitetsklassene. Den kan implementere «interfaces», ta typeparametre, ha omsluttende instanser, indre klasser «overloaded constructors», statiske felter og alle slags adgangsbegrensninger for felter og metoder.
«Records», som ble fullført med Java 16, er opplagt som verdiklasser, heter det, fordi feltene allerede er «final».
Det kan se slik ut:
Verdiobjekter opprettes og behandles akkurat som normale objekter:
Operatoren == sammenligner verdiobjekter av samme klasse med hensyn til deres feltverdier, og altså ikke med hensyn til objektets identitet. Felter med primitive typer sammenlignet ut fra deres bitmønstre. Andre feltverdier – både identitets- og verdiobjekter –sammenlignes rekursivt med ==.
Det dreier seg fortsatt om et utkast, så verdiklasser kan altså bli endret sammenlignet med det er beskrevet i denne artikkelen.
Brukerdefinerte, primitive typer
En spesiell form for verdiklasser er brukerdefinerte, primitive typer. Som navnet antyder, dreier det seg om klasser som har samme karakteristika som Javas innebygde, primitive typer – for eksempel int og byte.
Dette er beskrevet i et annet forslag, som interessant nok er en «preview», og som derfor er nærmere målstreken enn utkastet til verdiklasser. Utviklerlaget er ikke noe for å sette en dato for når forbedringene kan tenktes å debutere i den offisielle Java, men status som «preview» kan tyde på at nyhetene ikke er så langt unna.
Primitive klasser gir programmerere mulighet til å definere nye, primitive typer. Programmer kan bruke av klassens fasiliteter uten å gi avkall på de fordeler som primitive typer gir når det gjelder yteevne.
Bruksmulighetene for primitive klasser inkluderer talltyper som ikke er innebygget i Java, slik som bytes ute fortegn, 128 bit heltall og flyttall med halv presisjon. Den sistnevnte muligheten er noe man ser innen stordata, kunstig intelligens og beregninger i superdatamaskiner, hvor lavere desimaltalloppløsning ikke nødvendigvis gir vesentlig dårligere presisjon i sluttresultatene.
Andre eksempler er punkter, komplekse tall, farger, vektor og andre flerdimensjonale, numeriske tall, tall med enheter, slik som fysiske størrelser og valuta, bitmasker, oppføringer i maps og interne datastrukturer, ty\upler og aggregering av primitive typer.
Gosling: Som seks sammenfiltrede ph.d-avhandlinger
Endelig skal Javas eksisterende «wrapper»-klasser for primitive typer – som Integer og Boolean – migreres til samme form som brukerdefinerte, primitive typer.
Når verdiklasser og primitive typer er i orden, fortsetter Valhalla-prosjektet med universell typeparametrisering, som skal forene håndteringen av referansetyper og primitive typer i det henseende. Deretter kommer turen til såkalt spesialisert typeparametrisering hvor typeinformasjon, i motsetning til i dag, også er tilstede under kjøringen, med de muligheter som det gir.
Prosjektet er omfattende. Brian Goetz med flere skriver:
«I 2014 beskrev James Gosling det som seks ph.d-avhandlinger som er filtret sammen.»
Den tekniske og svært tilgjengelige gjennomgangen av implementeringen av verdityper i JVM-en, er gjennomgått av de samme forfatterne her.
Denne artikkelen ble først publisert på Version 2.