Reflection ( reflecție ; un holonim pentru introspecție , reflectare în engleză ) este un proces în timpul căruia un program își poate urmări și modifica propria structură și comportament în timpul execuției. Paradigma de programare care stă la baza reflecției este una dintre formele de metaprogramare [1] și se numește programare reflectivă .
În timpul execuției instrucțiunilor de program (cod), calculatoarele prelucrează datele, ceea ce duce la modificarea acestora, în timp ce computerele nu modifică codul. Cu toate acestea, în majoritatea arhitecturilor moderne de computer , codul este stocat ca date, iar unele limbaje de programare au capacitatea de a trata codul nativ ca date, ceea ce duce la modificări în codul însuși în timpul execuției sale. Astfel de programe cu auto-modificare sunt create în mare parte cu limbaje de programare de nivel înalt care folosesc mașini virtuale (de exemplu , Smalltalk , limbaje de scripting ). Într-o măsură mai mică, reflectarea este folosită în limbaje cu tipuri declarate sau statice (de ex . C , ML , Haskell , F# ).
Conceptul de reflecție în limbaje de programare a fost introdus de Brian Cantwell Smith în teza sa de doctorat din 1982 [ 2] [3] împreună cu conceptul de evaluator meta - circular ca componentă a 3-Lisp .
Programarea orientată pe reflectare, sau programarea reflectivă, este o extensie funcțională a paradigmei de programare orientată pe obiecte . Programarea orientată spre reflecție include autoverificarea, automodificarea și autoclonarea. Totuși, principalul avantaj al paradigmei orientate spre reflecție constă în modificarea dinamică a programului, care poate fi definită și executată în timp ce programul rulează. Unele abordări imperative , cum ar fi paradigmele de programare procedurală și orientată pe obiecte, indică faptul că există o secvență clară predefinită de operațiuni de procesare a datelor. Paradigma de programare orientată spre reflectare, totuși, adaugă capacitatea de a modifica dinamic instrucțiunile programului în timpul rulării și de a le apela într-o formă modificată. Adică, arhitectura software în sine determină ce anume se poate face în timpul funcționării pe baza datelor, serviciilor și operațiunilor specifice.
Reflecția poate fi folosită pentru a observa și modifica un program în timpul execuției. Componenta reflectivă a programului poate observa execuția unei anumite bucăți de cod și se poate schimba pentru a atinge scopul dorit. Modificarea se realizează în timpul execuției programului prin schimbarea dinamică a codului.
Reflecția poate fi folosită și pentru a adapta dinamic un program la diferite situații. De exemplu, luați în considerare un program care utilizează două clase diferite Xși Ypentru a efectua operații similare. Fără reflectare în codul programului, metodele de clasă Xvor Yfi apelate explicit. Dacă programul este proiectat utilizând paradigma de programare orientată spre reflecție, o anumită secțiune de cod nu va conține apeluri explicite la metodele de clasă Xși Y; programul va executa această secțiune de două ori: mai întâi pentru clasă X, apoi pentru clasă Y.
Un exemplu care ilustrează beneficiile reflectării este Serializarea unui obiect în JSON . Fără reflecție, ar fi necesar să se specifice în mod explicit toate numele câmpurilor de clasă și să se facă referire la valorile lor pentru serializare. Dar reflecția permite programului însuși să determine toate câmpurile disponibile și să obțină numele textuale ale acestora. Astfel, serializarea devine disponibilă pentru orice obiect fără a scrie cod suplimentar.
Programele scrise în limbaje de programare care suportă reflecția sunt dotate cu caracteristici suplimentare care sunt greu de implementat în limbaje de nivel scăzut. Enumerăm câteva dintre ele:
Aceste caracteristici pot fi implementate în diferite moduri. În limbajul MOO , reflecția face parte din limbajul de programare zilnică. Toate metodele apelate primesc în context informații despre de unde sunt chemate și referințe la obiectele cărora le aparțin. Securitatea este controlată programatic folosind stiva de apeluri: apelers() este apelat pentru a obține o listă de metode; verifică dacă apelers()[1] s-a blocat.
Limbile compilate se bazează pe mediile lor de rulare pentru a oferi programelor informații despre codul lor sursă. Un fișier executabil compilat pe Objective-C , de exemplu, scrie numele tuturor metodelor într-un singur bloc, creează un tabel de căutare. În limbajele compilate care acceptă crearea de funcții în timpul execuției, cum ar fi Common Lisp , timpul de execuție trebuie să includă un compilator și un interpret.
Implementarea reflectării în limbaje care nu o acceptă se realizează folosind sistemul de transformare a programului pentru a urmări automat modificările din codul sursă.
Un exemplu în C# , în care este creată o instanță fooa clasei Fooși se face un apel de metodă Hellocare nu folosește reflectarea și o folosește:
// Fără reflecție nou Foo (). salut (); // Cu reflexie Tip tip = System . tip . GetType ( "foo" ); var foo = Activator . CreateInstance ( tip ); foo . Gettype (). GetMethod ( "Bună ziua" ). Invocare ( foo , null );Exemplu similar pentru ECMAScript , JavaScript și ActionScript :
// Fără reflecție nou Foo (). buna () // Cu reflexie // presupunând că Foo este în acest nou [ ' Foo' ]()[ 'hello' ]() // fără ipoteze noi ( eval ( 'Foo' ))()[ 'hello' ]()