Limbaj de programare

De la Wikipedia, enciclopedia liberă.
Salt la navigare Salt la căutare
Codul sursă al unui program scris în limbajul BASIC

Un limbaj de programare , în informatică , este un limbaj formal care specifică un set de instrucțiuni care pot fi utilizate pentru a produce date de ieșire: poate fi utilizat pentru a controla comportamentul unei mașini formale sau o implementare a acesteia (de obicei, un computer ) sau în faza de programare a acestuia prin scrierea codului sursă al unui program de către un programator : un limbaj de programare este considerat din toate punctele de vedere ca atare dacă este complet Turing .

Istorie

Primul limbaj de programare din istorie este limbajul mecanic folosit de Ada Lovelace pentru programarea mașinii lui Charles Babbage , urmat de Plankalkül de Konrad Zuse , dezvoltat de el în Elveția neutră în timpul celui de-al doilea război mondial și publicat în 1946 . Plankalkül nu a fost niciodată folosit cu adevărat pentru programare. Programarea primelor computere s-a făcut în schimb în cod scurt [1] , din care a evoluat ansamblul , care constituie o reprezentare simbolică a limbajului mașinii. Singura formă de control al fluxului este instrucțiunea de salt condițional, care duce la scrierea de programe care sunt foarte greu de urmat în mod logic datorită salturilor constante de la un punct la altul din cod.

Majoritatea limbajelor de programare ulterioare au încercat să se abțină de la acest nivel de bază, oferind posibilitatea de a reprezenta structuri de date și structuri de control mai generale și mai apropiate de modul (uman) de reprezentare a termenilor problemelor pentru care ne propunem pentru a scrie programe. Printre primele limbi de nivel înalt care au atins o oarecare popularitate s-a numărat Fortran , creat în 1957 de John Backus , din care a derivat ulterior BASIC ( 1964 ): pe lângă saltul condițional, redat cu declarația IF, această nouă generație de limbi Introduce noi structuri de control al fluxului, cum ar fi buclele WHILE și FOR și instrucțiunile CASE și SWITCH: în acest fel, utilizarea instrucțiunilor de salt (GOTO) este mult redusă, ceea ce face codul mai clar și mai elegant și, prin urmare, o întreținere mai ușoară.

După apariția lui Fortran, s-au născut o serie de alte limbaje de programare istorice, care au implementat o serie de idei și paradigme inovatoare: cele mai importante sunt Lisp ( 1959 ) și ALGOL ( 1960 ). Toate limbajele de programare existente astăzi pot fi considerate descendenți ai unuia sau mai multora dintre aceste prime limbaje, de la care împrumută multe concepte de bază; ultimul mare progenitor al limbajelor moderne a fost Simula ( 1967 ), care a fost primul care a introdus conceptul (pe atunci abia schițat) a unui obiect software. În 1970 Niklaus Wirth a publicat Pascal , primul limbaj structurat, cu scop didactic; în 1972 B (rapid uitat) și apoi C s-au născut din BCPL , ceea ce a avut un mare succes de la început. În același an apare și Prolog , până acum principalul exemplu de limbaj logic, care, deși nu este utilizat în mod normal pentru dezvoltarea industrială a software-ului (datorită ineficienței sale) reprezintă o posibilitate teoretică extrem de fascinantă.

Cu primele mini și microcomputere și cercetări din Palo Alto, în 1983 s-a născut Smalltalk , primul limbaj care este cu adevărat și complet orientat spre obiect, inspirat de Simula și Lisp: pe lângă faptul că este încă folosit în prezent în anumite sectoare, Smalltalk este amintit pentru influența enormă pe care a exercitat-o ​​asupra istoriei limbajelor de programare, introducând paradigma orientată pe obiecte în prima sa încarnare matură . Exemple de limbaje orientate obiect astăzi sunt Eiffel ( 1986 ), C ++ (care a apărut în același an ca Eiffel) și mai târziu Java , clasa 1995 .

Descriere

Concepte fundamentale

Pictogramă lupă mgx2.svg Același subiect în detaliu: Teoria limbajelor de programare și Programare (informatică) .
Manuale de programare

Toate limbajele de programare existente sunt definite printr-un lexicon , o sintaxă și o semantică și au:

  • Instrucțiune : o comandă sau o regulă descriptivă: chiar și conceptul de instrucțiune este foarte variabil între diferitele limbi. Cu toate acestea, indiferent de limbajul particular, de fiecare dată când se execută o instrucțiune, starea internă a computerului (indiferent dacă este starea reală a mașinii sau un mediu teoretic virtual creat de limbaj) se schimbă.

Unele concepte sunt, de asemenea, prezente în majoritatea limbilor:

  • Variabil și constant : o referință sau un set de date, cunoscute sau necunoscute, deja memorate sau care urmează să fie memorate; unei variabile corespunde întotdeauna, undeva, un anumit număr (fix sau variabil) de locații de memorie care sunt alocate , adică rezervate, pentru a conține datele în sine. Multe limbi atribuie variabilelor un tip , cu proprietăți diferite (șiruri de text, numere, liste, atomi etc.) care pot fi atribuite într-un mod puternic ( tastare puternică ) sau slab ( tastare slabă ). Există limbaje de programare, cum ar fi unlambda , care nu utilizează variabile. Unele limbi acceptă utilizarea așa-numitelor indicatoare variabile.
Exemplu de diagramă a unui algoritm
  • Expresie : o combinație de variabile și constante , alăturate de operatori ; expresiile au fost inițial introduse pentru a reprezenta expresii matematice, dar funcționalitatea lor s-a extins de atunci. O expresie este evaluată pentru a produce o valoare, iar evaluarea ei poate produce „efecte secundare” asupra sistemului și / sau a obiectelor care participă la acesta. Cazurile speciale de exprimare sunt așa-numitele expresii regulate .
  • Structuri de date , mecanisme care vă permit să organizați și să gestionați date complexe.
  • Structurile de control , care permit să guverneze fluxul de execuție a programului, modificându-l pe baza rezultatului sau evaluării unei expresii (care poate fi redusă la conținutul unei variabile sau chiar să fie foarte complexă) (bucle iterative, cum ar fi for , do , while și structuri condiționale, cum ar fi if , switch-case ).
  • Subprogram : un bloc de cod care poate fi apelat din orice alt punct al programului. În acest context, aproape toate limbile oferă funcții de reutilizare a codului prin combinarea secvențelor de instrucțiuni în funcții care pot fi reamintite după cum este necesar în cadrul programelor sau în biblioteci care pot fi reamintite în fiecare program.
  • Funcționalitatea intrării datelor de la tastatură și vizualizarea datelor de ieșire (serigrafie) prin așa-numitele canale standard (intrare standard, ieșire standard).
  • Posibilitatea de a insera comentarii asupra codului scris, identificate și delimitate sintactic, care explică funcțiile sale în beneficiul lizibilității sau inteligibilității.

Cod sursa

Pictogramă lupă mgx2.svg Același subiect în detaliu: Cod sursă .
Exemplu de cod sursă

Programarea într-un limbaj de programare dat înseamnă, în general, scrierea unuia sau mai multor fișiere text ASCII simple, numite cod sursă, care exprimă algoritmul programului tradus în limbajul de programare. Fonturi, culori și , în general , aspectul grafic sunt irelevante în scopul programării per se: pentru acest motiv , programatorii nu folosesc un cuvânt de prelucrare a programelor, dar textul editori (cum ar fi emacs . Și scurtă) , care oferă în schimb funcții avansate de procesare de text ( regulate expresii , substituții condiționate și căutări pe mai multe fișiere, posibilitatea de a apela instrumente externe etc.).

În cazul în care un anumit editor este capabil de a lucra îndeaproape cu alte instrumente de lucru (compilator, linker - ul, interpret, etc .: a se vedea mai jos) , atunci mai mult decât doar un editor vorbim despre IDE sau mediu de dezvoltare integrat. Trebuie remarcat faptul că unele limbaje de programare recente permit, de asemenea, o formă mixtă de programare, în care redactarea codului sursă ASCII este asociată și cu operațiuni de programare vizuală , prin care programatorul descrie unele aspecte ale programului desenând pe ecran folosind mouse - ul ; o aplicație tipică a ultimei forme de programare este proiectarea interactivă a interfeței grafice a programului (ferestre, meniuri și așa mai departe). Pentru a fi executat de procesor, codul sursă trebuie tradus în limbajul mașinii, care este limba în care mașina funcționează la nivel fizic, iar acest lucru este posibil prin două tehnici posibile: compilare și interpretare .

Codul sursă, care conține instrucțiunile care trebuie executate și (adesea) unele date cunoscute și constante, poate fi apoi executat trecându-l unui interpret care va executa instrucțiunile conținute în acesta, ceea ce este o practică normală pentru limbajele de scriptare ; sau poate fi compilat, adică tradus în instrucțiuni în limbajul mașinii de către un program compilator : rezultatul este un fișier binar „executabil” ( cod executabil ) care nu are nevoie de alte programe pentru a rula și, de asemenea, este mult mai rapid decât un program interpretat. În trecut, compilarea a fost norma pentru toate limbajele de programare cu scop general; în prezent există numeroase limbaje interpretate și de utilizare generală, cum ar fi Java sau cele ale platformei .NET , care aplică o abordare hibridă între cele două soluții, utilizând un compilator pentru a produce cod într-un limbaj intermediar (numit bytecode ) care este ulterior interpretat. Diferența de performanță între limbile interpretate și cele compilate a fost redusă cu tehnici de compilare just-in-time , deși limbajele compilate (dacă nu asamblarea ) continuă să fie utilizate pentru aplicații care necesită cea mai mare performanță posibilă.

Compilare

Pictogramă lupă mgx2.svg Același subiect în detaliu: Compilație și Cod obiect .
Schema tipică a unui compilator ideal

Compilarea este procesul prin care programul, scris într-un limbaj de programare la nivel înalt, este tradus într-un cod executabil prin intermediul unui alt program numit compilator . Compilarea oferă numeroase avantaje, în primul rând faptul de a obține executabile foarte rapide în faza de rulare prin adaptarea diferiților parametri ai acestei faze la hardware-ul disponibil; dar are principalul dezavantaj în faptul că este necesară compilarea unui executabil diferit pentru fiecare sistem de operare sau hardware ( platformă ) pe care urmează să fie pusă la dispoziție execuția sau lipsește așa-numita portabilitate .

Interpretare

Pictogramă lupă mgx2.svg Același subiect în detaliu: Interpret (computer) .
Un cod Python

Pentru a încerca să eliminăm problema de portabilitate (dependența sau nu a limbajului de pe platformă), am încercat să creăm alte limbi care ar putea fi bazate doar pe biblioteci compilate (componente) ad hoc pentru fiecare platformă, în timp ce codul lor este interpretat și, prin urmare, nu este nevoie de o compilare pe fiecare tip de mașină pe care este rulată. [ citație necesară ] Marele defect al acestor limbi este încetineala execuției; cu toate acestea, ele au marele avantaj că vă permit să utilizați același program fără modificări pe mai multe platforme. În acest caz, se spune că programul este portabil .

Pierderea performanței care se află la baza limbajelor interpretate este dubla muncă încredințată mașinii care se pregătește să proceseze acest program. Spre deosebire de un program compilat, de fapt, fiecare instrucțiune este verificată și interpretată la fiecare execuție de către un interpret . Limbajele interpretate sunt utilizate în faza de dezvoltare a unui program pentru a evita efectuarea de numeroase compilări sau, în schimb, atunci când doriți să creați software care efectuează operații non-critice care nu necesită optimizări în ceea ce privește viteza sau dimensiunea, dar care beneficiază mai mult de portabilitate. Scripturile și toate limbajele orientate pe web sunt aproape întotdeauna interpretate. PHP , Perl , Tcl / Tk și JavaScript și multe altele sunt exemple concrete de interacțiune non-platformă.

Există diferite încercări de a face compilatoare cross-platform prin crearea unui nivel intermediar, un fel de semi-interpretare, ca în cazul menționat mai sus Java ; pe de altă parte, pentru limbajele interpretate există încercări de a genera compilații automate (sau semi-compilații) specifice mașinii pe care sunt rulate. Există, de asemenea, instrumente pentru a automatiza cât mai mult posibil compilarea aceluiași program pe diferite platforme, de exemplu GNU autoconf / automake , care vă permite să creați o distribuție a codului sursă care poate fi configurat și compilat automat pe diferite platforme, în general cel puțin toate Unix .

Conectare

Pictogramă lupă mgx2.svg Același subiect în detaliu: Conectarea .

Dacă programul, așa cum se întâmplă adesea, folosește biblioteci sau este compus din mai multe module software , acestea trebuie „conectate” între ele. Instrumentul care efectuează această operațiune se numește linker și este preocupat în principal de rezolvarea interconectărilor dintre diferitele module. Există în principal două tipuri diferite de legături: dinamice și statice .

Legătură statică

Toate modulele de program și bibliotecile utilizate sunt incluse în executabil, care este mare, dar conține tot ceea ce este necesar pentru executarea acestuia. Dacă devine necesară o modificare a uneia dintre biblioteci, pentru a corecta o eroare sau o problemă de securitate , toate programele care le utilizează cu legătură statică trebuie re-legate cu noile versiuni ale bibliotecilor.

Legătură dinamică

Bibliotecile utilizate sunt încărcate de sistemul de operare atunci când este necesar ( legare dinamică ; bibliotecile externe sunt numite „DLL”, biblioteci cu legături dinamice în sistemele Microsoft Windows , în timp ce obiectul partajat „SO” în sistemele de tip Unix ). Executabilul rezultat este mai compact, dar depinde de prezența bibliotecilor utilizate în sistemul de operare pentru a putea rula. În acest fel, bibliotecile pot fi actualizate o singură dată la nivelul sistemului de operare, fără a fi nevoie să reconectați programele. De asemenea, devine posibil să utilizați diferite versiuni ale aceleiași biblioteci sau să utilizați biblioteci personalizate cu caracteristici specifice pentru gazda respectivă. În realizarea unui proiect software complex, se poate întâmpla ca unele părți ale programului să fie create ca biblioteci, pentru ușurința întreținerii sau pentru a le putea folosi în diferite programe care fac parte din același proiect.

Complicația adăugată este că, atunci când instalați un program de legătură dinamică, trebuie să verificați bibliotecile pe care le folosește și, eventual, să le instalați. Sistemele de gestionare a pachetelor, care se ocupă de instalarea programelor pe un sistem de operare, de obicei urmăresc automat aceste dependențe. În general, este preferată legarea dinamică, pentru a crea programe mici și, în general, pentru a reduce memoria RAM ocupată, presupunând că bibliotecile necesare sunt deja prezente în sistem, sau uneori distribuindu-le împreună cu programul.

Comparație între compilație și interpretare

Un exemplu de cod sursă în Python . Evidențierea anumitor bucăți de cod este un instrument obișnuit printre programatori pentru a naviga în cod.

Aceste două metode de creare și executare a unui program au atât avantaje, cât și dezavantaje: cel mai mare avantaj al compilării este, fără îndoială, eficiența mult mai mare în ceea ce privește performanța, la prețul de a rămâne legat de o platformă (combinație de arhitectură hardware și sistem operațional) ; pe de altă parte, un limbaj interpretat nu are, în principiu, această dependență, dar este mai lent și necesită mai multă memorie în timpul rulării.

Bytecode și cod P

O soluție intermediară între compilare și interpretare a fost introdusă în primele versiuni de Pascal (inclusiv cea creată în 1975 de inventatorul său, Niklaus Wirth ) și ulterior adoptată în limbile Java și Python , cu bytecode , și în Visual Basic și .NET limbile Microsoft cu codul P.

În ambele cazuri, codul sursă al programelor nu este compilat în limbajul mașinii, ci într-un cod intermediar „hibrid” destinat interpretării în momentul execuției programului: motivul acestui pas dublu este de a avea portabilitatea interpretării limbi, dar și, datorită precompilării, o fază de interpretare mai simplă și, prin urmare, mai rapidă. În cazul codului secundar Java avem de-a face cu un limbaj de asamblare real, care inițial trebuia implementat într-un model de procesor real, dar niciodată realizat; unele microprocesoare moderne, cum ar fi ARM cu Jazelle implementează nativ multe instrucțiuni de bytecode și, prin urmare, sunt capabile să execute bytecode Java ca și cum ar fi asamblare.

Cu toate acestea, codul intermediar este mai ușor atât de interpretat, cât și de compilat: din acest motiv, au fost dezvoltate compilatoare JIT (Just In Time) atât pentru limbajele Java, cât și pentru .NET, pe care le compilează la momentul lansării unui program Java sau .NET. cod intermediar din mers și execută codul mașinii native, eliminând complet necesitatea unui interpret și făcând programe scrise în aceste limbi aproape la fel de repede ca programele lor compilate corespunzătoare.

Medii de dezvoltare și execuție

Pictogramă lupă mgx2.svg Același subiect în detaliu: mediu de dezvoltare și mediu de execuție .
Exemplu IDE
Platforma Java , un exemplu tipic de mediu de execuție

Prin mediul de dezvoltare ne referim la setul de instrumente pentru dezvoltarea codului sursă al programului, în timp ce prin mediul de execuție ne referim, de obicei, la setul de biblioteci de software, numit și platformă software, folosit de programul însuși pentru a funcționa corect.

Clase de limbi

Pictogramă lupă mgx2.svg Același subiect în detaliu: Paradigma de programare și Lista limbajelor de programare .

În general, există aproximativ 2500 de limbaje de programare mai mult sau mai puțin cunoscute și răspândite. Acestea sunt în primul rând clasificate, în funcție de nivelul de abstractizare, începând de la limbajul mașinii până la limbajul logic uman, în limbaje de nivel scăzut și de nivel înalt (în anii nouăzeci au fost distinși chiar și cei de la cel mai înalt nivel ). La rândul lor, limbile pot fi clasificate în limbi compilate și interpretate așa cum se vede mai sus. Limbile sunt apoi de obicei împărțite în trei familii mari, bazate pe paradigma de programare de referință: limbaje imperative , funcționale și logice .

Imperative

Pictogramă lupă mgx2.svg Același subiect în detaliu: programarea imperativă .

În limbile imperative, instrucțiunea este o comandă explicită, care operează pe una sau mai multe variabile sau pe starea internă a mașinii, iar instrucțiunile sunt executate într-o ordine predeterminată. Scrierea unui program într-un limbaj imperativ înseamnă, în esență, gestionarea a ceea ce trebuie să facă mașina pentru a obține rezultatul dorit, iar programatorul este ocupat să regleze algoritmii necesari pentru a manipula datele. Structurile de control iau forma unor instrucțiuni de flux (GOTO, FOR, IF / THEN / ELSE etc.) și calculul se desfășoară prin iterație mai degrabă decât prin recursivitate. Valorile variabile sunt deseori atribuite din constante sau alte variabile (atribuire) și rareori prin trecerea parametrilor (instanțierea).

Limbi imperative tipice:

Structurat

Pictogramă lupă mgx2.svg Același subiect în detaliu: Programare structurată .

Programarea structurată este o tehnică al cărei scop este de a limita complexitatea structurii de control a programului. Programatorul este obligat să folosească doar structurile de control canonice definite de teorema Böhm-Jacopini , adică secvența , selecția și bucla , evitând instrucțiunile de salt necondiționate.

Orientat pe obiecte

Pictogramă lupă mgx2.svg Același subiect în detaliu: Programare orientată pe obiecte .

Programarea orientată pe obiecte se bazează pe o evoluție a conceptului de tip abstract de date caracterizat prin încapsulare , moștenire , polimorfism . Pe lângă limbaje specializate care implementează pe deplin principiile acestei metodologii (cum ar fi Smalltalk sau Java), multe limbaje moderne încorporează unele concepte de programare orientată pe obiecte.

Funcţional

Pictogramă lupă mgx2.svg Același subiect în detaliu: Programare funcțională .

Limbajele funcționale se bazează pe conceptul matematic al funcției. Într-un limbaj funcțional pur, atribuirea explicită este chiar complet absentă și se folosește doar trecerea parametrilor. În mod tipic în acest model, controlul calculului este gestionat prin recursivitate și potrivire de tipare (acțiunea de verificare a prezenței unui anumit motiv - model - în interiorul unui obiect compozit), în timp ce cea mai comună structură de date este lista , o secvență de elemente. Cel mai important exponent al acestei categorii este fără îndoială Lisp (LISt Processing).

Declarativ (sau logic)

Pictogramă lupă mgx2.svg Același subiect în detaliu: Programare logică .

În limbaje logice, instrucțiunea este o clauză care descrie o relație între date: programarea într-un limbaj logic înseamnă descrierea setului de relații dintre date și rezultatul dorit, iar programatorul este angajat în stabilirea modului în care datele trebuie să evolueze în timpul calculului. Nu există o ordine prestabilită de executare a diferitelor clauze, dar este de latitudinea interpretului să găsească ordinea corectă. Structura principală de control este reprezentată de tăiere , care se numește roșu dacă schimbă comportamentul programului sau verde dacă face doar calculul mai eficient, care se desfășoară prin recursivitate și nu prin iterație. Variabilele își primesc valoarea prin instanțiere sau de la alte variabile deja atribuite în clauza ( unificare ) și aproape niciodată prin atribuire, care este utilizată numai în cazul calculului direct al expresiilor numerice.

Pentru ca acestea să poată fi utilizate într-un program declarativ, toți algoritmii normali trebuie reformulați în termeni recursivi și backtracking ; acest lucru face ca programarea cu aceste limbaje să fie o experiență complet nouă și necesită un mod de gândire radical diferit, deoarece mai mult decât calcularea unui rezultat necesită demonstrarea valorii sale exacte. Confruntate cu aceste cerințe, limbajele declarative permit obținerea unor rezultate excepționale atunci când vine vorba de manipularea grupurilor de entități în relație între ele.

Limbi slab sau puternic tastate

O altă clasificare dorește din punct de vedere al tipului de date exprimate, dorește împărțirea în limbi cu tastare puternică sau slabă.

Limbaje ezoterice

Pictogramă lupă mgx2.svg Același subiect în detaliu: limbaj de programare ezoteric .

Limbi paralele

Supercomputerele moderne și - până acum - toate computerele de nivel înalt și mediu sunt echipate cu procesoare multiple. Ca o consecință evidentă, aceasta necesită abilitatea de a le exploata; per questo sono stati sviluppati dapprima il multithreading , cioè la capacità di lanciare più parti dello stesso programma contemporaneamente su CPU diverse, e in seguito alcuni linguaggi studiati in modo tale da poter individuare da soli, in fase di compilazione, le parti di codice da lanciare in parallelo.

Linguaggi di scripting

Magnifying glass icon mgx2.svg Lo stesso argomento in dettaglio: Linguaggio di scripting .

I linguaggi di scripting sono nati come linguaggi batch , per automatizzare compiti lunghi e ripetitivi da eseguire, appunto, in modalità batch . Invece di digitare uno ad uno i comandi per realizzare un certo compito, essi sono salvati in sequenza in un file, utilizzabile a sua volta come comando composto. I primi linguaggi di scripting sono stati quelli delle shell Unix ; successivamente, vista l'utilità del concetto, molti altri programmi interattivi hanno cominciato a permettere il salvataggio e l'esecuzione di file contenenti liste di comandi, oppure il salvataggio di registrazioni di comandi visuali (le cosiddette macro dei programmi di videoscrittura , per esempio). Il passo successivo, è stato in molti casi l'estensione dei linguaggi con l'associazione di simboli a valori, cioè l'uso di variabili, con i comandi di gestione del flusso, ovvero i costrutti di salto condizionato, le istruzioni di ciclo o di ricorsione, rendendoli così linguaggi completi. Recentemente molti programmi nati per scopi ben diversi dalla programmazione offrono agli utenti la possibilità di programmarli in modo autonomo tramite linguaggi di scripting.

La sintassi di molti linguaggi di scripting, come PHP oi dialetti di ECMAScript , è simile a quella del C, mentre altri, come Perl o Python , ne adottano invece una progettata ex novo. Visto che molto spesso i linguaggi di scripting nascono per l'invocazione di comandi o procedure esterne, altrettanto spesso essi sono interpretati , cioè eseguiti da un altro programma, come il programma madre, del quale il linguaggio di scripting è un'estensione, o un apposito interprete.

Altri linguaggi

Altri tipi di linguaggi sono i linguaggi di programmazione ad altissimo livello utilizzato da professionisti ei linguaggi di programmazione visuali che non richiedono particolari conoscenze avanzate in fatto di programmazione.

Valutazione

Non ha senso, in generale, parlare di linguaggi migliori o peggiori, o di linguaggi migliori in assoluto: ogni linguaggio nasce per affrontare una classe di problemi più o meno ampia, in un certo modo e in un certo ambito. Però, dovendo dire se un dato linguaggio sia adatto o no per un certo uso, è necessario valutare le caratteristiche dei vari linguaggi.

Caratteristiche intrinseche

Sono le qualità del linguaggio in sé, determinate dalla sua sintassi e dalla sua architettura interna. Influenzano direttamente il lavoro del programmatore, condizionandolo. Non dipendono né dagli strumenti usati (compilatore/interprete, IDE, linker) né dal sistema operativo o dal tipo di macchina.

  • Espressività : la facilità e la semplicità con cui si può scrivere un dato algoritmo in un dato linguaggio; può dipendere dal tipo di algoritmo, se il linguaggio in questione è nato per affrontare certe particolari classi di problemi. In generale se un certo linguaggio consente di scrivere algoritmi con poche istruzioni, in modo chiaro e leggibile, la sua espressività è buona.
  • Didattica : la semplicità del linguaggio e la rapidità con cui lo si può imparare. Il BASIC, per esempio, è un linguaggio facile da imparare: poche regole, una sintassi molto chiara e limiti ben definiti fra quello che è permesso e quello che non lo è. Il Pascal non solo ha i pregi del BASIC ma educa anche il neo-programmatore ad adottare uno stile corretto che evita molti errori e porta a scrivere codice migliore. Al contrario, il C non è un linguaggio didattico perché pur avendo poche regole ha una semantica molto complessa, a volte oscura, che lo rende molto efficiente ed espressivo ma richiede tempo per essere padroneggiata.
  • Leggibilità : la facilità con cui, leggendo un codice sorgente, si può capire cosa fa e come funziona. La leggibilità dipende non solo dal linguaggio ma anche dallo stile di programmazione di chi ha creato il programma: tuttavia la sintassi di un linguaggio può facilitare o meno il compito. Non è detto che un linguaggio leggibile per un profano lo sia anche per un esperto: in generale le abbreviazioni e la concisione consentono a chi già conosce un linguaggio di concentrarsi meglio sulla logica del codice senza perdere tempo a leggere, mentre per un profano è più leggibile un linguaggio molto prolisso.

A volte, un programma molto complesso e poco leggibile in un dato linguaggio può diventare assolutamente semplice e lineare se riscritto in un linguaggio di classe differente, più adatta.

  • Robustezza : è la capacità del linguaggio di prevenire, nei limiti del possibile, gli errori di programmazione. Di solito un linguaggio robusto si ottiene adottando un controllo molto stretto sui tipi di dati e una sintassi chiara e molto rigida; la segnalazione e gestione di errori comuni a runtime dovuti a dati che assumono valori imprevisti ( overflow , underflow ) o eccedono i limiti definiti (indici illegali per vettori o matrici) controllo dei limiti ; altri sistemi sono l'implementare un garbage collector, limitando (a prezzo di una certa perdita di efficienza) la creazione autonoma di nuove entità di dati e quindi l'uso dei puntatori, che possono introdurre bug molto difficili da scoprire.

L'esempio più comune di linguaggio robusto è il Pascal, che essendo nato a scopo didattico presuppone sempre che un'irregolarità nel codice sia frutto di un errore del programmatore; mentre l'assembly è l'esempio per antonomasia di linguaggio totalmente libero, in cui niente vincola il programmatore (e se scrive codice pericoloso o errato, non c'è niente che lo avverta).

  • Modularità : quando un linguaggio facilita la scrittura di parti di programma indipendenti (moduli) viene definito modulare . I moduli semplificano la ricerca e la correzione degli errori, permettendo di isolare rapidamente la parte di programma che mostra il comportamento errato e modificarla senza timore di introdurre conseguenze in altre parti del programma stesso. Questo si ripercuote positivamente sulla manutenibilità del codice; inoltre permette di riutilizzare il codice scritto in passato per nuovi programmi, apportando poche modifiche. In genere la modularità si ottiene con l'uso di sottoprogrammi (subroutine, procedure, funzioni) e con la programmazione ad oggetti.
  • Flessibilità : la possibilità di adattare il linguaggio, estendendolo con la definizione di nuovi comandi e nuovi operatori. I linguaggi classici come il BASIC, il Pascal e il Fortran non hanno questa capacità, che invece è presente nei linguaggi dichiarativi, in quelli funzionali e nei linguaggi imperativi ad oggetti più recenti come il C++ e Java.
  • Generalità : la facilità con cui il linguaggio si presta a codificare algoritmi e soluzioni di problemi in campi diversi. Di solito un linguaggio molto generale, per esempio il C, risulta meno espressivo e meno potente in una certa classe di problemi di quanto non sia un linguaggio specializzato in quella particolare nicchia, che in genere è perciò una scelta migliore finché il problema da risolvere non esce da quei confini.
  • Efficienza : la velocità di esecuzione e l'uso oculato delle risorse del sistema su cui il programma finito gira. In genere i programmi scritti in linguaggi molto astratti tendono ad essere lenti e voraci di risorse, perché lavorano entro un modello che non riflette la reale struttura dell'hardware ma è una cornice concettuale, che deve essere ricreata artificialmente; in compenso facilitano molto la vita del programmatore poiché lo sollevano dalla gestione di numerosi dettagli, accelerando lo sviluppo di nuovi programmi ed eliminando intere classi di errori di programmazione possibili. Viceversa un linguaggio meno astratto ma più vicino alla reale struttura di un computer genererà programmi molto piccoli e veloci ma a costo di uno sviluppo più lungo e difficoltoso.
  • Coerenza : l'applicazione dei principi base di un linguaggio in modo uniforme in tutte le sue parti. Un linguaggio coerente è un linguaggio facile da prevedere e da imparare, perché una volta appresi i principi base questi sono validi sempre e senza (o con poche) eccezioni.

Caratteristiche esterne

Oltre alle accennate qualità dei linguaggi, possono essere esaminate quelle degli ambienti in cui operano. Un programmatore lavora con strumenti software, la cui qualità e produttività dipende da un insieme di fattori che vanno pesati anch'essi in funzione del tipo di programmi che si intende scrivere.

  • Diffusione : il numero di programmatori nel mondo che usa il tale linguaggio. Ovviamente più è numerosa la comunità dei programmatori tanto più è facile trovare materiale, aiuto, librerie di funzioni, documentazione, consigli. Inoltre ci sono un maggior numero di software house che producono strumenti di sviluppo per quel linguaggio, e di qualità migliore. [2]
  • Standardizzazione : un produttore di strumenti di sviluppo sente sempre la tentazione di introdurre delle variazioni sintattiche o delle migliorie più o meno grandi ad un linguaggio, originando un dialetto del linguaggio in questione e fidelizzando così i programmatori al suo prodotto: ma più dialetti esistono, più la comunità di programmatori si frammenta in sottocomunità più piccole e quindi meno utili. Per questo è importante l'esistenza di uno standard per un dato linguaggio che ne garantisca certe caratteristiche, in modo da evitarne la dispersione. Quando si parla di Fortran 77 , Fortran 90 , C 99 ecc. si intende lo standard sintattico e semantico del tale linguaggio approvato nel tale anno, in genere dall' ANSI o dall' ISO .
  • Integrabilità : dovendo scrivere programmi di una certa dimensione, è molto facile trovarsi a dover integrare parti di codice precedente scritte in altri linguaggi: se un dato linguaggio di programmazione consente di farlo facilmente, magari attraverso delle procedure standard, questo è decisamente un punto a suo favore. In genere tutti i linguaggi "storici" sono bene integrabili, con l'eccezione di alcuni, come lo Smalltalk, creati più per studio teorico che per il lavoro reale di programmazione.
  • Portabilità : la possibilità che portando il codice scritto su una certa piattaforma (CPU + architettura + sistema operativo) su un'altra, questo funzioni subito, senza doverlo modificare. A questo scopo è molto importante l'esistenza di uno standard del linguaggio, anche se a volte si può contare su degli standard de facto come il C K&R o il Delphi.

Note

  1. ^ Robert W. Sebesta, Concepts of Programming languages , 2006, pp.44. ISBN 0-321-33025-0
  2. ^ Sito web della TIOBE Software che mensilmente stila una classifica di popolarità dei linguaggi di programmazione.

Bibliografia

Voci correlate

Altri progetti

Collegamenti esterni

Controllo di autorità Thesaurus BNCF 5676 · LCCN ( EN ) sh85107313 · GND ( DE ) 4047409-4 · BNF ( FR ) cb13318353n (data) · NDL ( EN , JA ) 00569224
Informatica Portale Informatica : accedi alle voci di Wikipedia che trattano di informatica