| CA-Visual Objects László István  Subsistemul OOP Acest material este o continuare a articolului despre mecanismele automate din CA-Visual Objects. Se presupune, că cititorul a avut contact cu un limbaj orientat obiect, măcar la nivelul obiectelor limbajului CA-Clipper. În mare parte, subsistemul OOP al limbajului CA-Visual Objects se conformează standardului în cea ce privește, în general, limbajele orientate obiect. Totuși - parțial datorat prezenței unui depozit de date active - există anumite diferențe de implementare. Pe lângă aceste diferențe, mai puțin importante, CA-Visual Objects oferă o serie de noutăți excitante și soluții elegante, care nu pot fi regăsite la alte limbaje. Cei doi factori, prezența depozitului activ de date, respectiv noutățile prezente fac din CA-Visual Objects un limbaj promițător. Merită menționat, de la început, că entitătile din CA-Visual Objects nu sunt delimitate de clauze de tipul BEGIN - END sau FUNCTION - RETURN. Entitătile sunt păstrate independent în depozitul de date al mediului (repository) -aceasta are implicația interesantă, pe de o parte că secventialitatea entităților nu are nici o importanță, pe de altă parte o entitate pur și simplu se termină acolo, unde începe o nouă entitate... Noțiuni de bazăÎn CA-Visual Objects sunt prezente diverse clase predefinite care pot fi utilizate direct, dar și programatorului i se permite definirea claselor proprii. În acest sens, sunt disponibile toate mecanismele obișnuite și chiar și facilități noi în privința mecanismelor orientate obiect. Declararea unei clase class MyClass Clasa astfel declarată este cea mai simplă clasă, deoarece un obiect al acestei clase nu are nici atribute (numite variabile de instantă), nici rutine de servicii sau acțiuni asociate (numite metode). O clasă sau o declarație singuratică de clasă nu are nici o utilitate, deoarece așa cum este nu poate să facă nimic; este doar o definiție a proprietătilor pe care le-ar avea un obiect al clasei, și comportamentul lui - dacă acest obiect ar exista... Diferența între o clasă și un obiect este critică: pe când obiectul există în spatiu și în timp, clasa este o definiție abstractă, o rețetă sau un plan de a construi obiectul respectiv. Puțin simplificat , o clasă există în timpul compilării, și obiectele doar în timpul execuției programului. Instanțierea obiectelorComanda executabilă de creare a unui obiect, sau a unei instanțe a unei clase, se dă prin numele clasei, urmat de acolade ({}). În contextul exemplului precedent: MyClass{}Ca urmare a acestei comenzi executabile, sistemul va crea un obiect, un exemplar al clasei MyClass. Se poate testa tipul rezultatului returnat, folosind funcția ValType(). ? ValType( MyClass{} ) // "O" de la ObiectObiecte ale claselor predefinite pot fi instanțiate exact la fel, doar că nu se declară clasele respective - declarația lor se găsește în diverse biblioteci. În anumite situații, obiectele create conform exemplului precedent sunt utile prin efectele laterale ale procesului de creare. Dacă în viitor se dorește accesarea obiectului creat, este nevoie de un mecanism prin care se asigură regăsirea obiectului respectiv. Implementare referențialăCa și rezultat al instanțierii unei clase, sistemul returnează o referință la obiectul creat; această valoare (referință) poate fi păstrată într-o variabilă. Operatiile pe obiecte se pot face numai prin variabile, care conțin o referință la obiectul respectiv. oObiect := MyClass{}Valoarea referinței este o valoare totalmente obișnuită, este de tipul O (de la Object), ea poate fi atribuită unei variabile, transmisă unei funcții ca și parametru, sau returnată de aceasta. Fără să intrăm în detalii, propun studierea următoarei secvențe de cod dat, pentru exemplificarea caracterului referențial: local oOne, oTwo oOne := MyClass{}
 	  oTwo := MyClass{}
 	  ? oOne == oTwo // afiseaza FALSE
 	  oTwo := oOne
 	  ? oOne == oTwo // afiseaza TRUE
 	  oTwo:MyExportVar := 10
 	  ? oOne:MyExportVar // afiseaza 10Tipizarea variabilelorDin motive de productivitate și eficiență, CA-Visual Objects suportă atât variabile netipizate, cât și variabile strict tipizate. (Parantezele drepte încadrează clauze opționale.) local oObiect [as usual] Linia de mai sus declară o variabilă locală de tip nedefinit sau polimorfă. Compilatorul nu verifică și nu restricționează sub nici o formă tipul valorilor care pot fi păstrate în variabile polimorfe.  CA-Visual Objects oferă posibilitatea tipizării statice a variabilelor. 
	  În acest context, cuvântul static nu se referă la delimitarea vizibilitătii, 
	  ci la restricționarea definitivă doar la un singur tip a valorilor care 
	  pot fi păstrate în variabila respectivă. Variabilele utilizate, indiferent de valabilitatea lor, pot fi deci strict tipizate. local oObiect as Pe lângă tipurile de bază ale limbajului (SYMBOL; INT, FLOAT, SHORT, LONG, 
	  BYTE, WORD, DWORD, REAL4, REAL8; DATE; LOGIC; VOID; PTR, PSZ, AS  Tipul OBJECT este un tip de bază predefinit. 
	  Prin această comandă, se declară o variabilă, care poate păstra valori 
	  de tip OBJECT. Orice altă tentativă de atribuire se va solda cu eroare.
	  Problema este că, în acest fel, compilatorul nu va fi capabil să verifice 
	  cu exactitate clasa. Nivelul următor de severitate în declararea tipului 
	  se poate regăsi în exemplul de mai jos:
	  Folosind o tipizare strictă, indiferent de nivelul de severitate, aceasta 
	  oferă nu numai un cod mai rapid, dar și posibilitatea eliminării unor erori 
	  latente, deja din timpul compilării. 
	  Bineînțeles, și varianta mai slab tipizată are avantajele ei: în acest 
	  mod se permite definirea unui cod polimorf, care de exemplu poate prelucra 
	  obiectele diverselor clase.
	  În concluzie, se poate lucra cu următoarele feluri de variabile:  Tipizarea variabilelor, care vor conține referințe la obiecte, poate fi 
	  făcută cu diverse grade de libertate: În ideea refolosirii componentelor, una din proprietătile de importanță 
	  deosebită a limbajului este posibilitatea definirii unei clase, bazată pe 
	  definiția unei alte clase. În acest caz, clasele copil moștenesc toate atributele 
	  și comportamentul de la clasa părinte. Prin această tehnică, este posibilă 
	  extinderea unei clase, fără perturbarea funcționalității. 
	  Proprietățile, atributele unui obiect se materializează în structuri de 
	  date de o complexitate oarecare. Fiecare exemplar (instanță) al clasei la 
	  crearea ei primește o copie a întregului set de variabile. Declararea 
	  acestor variabile, adică a variabilelor de instanță se face la nivelul clasei, 
	  dar în acel moment (la compilare) reprezintă doar șablonul după care se 
	  vor crea obiectele clasei respective. 
	  Variabilele de instanță se conformează acelorași reguli de tipizare ca 
	  și toate variabilele: pot fi polimorfe, sau - folosind clauza opțională 
	  AS  Valoare inițială a variabilelor de instanță Variabilele tipizate, la crearea lor, automat se inițializează la valoarea 
	  nulă a tipului respectiv (NULL_ARRAY, NULL_CODEBLOCK, NULL_DATE, FALSE, 
	   Valabilitatea și vizibilitatea variabilelor de instanță Valabilitatea variabilelor de instanță este strict legată de valabilitatea 
	  obiectului din care fac parte, dar vizibilitatea lor este determinată de 
	  modificatorul aplicat la declararea lor. 
	  Vizibilitatea variabilelor de instanță din CA-Visual Objects se conformează 
	  tabelului următor:
	  Deoarece diverse obiecte ale aceleiași clase (sau al unei alte clase) 
	  au inevitabil variabile de instanță cu același nume, nu este suficientă 
	  specificarea numelui variabilei de instanță. Pentru a înlătura nesiguranța 
	  la referirea unei variabile de instanță, este nevoie și de specificarea 
	  obiectului de care aparține variabila. Pentru a referi o variabilă de instanță 
	  se folosește operatorul send (:).
	  Variabilele de instanță exportate fac parte din interfața publică a obiectelor, 
	  reflectă starea reală a acestora. Variabilele EXPORT care sunt deci vizibile 
	  codului exterior clasei violează principiul încapsulării, deoarece permit 
	  acces necontrolat la atributele obiectelor. Ca urmare, vom reveni cu o soluție 
	  la această problemă după o scurtă introducere a folosirii metodelor...
	   Comportamentul, serviciile specifice unei clase se materializează într-un 
	  grup de funcții sau așa-zise metode, care sunt strict legate de clasa respectivă. 
	   O metodă conform definiției din CA-Visual Objects este codul unei singure 
	  acțiuni în comportamentul obiectului; în general, metodele sunt ca și funcțiile 
	  (au parametri, conțin declarații și instrucțiuni, comenzi și valori returnate), 
	  cu anumite diferențe: Definirea metodelor Corpul metodei poate conține și una sau mai multe comenzi RETURN [ Invocarea metodelor La recepționarea unui mesaj, se execută metoda cu același nume - dacă 
	  aceasta există. Invocarea unei metode prin sistemul de mesaje este similară 
	  apelării unei funcții sau a unei subrutine.
	  Referințe la obiectul curent Linia marcată cu 1 este eronată, deoarece - vezi liniile 1 și 3 - apelul 
	  unei metode se poate confunda cu apel de funcție. Soluția este folosirea 
	  unei referințe la obiectul curent SELF și a operatorului send (:) pentru 
	  a înlătura nesiguranța - vezi linia 2.
	  Merită făcută observația, că limbajul este consecvent în modul de invocare 
	  al funcțiilor și metodelor: funcțiile se apelează totdeauna prin simplul 
	  nume, iar metodele folosind o valoare de tip referință (variabilă sau SELF), 
	  operatorul send și numele metodei.
	  Valoarea returnată Vizibilitatea metodelor Există două cuvinte cheie care pot fi folosite pentru a modifica vizibilitatea 
	  metodelor: PROTECT și HIDDEN. Metodele protejate sunt vizibile din clasa 
	  curentă și subclasele ei, iar cele ascunse doar din clasa pentru care s-a 
	  definit metoda.
	  Începând cu versiunea 2.0 CA-Visual Objects permite definirea și a metodelor 
	  strict tipizate. Metodele tipizate - cu totul, că flexibilitatea lor este 
	  mult mai mică, sunt utile deoarece prin folosirea lor se obține un cod mult 
	  mai stabil și mai rapid (legarea metodelor poate fi făcută timpurie, deja 
	  în timpul compilării).
	  Pentru a declara metodele tipizate, se folosește clauza opțională DECLARE 
	  a definiției de clasă: 
	  Definiția metodei se extinde cu specificarea tipului returnat, și a convenției 
	  de apel, ca și la funcții. (Datorită caracterului hibrid al limbajului, 
	  sunt prezente mai multe posibilităti de a declara modul de apel al funcțiilor 
	  și procedurilor. CALLBACK respectă convenția Windows, PASCAL asigură eficiență 
	  prin rigiditatea ei, respectiv CLIPPER oferă flexibilitatea obișnuită la 
	  limbajele Xbase.)
	  Avantajul variantei tipizate este viteza mai mare, respectiv siguranța, 
	  corectitudinea mărită a codului, față de flexibilitatea superioară a metodelor 
	  netipizate.
	  Metoda Init() De obicei, metoda Init() este folosită la executarea unor inițializări 
	  (de exemplu, la setarea unor valori implicite pentru variabilele de instanță 
	  sau alocarea unor resurse - ca și deschiderea unui fișier - necesare funcționării 
	  obiectului).
	   Metoda Axit() De remarcat este, conform filozofiei CA-Visual Objects, că timpul de viață 
	  al unui obiect este strâns legat de posibilitatea de referențiere a ei. 
	  Adică, până când există o variabilă prin care obiectul poate fi referit, 
	  el există, dar odată cu dispariția tuturor referințelor asupra ei, obiectul 
	  este osândit distrugerii. Acest proces de distrugere este executat de un 
	  mecanism automat de colectare a reziduurilor.
	  Dacă utilizatorul definește metoda Axit(), aceasta este invocată automat, 
	  înainte de distrugerea obiectului. 
	  Cum am mai discutat, obiectele au o parte statică - care se reflectă prin 
	  structură, prin relații și atribute; și o parte dinamică - oglindită prin 
	  comportament, sau mesaje și servicii (sinonimă: metode). 
	   Fiecare obiect are o interfață bine definită, care determină care sunt 
	  stimulii care sunt acceptați de obiect, adică ce operații pot fi 
	  efectuate asupra obiectelor. (...) Fiecare stimul cauzează executarea unei 
	  operații, sau accesează direct o variabilă de instanță. 
	  Folosind mecanismul subclasării, se asigură moștenirea structurii și comportamentului 
	  clasei părinte de către clasele copil.
	  Funcționalitatea noii clase se poate extinde prin  Din exteriorul unei clase doar variabilele de instanță EXPORT sunt vizibile, 
	  celelalte variabile interne sau neexportate sunt neaccesibile din funcții 
	  sau metode externe clasei. Pentru a accesa variabilele interne se pot folosi 
	  metode. Aceasta corespunde principiului încapsulării, dar este o soluție 
	  incomodă. 
	  O soluție mult mai elegantă - și extrem de flexibilă - este oferită de 
	  metodele speciale ACCESS și ASSIGN. Aceste metode se folosesc la implementarea 
	  variabilelor de instanță virtuale, care de fapt simulează prin intermediul 
	  metodelor ACCESS și ASSIGN o variabilă de instanță obișnuită. 
	  Sintaxa pentru accesarea, respectiv pentru asignarea acestor variabile 
	  virtuale este aceeași ca și pentru o variabilă reală - singura diferență 
	  este că accesul prin acest mod devine controlat. 
	  Cum se observă, se pot defini fără nici o restricție sau obligativitate 
	  metode ACCESS și ASSIGN cu același nume ca și variabila de instanță la care 
	  au rolul de a controla accesul.
	  Dat fiind faptul că nu se impune ca să existe o variabilă concretă care 
	  să stea în spatele metodelor de acces și asignare, se pot defini metode 
	  speciale care implementează variabile virtuale read-only, write-only, sau 
	  read-write; aceste variabile sunt vizibile doar, sau dacă doriți, există 
	  prin intermediul acestor metode speciale. 
	  Cuvântul cheie SUPER servește la referirea predecesorului direct al unei 
	  clase. Prin acest cuvânt cheie, este posibilă referirea metodelor și a variabilelor 
	  de instanță vizibile ale superclasei (sau a părintelui).
	  Dacă pentru o subclasă se definește o metodă cu un nume, care se suprapune 
	  cu denumirea unei metode a părintelui, pentru obiectele subclasei la un 
	  apel se va identifica și executa noua metodă. Practic noua metodă înlocuiește 
	  vechea metodă a superclasei. Prin aceasta, funcționalitatea clasei se modifică. 
	  Sunt situații, când se dorește - fără perturbarea funcționalității - o 
	  extindere a metodei redefinite. Pentru aceasta, nu este necesară cunoașterea 
	  structurii clasei-părinte: folosind cuvântul cheie SUPER, se poate executa 
	  și metoda superclasei.
	  Folosirea acestei tehnici este singura posibilitate de a extinde funcționalitatea 
	  unei metode la o subclasă.
	   Exemplu clasic este metoda specială Init(), care trebuie să execute anumite 
	  inițializări la nivelul clasei curente - fără ca să se cunoască structura 
	  sau nevoile superclasei. 
	  Pentru a detecta mesajele la care în mod direct nu poate răspunde clasa, 
	  sunt dedicate trei metode. În funcție de sintaxa prin care se trimite mesajul 
	  obiectului, se invocă metoda corespunzătoare.
	  NoIVarGet() se apelează la referirea pentru citire (operatia get) a unei 
	  variabile de instanță inexistentă conform sintaxei  NoIVarPut() se apelează la referirea pentru atribuire (operatia put) a 
	  unei variabile de instanță inexistentă conform sintaxei  NoMethod() se apelează la receptionarea de către un obiect a unei mesaj 
	  pentru care nu există metoda corespunzătoare, conform sintaxei  Ideea de bază este ca, în cazul în care obiectul primește un mesaj pe 
	  care mecanismul automat nu îl poate controla direct, să nu se anunțe direct 
	  sistemul de erori, ci să fie apelat un mecanism care poate decide comportamentul 
	  obiectului în cauză.
	  O utilizare deosebit de interesantă a acestei tehnici, specifice limbajului 
	  CA-Visual Objects, este posibilitatea creării obiectelor care sunt capabile 
	  să-și modifice structura sau comportamentul în runtime. 
	  Ca și exemplu de valoare clasică, se poate prezenta problema reflectării 
	  structurii unei baze de date (.DBF) în obiectul de interfață, să o numim 
	  DBServer - în cazul în care structura fișierului de date nu este în prealabil 
	  cunoscută. 
	   O funcționalitate extrem de interesantă, oferită de CA-Visual Objects, 
	  este posibilitatea extinderii elegante a sintaxei operatorilor folositi 
	  la tipuri de date simple și pe clase (tipuri) definite de utilizator. 
	  Operatorii care pot fi redefiniți, respectiv corespondența dintre operatori 
	  și metodele care joacă rolul operatoarelor este determinată intern.
	  Lista metodelor dublate prin operatori, care pot fi definite pentru orice 
	  clasă, este: Add(), Mul(), Sub(), Div(), Pow(), Gtr(), Less(), GtrEqu(), 
	  LessEqu(), Neg(), Not()
	  În fond, pentru operatorii redefiniți se vor apela pur și simplu metodele 
	  corespunzătoare. Avantajul major al acestei tehnici este că acest apel se 
	  va face conform sintaxei operatorilor. 
	  Avantajul major al acestei tehnici este că se poate lucra mult mai natural 
	  cu obiecte, folosind sintaxa deja obișnuită a operatorilor pentru operații 
	  considerate clasice.
	  Interfața publică a unei clase poate fi interogată prin intermediul unor 
	  funcții speciale. În cele ce urmează, prezentăm câteva categorii - însă 
	  fără dorinta să fim compleți Domeniul fiind prea vast, în acest moment nu intenționăm să intrăm în 
	  detalii. În cazul în care un vector conține obiecte similare, același mesaj poate 
	  fi trimis la toate obiectele vectorului printr-o sintaxă foarte simplă: 
	  Expresia 
	  este perfect echivalentă cu următoarea secvență de comenzi
	   Subsistemul obiectual al limbajului CA-Visual Objects este robust și 
	  comprehensiv. El se bazează pe sâmburele obiectual al limbajului CA-Clipper, 
	  și ca urmare este o extensie naturală a unui limbaj Xbase, dedicat prelucrării 
	  bazelor de date. Eficient și flexibil, este la fel de competitiv ca și celelalte 
	  limbaje obiectuale populare. Dar CA-Visual Objects este caracterizat de 
	  simplitate și de o eleganță deosebită. 
	  Subsistemul obiectual al CA-Visual Objects, împreună cu mecanismele automate 
	  și serviciile oferite, îi conferă limbajului puterea necesară ca aceasta 
	  să poate aspira spre a deveni standard industrial.
	   
	  BYTE România - decembrie 1997
 (C) Copyright Computer Press Agora |