Referenčna preglednost je lastnost delov računalniških programov. Del programa imenujemo "referenčno pregleden", če ga lahko nadomestimo z vrednostjo, ki jo vrača, ne da bi spremenili obnašanje programa. Referenčno pregledna funkcija mora biti čista - vedno vrne enak izhod za enak vhod in ne sme imeti stranskih učinkov - delov programa, ki izvajajo drugo dejanje kot vračanje vrednosti. Nasprotje referenčne preglednosti je referenčna nepreglednost, kjer zamenjava izraza z njegovo vrednostjo lahko spremeni obnašanje programa.

Kaj to pomeni v praksi

V matematiki so vse funkcije referenčno pregledne, saj lahko matematična funkcija samo sprejme argument in vrne vrednost. Pri programiranju to ne velja vedno: funkcija lahko na primer preveri trenutni čas, bere ali piše datoteke, spreminja stanje programa ali na zaslon izpiše sporočilo. Zaradi tega se v programiranju za funkcije brez vrnitne vrednosti ali z efekti včasih uporabljajo drugačna imena, kot so postopki ali procedure.

Primeri čistih in nečistih funkcij

  • Čista funkcija: funkcija, ki le izračuna vrednost iz vhodnih parametrov in nima stranskih učinkov. Primer v pseudo kodi:
    function add(x, y) {   return x + y; }
    Pri enakih x in y bo vedno vrnila isti rezultat in jo lahko varno nadomestimo z rezultatom.
  • Nečista funkcija: funkcija, ki poleg vrnitve vrednosti spreminja stanje ali je odvisna od zunanjega stanja:
    function getCurrentTime() {   return Date.now(); }  function logAndReturn(x) {   console.log(x);   return x; }
    Ti primeri niso referenčno pregledni, ker vrneta različne rezultate ali povzročita učinke ob vsakem klicu.

Koristi referenčne preglednosti

Referenčna preglednost ponuja številne praktične prednosti za programerje in prevajalnike:

  • Lažje dokazovanje pravilnosti programov: ker se izraze obravnava kot neodvisne enote, je lažje formalno preveriti, da program počne to, kar naj bi počel.
  • Poenostavitev algoritmov in kode: delovne enote je mogoče zamenjati z njihovimi rezultati, s čimer se odpravi odvečno računanje.
  • Lažje vzdrževanje in refaktoriranje: spremembe v enem delu kode manj verjetno vplivajo na drugje, če so funkcije čiste.
  • Boljše možnosti optimizacije: prevajalniki in izvajalna okolja lahko varno izvajajo prepisovanje in druge optimizacije, ki pospešijo izvajanje ali zmanjšajo porabo pomnilnika.
  • Enostavnejše testiranje: čiste funkcije so deterministične in jih je enostavno enotno testirati.
  • Vzporedno izvajanje: ker čiste funkcije ne uporabljajo skupnega stanja, jih je varneje izvajati sočasno brez zapletov z zaklepi ali sinhronizacijo.

Optimizacije in tehnike, ki izkoriščajo referenčno preglednost

Obstaja več načinov, kako izkoristiti referenčno preglednost za izboljšanje učinkovitosti:

  • Memoizacija (shranjevanje odgovorov po prvem poskusu): shranjevanje rezultatov klicev funkcije za kasnejšo ponovno uporabo brez ponovnega računanja.
  • Odprava skupnih podizrazov: ugotavljanje in združevanje dveh enakih delov kode, da se izognemo podvajanju izračunov.
  • Leno vrednotenje: izračun izraza šele, ko je njegova vrednost res potrebna, kar prihrani nepotrebno delo.
  • Vzporejanje (delo na več problemih hkrati): varno porazdeljevanje dela med niti ali procesi, ker nečiste interakcije s skupnim stanjem niso prisotne.

Omejitve in opozorila

Čeprav je referenčna preglednost zaželena, ni vedno praktična ali mogoče popolnoma doseči v realnih aplikacijah. Nekateri deli programa morajo komunicirati z zunanjim svetom (vnos/izhod, omrežje, baza podatkov), kar prinese stranske učinke. V takih primerih se pogosto loči računanje (čiste funkcije) od efektov (IO), ali pa se uporabijo tehnike, ki efekte jasno izpisujejo in omejujejo njihov vpliv (npr. monade v funkcionalnih jezikih).

Zaključek

Referenčna preglednost poenostavi razmišljanje o kodi, omogoča močne optimizacije in prispeva k bolj zanesljivim ter lažje testirljivim programom. V praksi je cilj pogosto maksimirati dele aplikacije, ki so referenčno pregledni, in jasno ločiti tiste dele, ki morajo imeti stranske učinke.