Deși beneficiile tipăririi statice sunt evidente, este bine să le vorbim din nou.
avantaje
Motivele pentru utilizarea tipăririi statice în tehnologia obiectului, am enumerat la începutul lecției. Este fiabilitate, simplitate de înțelegere și eficiență.
Fiabilitatea se datorează descoperirii unor erori care s-ar putea manifesta altfel numai în timpul funcționării și numai în unele cazuri. Prima regulă, forțând declara esență, ca, într-adevăr, și funcțiile introduse în textul redundanța program care permite compilatorul, folosind celelalte două reguli, există o discrepanță între aplicația și reale entități concepute, componente și expresii.
Detectarea precoce a erorilor este de asemenea importantă, deoarece cu cât întârziem căutarea, cu atât mai mult vor crește costurile corecției. Această proprietate, intuitiv înțeleasă pentru toți programatorii profesioniști, este confirmată cantitativ de bine-cunoscutele lucrări ale lui Boehm. Dependența de costurile pentru a corecta timpul de a găsi eroarea este prezentată în grafic, construit în conformitate cu o serie de proiecte industriale mari și experimente realizate cu mici pentru a gestiona proiectul:
Fig. 17.1. Costuri comparative pentru corectarea erorilor ([Boehm 1981], publicate cu permisiune)
Lizibilitatea sau simplitatea înțelegerii (lizibilitatea) are avantajele sale. În toate exemplele acestei cărți, apariția unui tip într-o entitate oferă cititorului informații despre scopul său. Lizibilitatea este extrem de importantă în etapa de acompaniament.
tip trebuie să fie clar atât pentru mașină, cât și pentru persoana care citește textul. | |
Argumente în favoarea tastării dinamice
Cu toate acestea, tastarea dinamică nu-și pierde aderenții, în special printre programatorii Smalltalk. Argumentele lor se bazează în primul rând pe realismul discutat mai sus. Sunt siguri că tastarea statică le restricționează prea mult, fără a le permite să-și exprime liber ideile creative, uneori numind-o "centura castității".
Cu acest argument putem fi de acord, dar numai pentru limbile statice tipărite care nu suportă o serie de posibilități. Este demn de remarcat faptul că sunt necesare toate conceptele legate de conceptul de tip și introduse în conferințele anterioare - respingerea oricărei dintre ele este plină de limitări serioase, și introducerea lor, dimpotrivă, dă la acțiunile noastre de flexibilitate, si ne da posibilitatea de a se bucura pe deplin practic de statică dactilografiere.
Tastarea: componente ale succesului
Care sunt mecanismele de scriere realistă statică? Toate acestea sunt introduse în cursurile precedente și, prin urmare, trebuie doar să le reamintim pe scurt. Lista lor comună arată consistența și puterea unificării lor.
Sistemul nostru de tip este complet bazat pe conceptul de clasă. Clasele sunt chiar și tipuri de bază ca INTEGER. și, prin urmare, nu avem nevoie de reguli speciale pentru descrierea tipurilor predefinite. (În această notație, notația noastră diferă de limbile "hibride", cum ar fi Object Pascal, Java și C ++, unde sistemul de tip vechi este combinat cu tehnologia obiectului bazată pe clase.)
Tipurile implementate ne dau mai multă flexibilitate, permițând tipurilor ale căror valori denotă obiecte, împreună cu tipuri ale căror valori reprezintă referințe.
Cuvântul decisiv în crearea unui sistem de tip flexibil aparține moștenirii și conceptului asociat de compatibilitate. Acest lucru depășește principala limitare
limbi tipizate de tip clasic, de exemplu, Pascal și Ada, în care operatorul x: = y cere ca tipurile x și y să fie aceleași. Această regulă este prea strictă: interzice utilizarea entităților care pot desemna obiecte de tipuri interdependente (
SAVINGS_ACCOUNT și CHECKING_ACCOUNT). Atunci când moștenim, avem nevoie doar de compatibilitatea tipului y cu tipul x. de exemplu, x este de tip ACCOUNT. y - SAVINGS_ACCOUNT. iar a doua clasă este moștenitorul primului.
În practică, un limbaj format în mod static necesită suport pentru moștenire multiplă. Există cunoștințe principale despre tipărirea statică prin faptul că nu oferă ocazia de a interpreta obiectele în mod diferit. Astfel, obiectul DOCUMENT poate fi transmis prin rețea și, prin urmare, necesită prezența componentelor asociate tipului de mesaj (mesaj) MESSAGE. Dar această critică este valabilă doar pentru limbile limitate de moștenirea unică.
Fig. 17.2. Moștenirea multiplă Universalitatea este necesară, de exemplu, pentru a descrie flexibilitatea, dar sigură
Într-o serie de cazuri, universalitatea trebuie să fie limitată. Aceasta permite utilizarea unor operațiuni care se aplică numai entităților de tip generic. Dacă clasa generică SORTABLE_LIST acceptă sortarea, aceasta necesită entități de tip G. În cazul în care G este un parametru generic, există o operație de comparare. Acest lucru este realizat prin asocierea cu clasa G specificând restricția generică - COMPARABILITATE:
clasa SORTABLE_LIST [G -> COMPARABIL].
Orice parametru generic SORTABLE_LIST trebuie să fie un descendent al clasei COMPARABLE. având componenta necesară.
Un alt mecanism obligatoriu - încercarea de alocare - organizează accesul la acele obiecte, pe care software-ul nu le gestionează. Dacă y este un obiect de bază de date sau un obiect primit prin rețea, atunci operatorul x? = Y atribuie x la y. dacă y are un tip compatibil, sau dacă nu, x va da Void.
Aprobarea. conectat ca parte a ideii de proiectare prin contract, cu clasele și componentele acestora sub forma unor condiții preliminare, postconditii și invarianți de clasă, oferă o oportunitate de a descrie restricțiile semantice, care nu sunt acoperite de tipul de caietul de sarcini. În limbi, cum ar fi Pascal și Ada, există tipuri de subrețele care pot restrânge valoarea naturii, de exemplu, intervalul de la 10 la 20, cu toate acestea, folosindu-le, nu va fi în măsură să se asigure că valoarea i este negativ, întotdeauna mai mare de două ori j. Invarianții de clasă ajung la ajutor, proiectați să reflecte cu acuratețe restricțiile impuse, indiferent cât de complexe sunt acestea.
În dezvoltarea sistemelor software, de fapt, o altă proprietate inerentă mediului de dezvoltare în sine este o recompilare rapidă, incrementală. Când scrieți sau modificați sistemul, aș dori să văd efectul modificărilor cât mai curând posibil. Cu tastarea statică, trebuie să dați timpul compilatorului pentru a verifica din nou tipurile. rutine de compilare tradiționale necesită traducerea întregului sistem (și ansamblul ei) repetate, iar acest proces poate fi dureros de lent, mai ales cu trecerea la sisteme la scară largă. Acest fenomen a fost argumentul în favoarea sistemelor de interpretare, cum ar fi mediul Lisp devreme sau Smalltalk, porniți sistemul cu puțin sau deloc de prelucrare, fără a efectua tip de verificare. Acum, acest argument este uitat. Un bun compilator modern determină modul în care codul sa schimbat de la ultima compilare și procesează numai modificările găsite.
"Este tastând minuscul"?
Obiectivul nostru este de a scrie cu strictețe stricte. De aceea ar trebui să evităm orice lacune în "jocul de reguli", cel puțin, să le identificăm cu exactitate, dacă există.
Cea mai obișnuită lacună în limbile statice tipizate este prezența transformărilor care schimbă tipul entității. În limbajul C și în limbile derivate, ele sunt numite "casting type" sau casting. Înregistrarea (OTHER_TYPE) x indică faptul că valoarea x este percepută de către compilator ca având tipul OTHER_TYPE. sub rezerva anumitor restricții privind tipurile posibile.
Astfel de mecanisme depășesc limitele verificării tipului. Distribuția este folosită pe scară largă în programarea în C, inclusiv în dialectul ANSI C. Chiar și în C ++, tiparea turnării, deși nu atât de frecventă, rămâne o sarcină familiară și posibil necesară.
Aderarea la regulile de scriere statică nu este atât de simplă, dacă în orice moment ele pot fi eludate prin turnare.
Apoi vom presupune că sistemul tip este strict și nu permite turnarea.
| Probabil ați observat că o încercare de alocare - o componentă integrală a unui sistem de tip realist - seamănă cu o distribuție. Cu toate acestea, există o diferență semnificativă: o încercare de atribuire verifică dacă tipul curent corespunde unui anumit tip, este sigur și uneori necesar. | |
Tastarea și legarea
Deși, ca cititor al acestei cărți, este posibil să distingem între tastarea statică și legarea statică. există oameni care nu pot face acest lucru. Acest lucru poate fi parțial
este asociată cu influența limbajului Smalltalk, susținând o abordare dinamică a ambelor sarcini și capabilă să formuleze ideea greșită că aceștia au aceeași soluție. (Noi, în cartea noastră, susținem că este de dorit să combinăm scrierea statică și legarea dinamică pentru a crea programe fiabile și flexibile.)
Atât scrierea, cât și legarea se referă la semantica constructului de bază x.f (arg). dar răspundeți la două întrebări diferite:
Tastarea și legarea
* Întrebarea de a scrie. când trebuie să știm cu certitudine că o operație corespunzătoare f va apărea la timpul de execuție. Se aplică unui obiect atașat entității x (cu parametrul arg)?
* Problema obligatorie. când trebuie să știm ce operație a dat
Tastarea răspunde la întrebarea despre prezența a cel puțin o operațiune, legarea este responsabilă pentru alegerea celei potrivite.
În cadrul abordării obiectului:
* Problema care apare în timpul tastării este legată de polimorfism. deoarece x la timpul de execuție poate denumi obiecte de mai multe tipuri diferite, trebuie să fim siguri că operația reprezentând f. este disponibil în fiecare dintre aceste cazuri;
Ambele sarcini pot fi rezolvate dinamic sau static. În limbile existente, sunt prezentate toate cele patru soluții.
* Un număr de limbi non-obiective, spun Pascal și Ada, implementează atât tastarea statică, cât și legarea statică. Fiecare entitate reprezintă obiecte de un singur tip specificate în mod static. Aceasta asigură fiabilitatea soluției, plată pentru care este flexibilă.
* Smalltalk și alte limbi OO conțin instrumente de conectare dinamică și instrumente de tastare dinamice. Preferința este acordată flexibilității în detrimentul fiabilității lingvistice.
* Limbile separate non-obiect suportă tastarea dinamică și legarea statică. Printre acestea sunt limbi de asamblare și un număr de limbi de scripting.
* Ideile de scriere statică și legare dinamică sunt încorporate în notația sugerată în această carte.
Rețineți particularitatea limbajului C ++ care acceptă scrierea statică, deși nu este strictă datorită prezenței turnărilor, legării statice (implicit),
Motivul alegerii tipăririi statice și legării dinamice este evident. Prima întrebare: "Când vom ști despre existența componentelor?" - presupune un răspuns static: "Cu cât mai repede, cu atât mai bine", ceea ce înseamnă: la momentul compilării. A doua întrebare: "Care componentă ar trebui să folosesc?" Acesta presupune un răspuns dinamic: "cel care este necesar" - care corespunde tipului dinamic al obiectului, determinat în timpul execuției. Aceasta este singura soluție acceptabilă dacă legarea statică și dinamică oferă rezultate diferite.
Următorul exemplu al ierarhiei de moștenire ajută la clarificarea acestor concepte:
Fig. 17.3. Tipuri de aeronave Luați în considerare provocarea:
Problema de dactilografiere atunci când convins că nu va fi componenta lower_landing_gear ( „trenul de aterizare“), aplicabilă obiectului (pentru COPTER nu va fi deloc) problema legării: care dintre mai multe variante posibile de a alege.
Tastarea dinamică în stilul Smalltalk necesită așteptarea apelului și, la momentul execuției sale, verificați prezența componentei dorite. Acest comportament este posibil pentru prototipuri și dezvoltare experimentală, dar este inacceptabil pentru sistemele industriale - în timpul zborului este prea târziu să vă întrebați dacă aveți un șasiu.