La sintassi dei linguaggi di programmazione dipende dalla loro implementazione?


12

Tuttavia, la mia domanda potrebbe essere del tutto irrilevante, ma ho avvertito un modello tra la maggior parte dei linguaggi di programmazione e le loro implementazioni ufficiali.

I linguaggi interpretati ( interpretati da byte?) Come Python, Lua ecc. Di solito hanno una sintassi estremamente semplice e facile e sono generalmente senza tipo o non richiedono allo sviluppatore di scrivere esplicitamente tipi variabili nel codice sorgente;

I linguaggi compilati come C, C ++, Pascal ecc. Di solito hanno una sintassi rigorosa, generalmente hanno tipi e richiedono principalmente più tempo di codice / sviluppo

I linguaggi le cui implementazioni ufficiali sono compilate in JIT come Java / C # di solito sono un compromesso unico tra i due precedenti con alcune delle migliori caratteristiche di entrambi.

Alcuni dei più moderni linguaggi di programmazione compilati come D e Vala (e l'implementazione GNU GJC di Java) sono forse un'eccezione a questa regola e assomigliano alla sintassi e alle caratteristiche dei linguaggi compilati JIT come Java e C #.

La mia prima domanda è: è davvero rilevante? O è solo una coincidenza che la maggior parte dei linguaggi interpretati ha una sintassi semplice, quelli compilati con JIT hanno una sintassi e caratteristiche moderate ecc.

In secondo luogo, se questa non è una coincidenza, allora perché è così? Ad esempio, alcune funzionalità possono essere implementate in un linguaggio di programmazione solo se, ad esempio, lo stai compilando JIT?


@YannisRizos scusa, non è un preventivo. Volevo solo evidenziarlo. Lo modificherò.
ApprenticeHacker,

1
Fantastico, pensavo che non fosse una citazione, ma potrebbe portare i rispondenti a pensare che fosse uno e non provare a confutarlo (o concordare ciecamente con esso) ... Ho notato schemi simili ma purtroppo non hanno un buon risposta.
yannis,

@ R.MartinhoFernandes scusa, non ne ero a conoscenza. Lo modificherò (di nuovo).
Apprentice

4
Perl è tipizzato in modo dinamico per tipi definiti dall'utente, tipicamente staticamente rispetto a matrici, hash, scalari e subroutine distintivi e fortemente tipizzato tramite l'uso rigoroso, interpretato e compilato JIT (non allo stesso tempo ovviamente) ... Ogni volta che qualcuno prova dare un senso al design del linguaggio, gettare un po 'di Perl è sempre divertente ...
yannis,

3
Cosa intendi con "sintassi indulgente" vs. "sintassi rigorosa"? Sono tutti linguaggi formali e nessuno eseguirà il codice sorgente con errori di sintassi.
nikie il

Risposte:


17

Non esiste alcuna connessione tra semantica e sintassi. I linguaggi compilati omoiconici come Scheme hanno una sintassi piuttosto minimalista. I meta-linguaggi compilati a basso livello come Forth sono ancora più semplici di così. Alcuni linguaggi compilati molto rigorosamente tipizzati sono basati su una sintassi banale (pensa ML, Haskell). OTOH, la sintassi di Python è molto pesante, in termini di una serie di regole di sintassi.

E sì, la digitazione non ha nulla a che fare con la sintassi, è sul lato semantico di un linguaggio, a meno che non sia qualcosa di perverso come C ++, dove non è nemmeno possibile analizzare senza avere tutte le informazioni di digitazione disponibili.

Una tendenza generale è che le lingue che si sono evolute per troppo tempo e non contenevano alcuna protezione del progetto contro le deviazioni della sintassi si evolverebbero prima o poi in abominazioni sintattiche.


+1 per avermi fatto sembrare "omoiconico" ... E per il sottile cenno del
capo

1
+1, linguaggi che si sono evoluti troppo a lungo e non contenevano alcuna garanzia di progettazione , fa riferimento anche a Delphi / Object-Pascal?
Apprentice

1
@ThomasEding, ti sbagli. La stessa semantica può essere implementata su un'ampia gamma di stili di sintassi, anche con un linguaggio senza sintassi (come Lisp o Forth). La stessa sintassi può essere utilizzata con una grande varietà di semantiche diverse - ad esempio, la sintassi delle espressioni C e Verilog è quasi la stessa, ma la semantica è drammaticamente diversa.
SK-logic,

1
@ SK-logic - Solo perché è complesso e Turing completo non significa che non sia almeno una parte molto importante della sintassi del programma. L'analisi di varie lingue è Turing-complete, che non esegue magicamente l'analisi di qualcosa che "non ha nulla a che fare con la sintassi". La sintassi non riguarda "ambito", si tratta di regole per la struttura delle istruzioni in una lingua - senza dire nulla sul significato di tali dichiarazioni. Il controllo del tipo e l'inferenza del tipo operano su alberi di sintassi dei programmi senza eseguirli - determinano cose sulla struttura del programma senza dire nulla su ...
Jack

1
@Jack, stai cercando di ridefinire la sintassi. Non ci sono linguaggi pratici che richiedono un parser completo di Turing, la maggior parte non sono altro che privi di contesto. Ed è qui che dovrebbe rimanere la sintassi. Si prega di non estendere questa nozione (già troppo estesa) altrove. E ho già menzionato l'isomorfismo di Curry-Howard: è tutto sulla semantica, ben oltre le semplici regole di correttezza. Penso che il termine " type checking" sia estremamente controproducente e non debba essere usato, è molto fuorviante, non riflette la natura dei sistemi di tipi.
SK-logic,

6

Principalmente questa è una coincidenza.

I linguaggi di programmazione si sono evoluti nel tempo e la tecnologia dei compilatori e degli interpreti è migliorata. L'efficienza dell'elaborazione sottostante (ovvero il tempo di compilazione, le spese generali di interpretazione, i tempi di esecuzione ecc.) È anche meno importante poiché le piattaforme di elaborazione tradizionali sono cresciute di potenza.

La sintassi del linguaggio ha un impatto - per esempio, Pascal era molto attentamente progettato in modo che possa utilizzare un unico compilatore passaggio - vale a dire passare uno sopra l'origine e si dispone di codice macchina excutable. Ada d'altra parte non ha prestato attenzione a questo, e i compilatori Ada sono notoriamente difficili da scrivere - la maggior parte richiede più di un passaggio. (Un ottimo compilatore di Ada che ho usato molti anni fa era un compilatore a 8 passaggi. Come puoi immaginare, è stato molto lento.)

Se guardi vecchie lingue come Fortran (compilato) e BASIC (interpretato o compilato) hanno / avevano sintassi e regole semantiche molto rigide. [Nel caso di BASIC, questo non è il vecchio BASIC di fatture, è necessario tornare prima all'originale.]

D'altra parte, guardando altre cose più vecchie come APL (un bel po 'di divertimento) questo aveva una specie di tipizzazione dinamica. Inoltre è stato generalmente interpretato ma potrebbe anche essere compilato.

La sintassi lenitiva è difficile - se ciò significa che hai cose che sono opzionali o che possono essere dedotte, allora significa che la lingua ha una ricchezza sufficiente da poter essere abbattuta. Ancora una volta, BASIC l'ha avuto molti anni fa quando la dichiarazione "LET" è diventata facoltativa!

Molte delle idee che vedi ora (ad esempio, la tipizzazione senza testo o dinamica) sono in realtà molto vecchie - appaiono per la prima volta negli anni '70 o all'inizio degli anni '80. Il modo in cui vengono utilizzati e le lingue in cui vengono utilizzate queste idee è cambiato e cresciuto. Ma fondamentalmente, gran parte delle novità sono in realtà cose vecchie vestite con abiti nuovi.

Ecco alcuni esempi dalla parte superiore della mia testa:

  • APL: digitazione dinamica. Generalmente interpretato È venuto dagli anni '60 / '70.
  • BASIC: digitazione forte o dinamica. Interpretato o compilato. Anni '70 e molti altri.
  • Fortran: digitazione forte. Compilato. Anni '60 o precedenti.
  • Algol68: tipizzazione forte. Compilato. 1960.
  • PL / 1: tipizzazione forte. Compilato. 1960.
  • Pascal: digitazione forte. Compilato. 1970. (Ma negli anni '80 c'erano compilatori P-System molto simili ai compilatori JIT!)
  • Alcune implementazioni di Fortran e altre da parte di DEC all'inizio furono parzialmente compilate e parzialmente interpretate.
  • Smalltalk: digitazione dinamica. Compilato in bytecode che viene interpretato. 1980.
  • Prolog: più stranezza. Funzionale. Compilato (Turbo Prolog, qualcuno?). 1980.
  • C: digitazione forte (ah ah). Compilato. 1960's..today.
  • Ada: tipizzazione super forte. Compilato. 1980.
  • Perl: digitazione dinamica. (Sintassi forte). Interpretato. 1990 (?).

Potrei andare avanti.

  • Angolo di Nitpickers: molte lingue interpretate sono tokenizzate o "compilate in byte" nel momento in cui la sorgente viene caricata / letta. Questo rende molto più semplice l'operazione successiva dell'interprete. A volte è possibile salvare la versione del codice compilata in byte. A volte non puoi. È ancora interpretato.

Aggiornamento: perché non ero abbastanza chiaro.

La digitazione può variare notevolmente.

La tipizzazione statica fissa in fase di compilazione è comune (ad esempio, C, Ada, C ++, Fortan, ecc. Ecc.). Qui è dove dichiari una COSA di un TIPO ed è così per sempre.

È anche possibile avere una digitazione dinamica, in cui l'oggetto prende il tipo che gli è assegnato. Ad esempio, PHP e alcuni BASIC iniziali e APL, in cui si assegnerebbe un numero intero a una variabile e da quel momento in poi sarà un tipo intero. Se in seguito gli hai assegnato una stringa, allora era un tipo di stringa. E così via.

E poi c'è la digitazione libera, ad esempio PHP in cui puoi fare cose davvero bizzarre come assegnare un numero intero (citato, quindi è una stringa) a una variabile e quindi aggiungere un numero ad esso. (es. '5' + 5 comporterebbe 10). Questa è la terra del bizzarro, ma a volte anche molto utile.

TUTTAVIA queste sono funzionalità progettate in una lingua. L'implementazione lo rende possibile.


13
La tipizzazione forte non è la controparte della tipizzazione dinamica. È la controparte della digitazione debole. La controparte della tipizzazione dinamica è la tipizzazione statica: in una, i tipi di espressioni in un programma possono essere conosciuti staticamente (cioè senza eseguire il programma); in un altro i tipi possono essere conosciuti solo dinamicamente (cioè il programma deve essere eseguito).
R. Martinho Fernandes,

Sì, e entrambe le varianti di BASIC e APL lo stavano facendo alla fine degli anni '70. I tipi di APL non sono esattamente come li comprendiamo oggi (essendo cose come interi / float tipizzati universalmente ma potrebbero anche essere vettori, stringhe e matrici multidimensionali).
quick_now il

Un interprete Fortran è ancora ampiamente usato (vedi Cernlib e PAW). E il suo discendente, ROOT, è basato su un interprete C ++.
SK-logic,

Non sono del tutto chiaro come la tipizzazione forte / debole e statica / dinamica si riferisca alla sintassi, ad essere onesti. Ma la qualità della risposta è stata abbastanza buona, quindi sto solo evitando il voto. Classificherei la classe C come "statica / debole" (è banale guardare un valore memorizzato come se fosse un altro tipo, forse sbagliare il valore).
Vatine,

@Vatine - In realtà direi forte in fase di compilazione, inesistente in fase di esecuzione - se lo desideri in quel modo. Puoi farlo usando i puntatori e il loro equivalente in molte lingue. È anche possibile nel Pascal classico usando i record delle varianti, e in Ada usando UNCHECKED_CONVERSION (anche se difficile, è possibile).
quick_now

2

Penso che sia il contrario: l'implementazione dipende dalla sintassi. Ad esempio, se la sintassi consente la riflessione, l'implementazione deve fornire un runtime che supporti tale.


@IntermediateHacker: ma è in Java, quindi dovrei essere fantastico
vedi il

2

Sono generalmente d'accordo con quick_now in quanto la tua osservazione è principalmente il risultato della storia. Detto questo, il ragionamento sottostante si riduce a qualcosa del genere:

The more modern a language is, the more comfortable it should be to use.

(Non una citazione davvero, solo la mia formulazione.) Quando scrivo comfortablequi, mi riferisco a ciò che hai chiamato best features of both. Più precisamente, non voglio parlare a favore o contro la tipizzazione statica / dinamica o sintassi rigorosa / indulgente. Invece, è importante vedere l'attenzione rivolta agli sviluppatori e aumentare il loro livello di comfort quando si lavora con la lingua.

Ecco alcuni motivi, che non sono stati menzionati nelle risposte precedenti, che potrebbero fornirti alcune idee sul perché osservi queste cose (e sono tutte basate sulla storia della programmazione dello sviluppo di lanugage):

  • Oggi abbiamo centinaia di lingue di programmazione. Quando ne esce uno nuovo, come può trovare un vasto pubblico? Questo è il motivo principale, perché nuove lingue cercano sempre di aumentare il livello di comfort degli sviluppatori. Se la lingua può fare lo stesso di una più vecchia, ma può farlo molto più facilmente / più semplice / più elegante / ecc. potresti voler considerare di cambiare effettivamente.

  • La curva di apprendimento va di pari passo con quella. In passato, avevamo poche lingue e valeva la pena investire tempo per impararne una. Anche se ciò significava investire molto tempo. Il comfort è di nuovo aumentato, se ti viene in mente una lingua che gli sviluppatori possono imparare molto rapidamente. Complessità di qualsiasi tipo (es. Complicata sintassi implicata) ne sono dannose e, di conseguenza, si riducono sempre più nei linguaggi più recenti.

  • I progressi tecnologici (una ragione storica diretta qui) sono responsabili del fatto che i costruttori di compilatori possono ora concentrarsi maggiormente sul comfort degli sviluppatori. All'inizio, eravamo felici di poter costruire un compilatore. Tuttavia, ciò implicava spesso pesanti restrizioni. Con l'aumentare del know-how tecnologico, siamo stati in grado di revocare nuovamente queste restrizioni.

Quindi, in generale, i linguaggi di programmazione e i compilatori hanno visto uno sviluppo simile a quello delle tipiche applicazioni per l'utente finale:

  1. Fase iniziale: è una cosa interessante avere, ma la tecnologia all'avanguardia non fa che funzionare a costo di comfort / usabilità / cosa no.
  2. Miglioramento tecnologico: possiamo costruire queste cose in modo più robusto, più veloce e più facile.
  3. L'attenzione si rivolge all'utente: analogamente al movimento Web 2.0 che si concentra sull'esperienza utente, i nuovi linguaggi di programmazione si concentrano sulla prospettiva dello sviluppatore.

(Not a quote really, just my own formulation.)Bene, l'hai formattato come codice, non come blockquote, quindi non credo che nessuno pensasse che fosse una citazione :)
yannis,

3
Il comfort dipende chiaramente da un gusto (che è sempre del tutto soggettivo). La lingua con cui mi sento più a mio agio è stata progettata nel 1959 e non sopporto di occuparmi di alcune delle lingue che sono apparse in questo secolo.
SK-logic,

1
Il comfort dipende anche dallo scopo. L'esecuzione di PHP o Prolog su un micro 8k incorporato per un controller di lavatrice potrebbe essere "comoda" da programmare, ma anche dannatamente dura per adattarla e funzionare con prestazioni accettabili.
quick_now

0

Un determinato linguaggio di programmazione può o meno esporre o limitare informazioni semantiche sufficienti per un compilatore da dedurre come ridurlo a codice eseguibile senza decisioni di runtime aggiunte ("che tipo è questa variabile?", Ecc.) Alcuni linguaggi sono esplicitamente progettati per rendere questo vincolo è obbligatorio o facile da determinare.

Man mano che i compilatori diventano più intelligenti, potrebbero essere in grado di indovinare o profilare informazioni sufficienti per generare codice eseguibile per i percorsi più probabili anche per le lingue che non sono state progettate esplicitamente per esporre o limitare tali decisioni.

Tuttavia, le lingue in cui il codice (evalString ()) può essere creato o inserito in fase di esecuzione (e altre cose che il compilatore non può dedurre o indovinare) può richiedere che un interprete o un compilatore JIT sia disponibile in fase di esecuzione, anche con tentativi di pre compilali.

In passato, un linguaggio di programmazione e la sua implementazione potrebbero essersi evoluti in modo da adattarsi ad alcuni vincoli hardware, ad esempio se l'interprete potrebbe adattarsi a 4k o 16k o se il compilatore potrebbe finire in meno di un minuto di tempo della CPU. Man mano che le macchine diventano più veloci, è diventato possibile (ri) compilare alcuni programmi precedentemente interpretati con la stessa velocità con cui il programmatore può premere il tasto Invio o interpretare il codice sorgente del programma precedentemente compilato più velocemente di quanto l'hardware leggermente più vecchio possa eseguire eseguibili compilati ottimizzati.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.