Oberon | |
---|---|
Clasa de limba | imperativ , structurat , modular |
Aparut in | 1986 |
Autor | Niklaus Wirth |
Tip sistem | static , puternic |
A fost influențat | Modula-2 , Pascal |
influențat | Oberon activ , Componenta Pascal , Go , Java [1] [2] , Modula-3 , Oberon-2 , Zonnon , Nim |
Licență | BSD |
Site-ul web | projectoberon.com |
Oberon este un limbaj de programare de nivel înalt conceput de Niklaus Wirth pentru executarea de programe pe sistemul de operare cu același nume , scris de Niklaus Wirth și Jürg Gutknecht .
Programele scrise în limbajul de programare Oberon necesită un fel de suport de rulare - au nevoie de un încărcător dinamic și de un colector de gunoi automat executat central, pentru care programele Oberon au nevoie de un mediu de operare special. Modul obișnuit de implementare este să adăugați la sistem un set de biblioteci care implementează componentele necesare, deși, în general, mediul de operare nu are neapărat nevoie de un sistem de operare separat: poate fi el însuși un sistem de operare. Acestea sunt sistemele Native Oberon pentru Oberonul original și A2 pentru Oberonul activ . În acest moment, există compilatoare Oberon pentru bytecode Java Virtual Machine și un CLI pentru .NET Virtual Machine .
Sistemele de operare și mediile pentru executarea programelor în limbile familiei Oberon care au evoluat din sistemul original Oberon sunt ETH Oberon, BlackBox Component Builder , WinOberon , A2 etc.
Oberon-0, Oberon-X și alte proiecte au fost dezvoltate pe baza lui Oberon [3] . Simplitatea lui Oberon și disponibilitatea codurilor sursă ale implementării originale facilitează adaptarea lui pentru clase speciale de probleme. Dar toți acești Oberoni sunt foarte aproape unul de celălalt, deoarece Oberonul original este foarte simplu.
Limbajul de programare Oberon a fost creat de Niklaus Wirth în 1988 pe baza limbajelor de programare Modula-2 , Pascal și Algol-60 [4] .
Potrivit lui Wirth, inițial au vrut să scrie sistemul direct pe Modul, dar au ajuns la concluzia că trebuie rafinat și redus, ceea ce a dus la apariția lui Oberon [5] .
Scopul proiectului ( Eng. Project Oberon ) de Niklaus Wirth și Jürg Gutknecht în 1986-1989 [6] a fost de a crea de la zero un sistem de operare vizibil și de încredere pentru o stație de lucru cu un singur utilizator.
Pentru a implementa acest proiect, în 1988 Niklaus Wirth a proiectat un limbaj de programare de nivel înalt de uz general, numit și Oberon [7] .
În 1989, prima implementare a lui Oberon pentru familia de procesoare NS32000 a fost lansată la ETH Zurich (ETH) . A fost creat ca o componentă a mediului de operare Oberon. Acest compilator necesită mai puțin de 50 KB de memorie, este format din 6 module cu un volum total de aproximativ 4000 de linii și se compilează singur în 15 secunde pe un computer cu procesor NS32532 (frecvență de ceas - 25 MHz).
Este pur și simplu imposibil să le mulțumim tuturor celor care, într-un fel sau altul, au alimentat cu ideile lor ceea ce se numește acum Oberon. Majoritatea ideilor au venit din utilizarea și învățarea din limbi existente, cum ar fi Modula-2, Ada, Smalltalk și Cedar, care ne-au avertizat adesea despre ce să nu facem.Niklaus Wirth [5]
Limbajul a păstrat principalele caracteristici ale sintaxei Modula și a fost o extensie de obiect . Acest lucru a făcut posibilă abandonarea mecanismului de module de înregistrări variante , care sunt o retragere față de tastarea statică puternică inițială , ceea ce a făcut posibilă introducerea unui mecanism automat de gestionare a memoriei - colectarea gunoiului : posibilitatea de a elibera memoria alocată dinamic folosind un operator special a fost exclus din limbaj și, în schimb, runtime-ul însuși conține un modul A care returnează memorie neutilizată sistemului. Gestionarea automată a memoriei este un mijloc de îmbunătățire a fiabilității programelor cu structuri de date dinamice, deoarece elimină erorile umane, care sunt tipice, de exemplu, pentru limbaje precum C / C++ .
Pentru a obține cea mai mare fiabilitate și performanță a traducerii, a fost întreprinsă o simplificare semnificativă a limbajului prin eliminarea caracteristicilor care erau considerate inutile (pe baza experienței în dezvoltarea, implementarea și utilizarea altor limbaje), fie a complicat compilatorul fără o justificare suficientă. din punct de vedere al performanței, sau au fost suficient de complexe pentru a fi livrate în biblioteci externe, sau nu sunt compatibile cu modularitatea și mecanismele de gestionare automată a memoriei: înregistrări variante , tipuri enumerate , tipuri de intervale , seturi generice , tip întreg nesemnat, module locale, module de definiție, export liste, operator pentru, versiunea anterioară a instrucțiunii with, o sintaxă specială pentru definirea unui program principal. Mijloacele rudimentare de susținere a programării paralele care erau disponibile în Modulul-2 nu au intrat în limbaj, deoarece a servit un sistem de operare cu un singur utilizator. Gestionarea excepțiilor a fost renunțată pentru simplitate .
Descrierea matricelor a fost simplificată (indexurile matricei pot fi doar numere întregi și încep întotdeauna de la zero, ca limbajul C), utilizarea pointerilor este limitată - pointerii pot exista doar pe înregistrări și matrice, doar modulul importat este specificat în import liste, iar la utilizarea numelor importate, o calificare obligatorie (indicarea explicită a numelui modulului exportator). În articolul „De la Modula la Oberon” [5] , Wirth a explicat în detaliu motivele înlăturării fiecăruia dintre elemente.
Din motive de „minim suficient”, metodele (proceduri și funcții asociate unui tip) nu au fost incluse în limbaj ca concept sintactic explicit, deoarece acest mecanism în forma sa cea mai generală este ușor de modelat prin crearea de câmpuri de tip procedural în obiecte (înregistrări în limba Oberon).şi atribuirea acestora proceduri corespunzătoare metodelor. Astfel, programarea orientată pe obiecte este suportată în Oberon cu mijloace minime pentru a simplifica procesul de traducere a codului și a accelera acest proces.
Datorită modificărilor făcute, Oberon a devenit mai simplu din punct de vedere sintactic. Descrierea sintaxei sale se potrivește pe o singură pagină, descrierea completă a limbajului durează aproximativ 20 de pagini, ceea ce înseamnă jumătate din descrierea lui Modula-2 . Oberon este, dacă nu minim, atunci cel puțin unul dintre cele mai mici limbaje de programare universale de nivel înalt.
Afirmația lui Einstein a fost aleasă ca epigraf la descrierea originalului Oberon: „Fă-l cât mai simplu posibil, dar nu mai simplu decât atât ” .
Definit în următoarele propuneri RBNF [8] :
Modul = ID MODUL ";" [ ImportList ] Ultima declarată [ BEGIN Ultimele declarații ] END id "." . ImportList = IMPORT [ id ":=" ] id { "," [ id ":=" ] id } ";" . LastDeclared = { CONST { DeclaredConst ";" } | TYPE { Declarație de tip ";" } | VAR { DeclaredVar ";" }} { DeclaredProc ";" | ForwardDeclared ";" }. DeclaredConst = IdentDef "=" ConstExpression . TypeDeclare = IdentDef "=" Tip . DeclaredVar = ListIdentifier „:” Tip . DeclaredProc = PROCEDURE [ Receiver ] IdentDef [ FormalParam ] ";" Ultima declarată [ BEGIN Ultimele declaraţii ] END Ident . ForwardDeclare = PROCEDURE "^" [ Receiver ] IdentDef [ FormalParam ]. FormalParam = "(" [ FP Section { ";" FP Section }] ")" [ ":" SpecIdent ]. SectionFP = [ VAR ] id { "," id } ":" Tip . Receiver = "(" [ var ] id ":" id ")" . Tip = QualID | ARRAY [ ConstExpression { "," ConstExpression }] OF Type | ÎNREGISTRARE [ "(" QualIdent ")" ] FieldList { ";" FieldList } END | POINTER TO Tastați | PROCEDURĂ [ FormalParam ]. FieldList = [ ListIdent ":" Type ]. AfterOperators = Operator { ";" Operatorul }. Operator = [ Notație ":=" Expresie | Notație [ "(" [ ListExpression ] ")" ] | IF Expr THEN Instrucțiune Seq { ELSIF Expr THEN Instrucțiune Seq } [ ELSE Instrucțiune Seq ] END | CASE Exprimarea Opțiunii { " |" Varianta } [ ELSE StatementSeq ] END | Instrucțiunea WHILE Express DO Seq END | REPEAT StatementSeq UNTIL Expresia | LOOP AfterStatements END | WITH Guard DO Statement Seq END | EXIT | RETURN [ Express ] ]. Option = [ Option Labels { "," Option Labels } ":" StatementLast ]. VariantLabels = ConstExpression [ ".." ConstExpression ]. Guard = SpecId ":" SpecId . ConstExpression = Express . Expresie = SimpleExpression [ Relație SimpleExpression ]. SimpleExpression = [ „+” | "-" ] Termen { Termen OperSlog }. Termen \ u003d Multiplicator { OperMul Multiplier }. Multiplicator = Notație [ "(" [ ListExpression ] ")" ] | număr | simbol | șir | NIL | Set | "(" Expresie ")" | " ~ " Multiplicator . Set = "{" [ Element { "," Element }] "}" . Element = Express [ ".." Express ]. Relație = "=" | „#” | „<” | „<=" | „>” | ">=" | ÎN | ESTE . OperSlog = "+" | „-” | SAU . OperUmn = "*" | „/” | DIV | MOD | „&” . Desemnare = calificativ { "." ident | „[” ListExpression „]” | „^” | "(" QualIdent ")" }. ListExpr = Expresie { "," Express }. ListIdent = IdentDef { "," IdentDef }. QualID = [ identificator "." ] ID . IdentDef = ident [ "*" | „-” ].Programul Oberon este un set de module. În general, modulul arată astfel:
Nume MODUL ; IMPORT ImportList ; Definitii ; BEGIN Declarații END Nume .Lista de import determină din ce module vor fi importate numele externe . Definițiile includ definiții de tipuri, proceduri, funcții, variabile, constante. În acest caz, definițiile numelor marcate cu asterisc sunt exportate de acest modul, adică vor fi vizibile pentru alte module care îl importă pe acesta. În Oberon-2 este, de asemenea, posibilă marcarea numelor cu semnul minus, caz în care acestea sunt exportate în modul doar citire.
Corpul modulului este executat când este încărcat. În Componenta Pascal, în interiorul corpului unui modul (în secțiunea BEGIN..END), acum este posibil să adăugați o secțiune CLOSE:
instrucțiuni BEGIN CLOSE instrucțiuni END Nume .Aici, instrucțiunile între BEGINși CLOSEsunt executate când modulul este încărcat, iar instrucțiunile între CLOSEși sunt executate când END este descărcat din memorie. O astfel de extensie a fost găsită utilă pentru programele componente care încarcă și descarcă module în mod dinamic .
Tipurile de date create de programator sunt limitate la următorul set: tipuri de matrice ARRAY , tipuri de înregistrare RECORD , tipuri procedurale , tipuri PROCEDURE de pointer POINTER . Un pointer poate fi declarat doar la o matrice sau o înregistrare.
Sintaxa părții interne a programului este destul de tradițională și simplă. Limbajul suportă setul tradițional de construcții: operator condiționat , operator IFde selecție CASE, cicluri (cu precondiție - WHILE, cu postcondiție REPEAT..UNTIL, necondiționat - LOOP). Similar cu Modulul-2, literele mari și mici din identificatori se disting, toate cuvintele rezervate sunt scrise cu majuscule. Toate constructele de limbaj, cu excepția unei bucle REPEAT..UNTIL, se termină cu un cuvânt cheie ENDși permit imbricarea în mai multe instrucțiuni fără a utiliza o instrucțiune compusă BEGIN..END. Desigur, ca și în Modulul-2, nu există salturi necondiționate.
Paradigma de programare orientată pe obiecte este susținută de mecanismul de extensie a înregistrărilor (limbajul nu are un cuvânt cheie separat pentru a descrie clase, precum „clasa” sau „obiect”, se consideră că conceptul obișnuit de „tip de înregistrare” este destul de suficient). În esență, fiecare tip de înregistrare este o descriere a clasei, iar câmpurile înregistrării sunt membri de date ai clasei.
În originalul Oberon, nu există deloc metode (proceduri și funcții asociate cu clasa ). Mecanismul metodei poate fi utilizat prin declararea câmpurilor de tip procedural în înregistrare, cărora li se atribuie proceduri specifice atunci când este creată o instanță a clasei. Apelarea unor astfel de proceduri se face în modul tradițional de accesare a câmpului de înregistrare, în mod implicit procedura nu știe despre instanța clasei pentru care a fost chemată (nu există un mecanism similar thisîn C++ sau Java), și dacă astfel de informațiile sunt necesare pentru aceasta, referința la instanță trebuie transmisă explicit (de exemplu, prin parametrul ). Lipsa metodelor descrise explicit a fost una dintre calitățile originalului Oberon, care a provocat critici din partea programatorilor obișnuiți cu limbajele hibride tradiționale. Pe de altă parte, mecanismul propus de Oberon vă permite să implementați tot ceea ce poate fi implementat prin mijloace tradiționale de limbaje cu metode și chiar mai mult - în Oberon, fiecare instanță a unei clase poate avea propria sa versiune a unei metode ( valoarea unui câmp de tip procedural), în timp ce atunci când descriem metode ca parte a unei clase, toate instanțele operează pe o singură variantă de metodă. În Oberon 2, metodele au fost încă introduse. Metodele sunt descrise separat de tipul de înregistrare, indicând tipul cu care sunt asociate.
Un nou tip de înregistrare poate fi declarat ca o extensie a unuia existent. În acest caz, tipul care este extins este specificat în descrierea intrării în paranteze după cuvântul cheie RECORD. Un tip extins primește automat toate câmpurile de tip extins și (în Oberon 2) este asociat cu toate procedurile asociate cu tipul extins. Procedurile asociate cu noul tip pot avea aceeași semnătură ca și procedurile asociate cu tipul care este extins - acest lucru asigură că metodele din tipurile derivate sunt suprascrise. În Componenta Pascal , pentru a oferi control static complet asupra consistenței ierarhiilor de moștenire (și, prin urmare, restabilind principiul total de tipărire statică care a distins Oberonul original), înregistrările nu sunt extensibile în mod implicit și metodele nu pot fi suprascrise. Cuvintele cheie introduse special sunt folosite pentru a controla extinderea înregistrărilor și înlocuirea metodei EXTENSIBLE, ABSTRACT, LIMITED, EMPTY. În acest caz, metodele nou introduse trebuie să fie marcate cu un cuvânt cheie NEW(cf. definiția obligatorie a variabilelor nou introduse).
Oberon vizează dezvoltarea software orientată pe componente [9] . Încapsularea este acceptată exclusiv la nivel de modul - toate tipurile declarate în interiorul modulului sunt absolut transparente între ele. Ceea ce este disponibil din alte module este ceea ce este declarat ca exportabil în definiție.
Polimorfismul este asigurat de mecanismul metodei (atât câmpurile procedurale din Oberon, cât și metodele din Oberon-2 se comportă ca virtuale , în terminologia majorității limbajelor hibride orientate obiect), precum și de un construct WITH extins care vă permite să executați diferite grupuri de declarații, în funcție de care dintre tipurile extinse îi aparține argumentul.
Nu există un mecanism special de construcție în limbaj. Metoda recomandată pentru crearea și inițializarea obiectelor este descrierea de generare a modulelor și procedurilor (fabrică în terminologia tradițională OOP).
Un program din această tehnologie este un set de componente relativ independente (în acest caz, module) care au o structură internă ascunsă de lumea exterioară și o interfață clar definită. Modulele pot fi încărcate și descărcate dinamic în timp ce programul rulează, sistemul oferă instrumente avansate de verificare a tipului de rulare care vă permit să scrieți algoritmi universali de procesare a datelor care nu depind de tipurile specifice ale acestor date (de exemplu, o bibliotecă pentru lucrul cu un SGBD poate oferi metode care scriu rezultatul unei interogări din baza de date într-o înregistrare a unei structuri arbitrare, dacă setul și tipurile de câmpuri din această înregistrare corespund setului și tipurilor de câmpuri din baza de date).
În paradigma componentelor, este considerată o decizie arhitecturală nefericită asociată cu utilizarea pe scară largă a moștenirii implementării de la tipurile declarate într-o altă componentă, deoarece aceasta duce la un fenomen cunoscut sub numele de „fragibilitate a tipului de bază” - după ce un număr mare de tipuri derivate sunt derivate din tipul de bază (și unele dintre ele pot fi chiar necunoscute dezvoltatorului tipului de bază), orice modificări în implementarea tipului de bază devin extrem de riscante, deoarece pot afecta tipurile descendente într-un mod imprevizibil.
Se știe că una dintre problemele utilizării programării orientate pe obiecte în programarea sistemelor este necesitatea de a avea grupuri de clase mici care să poată interacționa fără cheltuieli suplimentare. Oberon nu are această problemă - toate tipurile definite într-un modul se văd între ele, iar acest lucru nu creează probleme de fiabilitate, deoarece modulul este încă dezvoltat, testat și întreținut ca întreg.
Un sistem tipic dezvoltat pe Oberon este un set de module cu interfețe procedurale prin care modulele fac schimb de date, inclusiv obiecte. În același timp, toate instrumentele de încapsulare funcționează numai în interacțiune între module, ceea ce face ca programarea sistemului folosind obiecte să fie convenabilă.
Programare orientată pe obiecteInstrumentele de programare de obiecte sunt interpretate în Oberon ca o dezvoltare naturală a instrumentelor de lucru cu înregistrări într-un sistem modular, mai exact, ca un set de instrumente tehnice pentru rezolvarea unei probleme arhitecturale specifice: pentru a asigura o „diviziunea muncii” eficientă între diferite module atunci când se lucrează. cu tipuri dinamice și structuri de date: de exemplu, lucrul cu pointerii din listă poate fi ascuns (împreună cu câmpurile corespunzătoare) într-un singur modul, iar definirea și lucrul cu „umplerea” specifică a elementelor listei pot fi specificate într-un altul (sau, mai des, altele). În acest sens, tehnologia de programare a obiectelor a lui Oberon este subordonată conceptului de modularitate: aici este mai degrabă un mijloc de descriere a datelor decât un mijloc de a construi o arhitectură de aplicație în ansamblu.
Potrivit lui Wirth [10] , dezvoltatorii limbajului Java , cu câțiva ani înainte de crearea lui, „au studiat codurile sursă ale lui Oberon și, în special, codurile sursă ale colectorilor de gunoi ai lui Oberon. Apoi l-au încurcat pe Oberon cu sintaxa C și l-au numit Java.” Deși nu se poate cere acuratețe absolută a formulării dintr-o prezentare orală, în orice caz, asemănarea neîndoielnică a ideologiilor lui Oberon și Java (dorința de minimalism și tipărire puternică, restricția moștenirii multiple, gestionarea automată a memoriei) sugerează că există un anumit consens cu privire la instrumentele care ar trebui să formeze nucleul unui limbaj modern de programare cu scop general. Cu toate acestea, dacă minimalismul rămâne în prim-plan în Oberon și succesorii săi direcți, dezvoltatorii Java au luat calea dezvoltării extensive a capacităților limbajului.
Familia de limbaje Oberon în sine include și Oberon-07 , Oberon-2 , Component Pascal ( Component Pascal ), Active Oberon , OberonScript etc.
Versiunea originală a lui Oberon („Oberonul clasic”) este cea mai concisă, cu cel mai mic număr de cuvinte cheie și construcții sintactice. A fost folosit ca bază pentru crearea unei familii de limbi, fiecare dintre ele extinzându-l pe cea clasică într-o anumită direcție sau diferă de aceasta în unele detalii.
În 1992, Niklaus Wirth și studentul său Hanspeter Mössenböck sunt acum profesori la universitate. Johannes Kepler în Linz - a publicat o descriere a unei versiuni augmentate a lui Oberon, numită Oberon-2 . El este o versiune rafinată a clasicului Oberon. Adăugările făcute la Oberon 2 și făcute cu moderație sunt următoarele:
În ciuda extinderii limbajului, volumul descrierii formale a sintaxei lui Oberon-2 este mai mic decât cel al Oberonului clasic datorită optimizării descrierii sintaxei. Există un compilator de optimizare XDS [13] pentru Oberon-2; există, de asemenea, un compilator [14] la bytecode Java .
ETH Oberon , ale căror implementări sunt disponibile pentru multe platforme de calcul.
Oberon SA este o versiune a limbajului Oberon dezvoltat de N. Wirth pentru procesorul Strong-ARM utilizat într- un elicopter fără pilot .
Pe baza experienței de dezvoltare a Oberon SA, în 2007 N. Wirth a pregătit modificări și completări la Oberon clasic [15] [16] pentru un suport mai strict al programării structurate decât, de exemplu, în Oberon-2 sau Componenta Pascal. Noua versiune a limbii a fost numită Oberon-07 [17] . Există o traducere a „Limbajul de programare Oberon, Revizia 1.11.2008” în rusă [18] . Dar în ceea ce privește suportul pentru programarea orientată pe obiecte , limbajul Oberon-07 nu urmează Oberon-2, ci continuă linia minimalistă a clasicului Oberon, inclusiv lipsa suportului pentru procedurile asociate tipurilor de înregistrare.
Oberon-07 are următoarele diferențe principale față de Oberonul clasic:
Compania australiană CFB Software (Brisbane) de la Universitatea din Queensland a dezvoltat Astrobe IDE [21] pentru limbajul Oberon-07 pentru microcontrolere NXP (Philips) ARM7 și diagramele de sintaxă ale limbajului Oberon-07 [22] , de asemenea ca linii directoare pentru stilul programelor în Oberon-07 [23] .
Imediat după publicarea sa în 1992, Oberon-2 a fost considerat candidat pentru rolul unui standard lingvistic (Oakwood Conference, Croydon, 1993), dar experiența practică dobândită în crearea de sisteme software mari a scos la iveală unele puncte slabe ale inovațiilor și dezirabilitatea rafinamente ulterioare (care subliniază încă o dată înțelepciunea conservatorismului arătat de Wirth în definirea Oberonului clasic). Aceste perfecționări au fost întreprinse într-o variantă a lui Oberon-2 numită Component Pascal și publicată în 1999 de către Oberon microsystems [24] , formată în 1992 de studenții lui Wirth (Wirth însuși a devenit membru al consiliului de administrație). Ca și în tranziția de la Oberon la Oberon-2, aceste perfecționări se fac cel mai puțin [25] . În special, limbajul acceptă acum pe deplin metodologia de programare orientată pe componente . Datorită ultimei împrejurări, Componenta Pascal este în prezent, aparent, cea mai perfectă dintre descendenții direcți ai Oberonului clasic. Cu toate acestea, poate fi redusă nu numai la un subset echivalent cu Oberonul original, ci și la un alt subset minimalist cu drepturi depline, în care moștenirea și suprascrierea metodelor sunt permise numai pentru tipurile și metodele pur interfețe (definite cu atributul ABSTRACT). Această împrejurare dezvăluie natura oarecum intermediară a lui Oberon-2.
Componenta Pascal adaugă caracteristici care permit dezvoltatorului să aibă control deplin asupra extensiei tipului de export și a suprascrierii metodei (atribute EXTENSIBLE, ABSTRACT, NEW, EMPTY, precum și posibilitatea de export limitat al metodei „doar implementare”). S-a adăugat blocul de completare a corpului modulului (cuvânt cheie CLOSE) și metoda goală predefinită FINALIZE. Sistemul de tipuri de bază (elementare) este aliniat cu tipurile Java. A fost introdus un tip de șir implicit. Oberon Microsystems, care a definit Componenta Pascal , a lansat, de asemenea, BlackBox Component Framework și mediul de programare vizuală BlackBox Component Builder [26] , de dimensiuni mici și care nu necesită resurse, construite în întregime pe Componenta Pascal.
Ulterior, compilatorul BlackBox a fost integrat în mediul de programare multiplatformă Denia , în special pentru sistemul de operare în timp real JBed , scris în întregime în Componenta Pascal.
Aceste limbi deja cu un motiv întemeiat pot fi numite nu extensii sau versiuni de Oberon, ci limbi independente. Au extins semnificativ sintaxa, au introdus construcții pentru descrierea „proprietăților” clasice (proprietăți) cu control citire/scriere, tipuri numerice cu o dimensiune specificată în biți. Introducerea suportului pentru obiectele active care fac schimb de mesaje în formatul definit de descrierea RBNF, gestionarea excepțiilor [27] .