Cunoștințe, prelegere, tastare

Încrucișarea statică și dinamică

Deși sunt posibile versiuni intermediare, sunt prezentate două abordări principale:

  • Înscriere dinamică. așteptați momentul executării fiecărui apel și apoi luați o decizie.
  • Încrucișarea statică. Având în vedere setul de reguli, determinați prin sursă text dacă sunt posibile încălcări de tip atunci când sunt executate. Sistemul este executat dacă regulile garantează că nu există erori.

Acești termeni pot fi ușor de explicat: Când dactilografiere verificarea de tip dinamic se produce în timp ce sistemul este (dinamic) și executat static peste text (înainte de execuție) pentru verificarea dactilografiere statice.







Termenii tastați și netimpinați sunt adesea folosiți în loc să fie tipăriți în mod static și tipăriți dinamic. Pentru a evita orice neînțelegere, vom adera la numele complet.

Înscrierea statică presupune o verificare automată, de obicei impusă compilatorului. În final, avem o definiție simplă:

Definiție: o limbă statică

Limba OO este tipărită static dacă este prevăzută cu un set de reguli consecvente verificate de către compilator, a căror respectare garantează că executarea sistemului nu va duce la încălcarea tipului.

În literatura de specialitate există termenul de "tastare puternică" (puternic). Aceasta corespunde naturii ultimate a definiției, care necesită o absență completă a încălcării de tip. Forme posibile și slabe (slabe) de tipare statică. conform căruia normele elimină anumite încălcări fără a le elimina în totalitate. În acest sens, unele limbi OO sunt tipărite slab slab. Vom lupta pentru cea mai puternică tipificare.

Regulile de scriere

Notatia noastra OO este tiparita static. Regulile sale de tip au fost introduse în prelegerile anterioare și sunt reduse la trei cerințe simple.

Deși definiția unei limbi statice este dată cu destulă precizie, nu este suficientă, - sunt necesare criterii informale atunci când se creează reguli de tiparire. Considerăm două cazuri extreme.

  • Absolut corect limba. în care fiecare sistem corect sintactic este corect și în ceea ce privește tipurile. Regulile pentru descrierea tipurilor nu sunt necesare. Există astfel de limbi (imaginați expresia poloneză a unei expresii cu adăugarea și scăderea numerelor întregi). Din păcate, nici o limbă reală universală nu îndeplinește acest criteriu.
  • Limba absolut incorectă. care este ușor de creat prin luarea oricărei limbi existente și adăugarea unei reguli de scriere care face ca orice sistem să fie incorect. Prin definiție, această limbă este tipărită: deoarece nu există sisteme care să respecte regulile, niciun sistem nu va produce încălcări de tip.

Putem spune că limbile de primul tip sunt potrivite. dar inutil. acesta din urmă poate fi util, dar nu este adecvat.

În practică, este nevoie de un sistem tip care este util și util în același timp: este suficient de puternic pentru a realiza nevoile computaționale și este destul de convenabil, fără a ne forța să facem complicații pentru a satisface regulile de tiparire.

Vom spune că limba este realistă. Dacă este potrivit pentru utilizare și util în practică. Spre deosebire de definiția tipăririi statice. oferind un răspuns categoric la întrebarea: "Este scris X în mod static?", definiția realismului este parțial subiectivă.

În această prelegere, vom vedea că notația propusă de noi este realistă.

Inserarea statică duce, prin natura sa, la o politică "pesimistă". Încercarea de a da o garanție că toate calculele nu duc la eșecuri. respinge calculele care ar putea duce la erori.

Luați în considerare un limbaj obișnuit, non-obiectiv, asemănător cu Pascal, cu diferite tipuri de REAL și INTEGER. În descrierea lui n: INTEGER; r: Operatorul real n: = r va fi respins ca violând regula. Deci, compilatorul va respinge toți operatorii următori:

Dacă vom permite punerea lor în aplicare, putem vedea că [A] va funcționa întotdeauna, ca orice sistem de numerație este o reprezentare corectă a unui număr real 0.0, tradus în mod clar în cât mai multe 0. [B] va lucra aproape sigur. Rezultatul [C] nu este evident (dacă vrem să obțineți rezultatul de rotunjire sau îndepărtând partea fracționară?). [D] va face față sarcinilor sale, cum ar fi operatorul:

care include o atribuire inaccesibilă (n ^ 2 este pătratul numărului n). După înlocuirea n ^ 2 cu n, numai o serie de pornire va da rezultatul corect. Atribuirea unei valori reale mari care nu poate fi reprezentată de un număr întreg va duce la o eșec.

În limbile tipizate, toate aceste exemple (de lucru, inactiv, uneori de lucru) sunt tratate fără cruțare ca încălcări ale regulilor de definire a tipului și respinse de orice compilator.

Întrebarea nu este dacă vom fi pesimiști, ci cât de pesimisti ne putem permite să fim. Să ne întoarcem la cererea de realism. dacă regulile tipurilor sunt atât de pesimiste încât împiedică simplitatea calculelor scrise, le vom respinge. Dar dacă realizarea siguranței de tip se realizează printr-o mică pierdere a puterii expresive, le vom accepta. De exemplu, într-un mediu de dezvoltare care oferă funcții de rotunjire și selecție pentru întreaga parte și rotunjit. operatorul n: = r este considerat incorect deoarece vă obligă să scrieți în mod explicit conversia unui număr real la un număr întreg, în loc să utilizați conversii implicite ambigue.

Încadrarea statică: cum și de ce

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 costurilor corecției la momentul găsirii erorilor este prezentată în grafic, construită din datele unui număr de proiecte industriale mari și experimentate cu un mic proiect controlat:








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.

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. (Aceasta este notația noastră este diferită de limbile „hibrid“, cum ar fi Object Pascal. Java si C ++, în cazul în care, pe baza de clasă sistemul vechi tipuri de limbi, combinate cu tehnologia obiect.)

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 a limbajelor clasice, de exemplu, Pascal și Ada, în care operatorul x: = y cere ca tipurile x și y să fie identice. Această regulă este prea strictă: interzice utilizarea entităților care pot identifica obiecte de tipuri interconectate (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ștenire multiplă

Î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:

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. Traducerile tradiționale de compilare necesită o re-traducere a întregului sistem (și asamblarea acestuia), iar acest proces poate fi dureros de lung, în special cu trecerea la sisteme de mari dimensiuni. Acest fenomen a devenit un argument în favoarea sistemelor interpretative, cum ar fi mediile timpurii Lisp sau Smalltalk care au rulat sistemul cu procesare puțin sau deloc, fără a efectua verificări de tip. 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.

Poate că 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. În parte, acest lucru se poate datora influenței limbajului Smalltalk, susținând o abordare dinamică a ambelor sarcini și capabilă să genereze 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

  • Problema de tipificare. când trebuie să știm cu siguranță că o operație care corespunde cu 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 inițiază apelul?

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:

Ambele sarcini pot fi rezolvate dinamic sau static. În limbile existente, sunt prezentate toate cele patru soluții.

  • Un număr de limbi nonobiective, spun Pascal și Ada, implementează atât tipizarea statică, cât și legarea statică. Fiecare entitate reprezintă obiecte de un singur tip specificate 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 individuale non-obiect suportă tastarea dinamică și legarea statică. Printre acestea se numără limbi de asamblare și un număr de limbi de scripting.
  • Ideile de scriere statică și legare dinamică sunt incluse în notația sugerată în această carte.

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

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.







Articole similare

Trimiteți-le prietenilor: