Atsauces caurspīdīgums ir datoru programmu daļu iezīme. Programmas daļu sauc par "atsauces caurspīdīgu", ja to var aizstāt ar vērtību, ko tā atdod, nemainot programmas uzvedību — citādi sakot, izteiksmi var aizvietot ar tās rezultātu un programma uzvedīsies tāpat. Lai funkcija būtu atsauces caurspīdīga, tai jābūt tīrai: tā vienmēr atgriež to pašu izvadu, ja saņem to pašu ievadu, un tai nedrīkst būt blakusparādību - darbību, kas ietekmē pasauli ārpus tās izteiksmes (piem., maina globālo stāvokli, raksta failus, izmanto tīklu vai izvada tekstu uz ekrāna). Atsauces caurspīdīgumam pretēja parādība ir atsauces necaurspīdīgums, kad izsaukuma vietā nevar droši ielikt tā rezultātu bez uzvedības maiņas.
Salīdzinājums ar matemātiku un programmēšanu
Matemātikā visas funkcijas parasti tiek uzskatītas par referenciāli caurspīdīgām — matemātiskā funkcija tikai saņem argumentus un atgriež vērtību, tai nav papildu ietekmes uz ārējo vidi. Programmēšanā situācija bieži vien ir citāda: funkcija var, piemēram, noskaidrot sistēmas laiku, ģenerēt nejaušas vērtības, izdrukāt informāciju uz ekrāna vai mainīt koplietojamus mainīgos. Tāpēc programmēšanas praksē mēdz atšķirt “funkcijas” (kas atgriež vērtību) un “procedūras” (kas veic darbības, bieži ar blakusparādībām).
Kā to lieto un kāpēc tas ir svarīgi
Atsauces caurspīdīgums ļauj programmatūras izstrādātājiem un kompilatoriem domāt par kodu kā par pārrakstīšanas un vienādojumu sistēmu — izteiksmi var aizstāt ar tās rezultātu jebkurā vietā (substitution model). Tas padara iespējamu daudzas noderīgas lietas:
- Pāvstīt un pierādīt programmas vai koda daļu pareizību, jo var izmantot ekvacionālo domāšanu un vienkāršas pārveidošanas.
- Algoritma vienkāršošana — atsauces caurspīdīgas funkcijas bieži ļauj tiešāk redzēt datu plūsmu un optimizēšanas iespējas.
- Kodu ir vieglāk uzturēt un pārbūvēt (refaktorizēt), saglabājot pārliecību, ka funkcionalitāte nemainās.
- Efektivitātes uzlabojumi — kompilators vai izpildlaiks var droši veikt optimizācijas, piemēram, saglabāt vai atkārtoti izmantot aprēķinus, veikt slinku izvērtēšanu vai paralelizēt izsaukumus.
Praktiskas optimizācijas, kas balstās uz atsauces caurspīdīgumu
Pastāv vairāki paņēmieni, kas izmanto atsauces caurspīdīgumu, lai paātrinātu vai samazinātu atmiņas patēriņu. Pazīstamākie no tiem ir:
- Memoizācija — funkcijas rezultāta saglabāšana, lai nākamajā reizē, saņemot tos pašus argumentus, atgrieztu saglabāto vērtību bez pārrēķina.
- Kopīgu apakšizteicienu izslēgšana (common subexpression elimination) — ja vienā vai vairāk vietās tiek izsaukts tas pats izteiciens, to var aprēķināt vienu reizi un rezultātu izmantot vairākās vietās.
- Slika izvērtēšana (lazy evaluation) — izteiksmes netiek vērtētas, kamēr rezultāts tiešām nav nepieciešams, kas var ietaupīt aprēķinu laiku un atmiņu.
- Paralēlizācija — neatkarīgi, atsauces caurspīdīgas funkcijas var droši izpildīt paralēli, jo tām nav blakusparādību, kas varētu radīt sacensības par resursiem.
Piemēri
// Atsauces caurspīdīgs piemērs (tīra funkcija) function square(x) { return x * x; } // square(4) jebkurā vietā droši aizvietojams ar 16 // Atsauces necaurspīdīgs piemērs (ar blakusparādību) function printTime() { console.log(new Date()); } // printTime() rezultāts ir atkarīgs no sistēmas laika un nevar tikt aizvietots ar vienu fiksētu vērtību Kad atsauces caurspīdīgums nav iespējams
Atsauces caurspīdīgums pārtrūkst, ja funkcija:
- lasīt vai raksta ārējā stāvoklī (failsistēma, tīkls, datubāze),
- maina koplietojamus mainīgos vai globālo stāvokli,
- izmanto nejaušības ģeneratoru vai sistēmas laiku,
- izsauc ārējās puses kodu ar blakusparādībām (piem., I/O),
- atkārtoti neuzvedas vienādi, piemēram, ģenerē dažādus izņēmumus vai kļūdas atkarībā no ārējiem apstākļiem.
Tādēļ praksē bieži ieteicams atdalīt tīro aprēķinu daļas no neizbēgamām blakusparādību apstrādēm — tas saglabā optimizāciju un testēšanas priekšrocības, bet ļauj mijiedarboties ar pasauli.
Saitība ar programmēšanas valodām un paradumiem
Dažas valodas (piem., Haskell) sekmīgi veicina vai pat pieprasa tīrās funkcijas, kas atvieglo atsauces caurspīdīguma izmantošanu. Citi valodu ekosistēmās (piem., Java, C, JavaScript) tīrība ir izvēle — to var īstenot stilā, izolējot blakusparādības un rakstot vairāk tīru (pure) funkciju. Pat ja valoda neuzliek tīrību, tās principu ievērošana — funkcijas bez blakusparādībām, determinisms un skaidra stāvokļa pārvaldība — uzlabo koda uzturēšanu, testēšanu un optimizāciju.
Nobeigums
Atsauces caurspīdīgums ir fundamentāls koncepts, kas ļauj droši aizvietot izteiksmes ar to rezultātiem, kas savukārt atvieglo domāšanu par kodu, ļauj izmantot plašu optimizāciju instrumentu kopu un padara programmas vieglāk pārbaudāmas un uzturamas. Sapratne, kad šo īpašību var izmantot un kad to nevar, ir praktiski nozīmīga ikvienam programmētājam.