Principio KISS applicato alla progettazione del linguaggio di programmazione?


14

KISS ("Keep it simple, stupid" o "keep it simple stupid", vedi ad esempio qui ) è un principio importante nello sviluppo del software, anche se apparentemente ha avuto origine in ingegneria. Citando l'articolo di Wikipedia:

Il principio è meglio esemplificato dalla storia di Johnson che consegna a una squadra di ingegneri di progettazione una manciata di strumenti, con la sfida che l'aereo a reazione che stavano progettando deve essere riparabile da un meccanico medio sul campo in condizioni di combattimento solo con questi strumenti. Quindi, lo "stupido" si riferisce alla relazione tra il modo in cui le cose si rompono e la raffinatezza disponibile per risolverle.

Se volessi applicarlo al campo dello sviluppo del software, sostituirei "aerei a reazione" con "software", "meccanico medio" con "sviluppatore medio" e "in condizioni di combattimento" con "sotto lo sviluppo / manutenzione del software previsto condizioni "(scadenze, vincoli temporali, riunioni / interruzioni, strumenti disponibili e così via).

Quindi è un'idea comunemente accettata che si dovrebbe provare a mantenere un pezzo di software semplice (o semplice stupido , nel caso in cui si ometta la virgola) in modo che sia facile lavorarci su in seguito.

Ma il principio KISS può essere applicato anche alla progettazione del linguaggio di programmazione? Conoscete dei linguaggi di programmazione che sono stati progettati specificamente tenendo conto di questo principio, vale a dire "consentire a un programmatore medio in condizioni di lavoro medie di scrivere e mantenere il maggior codice possibile con il minimo sforzo cognitivo"?

Se citi una lingua specifica, sarebbe bello poter aggiungere un link ad un documento in cui questa intenzione è chiaramente espressa dai progettisti della lingua. In ogni caso, sarei interessato a conoscere le intenzioni (documentate) dei designer piuttosto che la tua opinione personale su un particolare linguaggio di programmazione.


4
Hai esplorato la famiglia di lingue di base (o almeno l'intento originale dietro di loro)?

4
BASIC e Pascal ... entrambi progettati come linguaggi didattici.
Michael Brown,

1
Cosa intendi con semplice? La maggior parte delle lingue è piuttosto semplice, in quanto non c'è molto da dire. Niente era meno complesso dell'assemblatore. I framework sono spesso complicati, ma sono progettati per consentire "di scrivere e mantenere il maggior codice possibile con il minimo sforzo cognitivo".
pdr

7
Lo schema (r) è stato usato come lingua di insegnamento per anni (decenni?) Ed è stato sviluppato semplificando LISP e Algol (e potrebbe essere di più). Il libro SICP richiede molto meno tempo per insegnare la lingua stessa. Inoltre, mi vengono in mente le DSL.
vpit3833,

3
@Giorgio dai un'occhiata a Haskell. Ha molto e intendo pochissimi bit incorporati. La maggior parte degli operatori sono funzioni presenti nella libreria principale, ma non necessarie alla lingua stessa, ha fatto di tutto per rimuovere tutti i pezzi non necessari
Jimmy Hoffa,

Risposte:


15

Quando penso al minimalismo, penso a Lisp and Go . Con Lisp, tutto ciò che hai sono funzioni ed elenchi, il più semplice possibile (beh, c'è un po 'di più, ma qualunque cosa). Tuttavia, penso che il caso Go sia più interessante.

Go è stato progettato per essere semplice (è una lettura decente). Il termine che usano è "ortogonalità delle caratteristiche", il che significa che qualsiasi caratteristica dovrebbe essere aggiunta solo se fornisce qualcosa di veramente unico. Ciò sembra derivare dal coinvolgimento degli autori ( Russ Cox e Rob Pike vengono in mente) con Plan9 , che era una reimmaginazione di UNIX pensando alla semplicità. (Se sei interessato al design minimale, la carta di Rob Pike su un semplice sistema di finestre è una buona lettura.)

Ecco alcuni semplici esempi della sintassi:

Solo un costrutto loop

Un loop può apparire come uno dei seguenti:

Ciclo infinito

for {
}

Mentre loop

for <conditional> {
}

Tradizionale per loop

for i := 0; i < 10; i++ {
}

Ciclo foreach

// works for maps or arrays
for k, v := range arr {
}

Interruttore multiuso

switch {
    // cases must be evaluate to a boolean
}

switch <value> {
}

switch t := <value>; t {
    // can use t inside
}

Ritorno multiplo

return val1, val2, ...
  • Elimina la necessità di lanciare (passa l'errore come ultimo valore restituito)
  • Elimina la necessità di parametri out
  • Elimina la necessità di tuple

interfacce

type X interface {
    DoSomething()
    String() string
}
  • Risolve problemi simili ai generici
  • Permette l'astrazione

Embedding

type A struct {
    Thing string
}

type B struct {
    A // embeds A in B, so B.Thing refers to A.Thing
}
  • Risolve lo stesso problema dell'ereditarietà
  • Richiede la necessità di lezioni

canali

Può essere utilizzato per implementare i semafori

var c = make(chan bool, 1)
c<-true // semaphore lock
<-c // semaphore free

Utilizzato per il passaggio di messaggi tra i thread

func produce(c chan<- bool) {
    for {
        c <- true
    }
}
func consume(c <-chan bool) {
    for {
        <-c
    }
}

var c = make(chan bool)
go produce(c)
go consume(c)

Può essere usato per gestire eventi asincroni

func async() chan bool {
    var c = make(chan bool)
    go doSomethingAsync(c)
    return c
}

// wait for long async process to finish
c := async()
select {
    case _ = <-c:
}

Conclusione

Non entrerò in ogni parte della sintassi, ma spero che tu possa vedere cosa può fare il minimalismo. Il linguaggio è intrigante non perché aggiunge una tonnellata di nuove funzionalità, ma perché utilizza le migliori funzionalità di altre lingue senza nulla in più.

Di solito c'è un modo "migliore" per risolvere un problema. Ad esempio, nella mailing list, molti utenti lamentano di non avere farmaci generici. Dopo la discussione, si rendono conto che tutto ciò che vogliono fare può essere fatto con le interfacce. Leggi su efficace vai per esempi sulla sintassi idiomatica.

Il vantaggio delle lingue KISS è che è possibile scrivere codice idiomatico, poiché lo stile del codice è limitato dalla lingua. Ad esempio, in Go non puoi scrivere qualcosa del genere:

if <condition>
    statement;

Devi usare le parentesi graffe:

if <condition> {
    statement;
}

Ci sono molti altri esempi di questo nella sintassi, che semplifica la lettura del codice di altre persone.

Vantaggi del linguaggio KISS rispetto a linguaggi caratteristici:

  • più facile da capire il codice degli altri
  • più facile da comprendere nell'intero linguaggio (C ++ è noto per essere difficile da capire)
  • concentrarsi sull'algoritmo, non sulla sintassi

5
Secondo la mia modesta opinione, la sintassi del tradizionale ciclo per non è che KISS. Ovviamente è familiare a tutti i programmatori di tipo C, ma ricordo la prima volta che ho imparato questo: ero molto confuso. BASIC è più BACIO: for i=1 to 10o pitone:for item in group
mouviciel

3
@mouviciel - Non uso quasi mai il tradizionale ciclo per. Il problema for i = 1 to 10è se isarà mai 10. Questo può dipendere dalla lingua (bash include 10, python no). Il tradizionale per loop è universale.
beatgammit,

+1, in particolare per il riassunto dei vantaggi del minimalismo.
Giorgio,

1
Vai come caso di studio è interessante perché non è considerato un linguaggio KISS dai suoi detrattori. In realtà, l'argomento va così: un linguaggio "semplice" non porta a un codice "semplice" o una comprensione più semplice. A volte ci deve essere più complessità (diciamo, un buon supporto generici) affinché il codice sia più facile da capire.
Andres F.

14

Penso che lo Zen di Python affermerà perché Python è un linguaggio semplice molto meglio di me:

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Modifica in risposta a @Giorgio

Come afferma la tua domanda,

"Conosci qualche linguaggio di programmazione che è stato progettato specificatamente tenendo presente questo principio, ovvero" consentire a un programmatore medio in condizioni di lavoro medie di scrivere e mantenere il maggior codice possibile con il minimo sforzo cognitivo ""

Python è, per me, ciò che mi viene subito in mente. Il design di Python risponde direttamente alla metodologia di Perl, il famoso "C'è più di un modo per farlo". Anche se è fantastico, consentendo ai programmatori di scrivere codice molto facilmente, non aiuta con la manutenzione. Avendo già gestito un programma (scritto molto male, lo ammetto) scritto in Perl, apprezzo Python forzando sia buone pratiche di programmazione che un linguaggio conciso in gola.

Python inoltre non ti obbliga a seguire una particolare metodologia durante la scrittura di programmi. Posso scegliere di seguire uno stile di programmazione orientato agli oggetti o posso scrivere un semplice script da eseguire in sequenza. Non dover inizializzare una classe, quindi chiamare il main()metodo come sei costretto a fare in Java è molto bello. (Inoltre, stampare su stdout in Python è meraviglioso, ma questo è un punto piuttosto nullo).

Infine, la metodologia "Batterie incluse" di includere una vasta libreria standard con il linguaggio è meravigliosa. Invece di cercare alcuni repository esterni per i pacchetti, la maggior parte di ciò di cui ho bisogno è già inclusa nella lingua. È anche bello avere quel repository esterno, ma non doverlo scavare per fare un'operazione di base è davvero utile.


3
Grazie per l'utile citazione. È questa l'intenzione ufficiale dei designer di Python? Inoltre, nota che non tutti i lettori potrebbero essere d'accordo con la tua opinione su Python, quindi è forse un po 'troppo forte affermare che "Python è un linguaggio semplice" come un fatto ben noto e accettato. Sarebbe possibile formularlo come "Python è stato progettato pensando alla semplicità"?
Giorgio,

@Giorgio - È l'esperienza di molti sviluppatori qui intorno che Python in realtà è un linguaggio semplice. Semplice da imparare, semplice da scrivere e semplice da leggere. A proposito del preventivo, poiché python è "batterie incluse", puoi ottenerlo direttamente dalla lingua con il import thiscomando.
mouviciel,

1
Anche TCL è una buona risposta per questo e IIRC era anche una risposta alla complessità del PERL.
jk.

@mouviciel Dopo essermi imbattuto in alcuni punti di spaghetti Python incredibilmente contorti in più punti, non penso più che Python riesca a raggiungere i suoi obiettivi qui. Python non è migliore della maggior parte delle lingue per quanto riguarda la semplicità: può essere molto utile in caso di offuscamento accidentale.
Izkata,

1
Python è semplice purché le persone stiano lontane dalla maggior parte dei __magic_functions __ () e @decorators.
weberc2,

3

Una chiave importante per mantenere la "semplicità" è riconoscere quando sarà necessaria la complessità e farlo fare alle parti del sistema che possono gestirla al meglio. Avere un solo tipo di riferimento all'oggetto che non fa distinzione tra valori immutabili, valori mutabili ed entità, rende Java "semplice", non elimina la necessità di distinguere tra valori ed entità; priva semplicemente i programmatori di strumenti per aiutarli a farlo.

Più in generale, se si sta cercando di avere un linguaggio di programmazione o una funzionalità del framework che supporti più casi d'uso, si dovrebbe garantire che non ci siano situazioni in cui comportamenti diversi sarebbero appropriati in diversi casi d'uso, ma il compilatore non sarebbe in grado di dire a parte. L'aggiunta di più tipi a una lingua o un framework può sembrare una complicazione, ma in molti casi può effettivamente rendere le cose più semplici.

Si consideri, ad esempio, il disordine delle regole che circondano i tipi firmati e non firmati in C. La complessità di queste regole deriva dal fatto che alcuni codici usano tipi interi senza segno per rappresentare numeri, mentre altri codici li usano per rappresentare membri di un anello algebrico avvolgente (in particolare, l'insieme di interi congruenti mod 2ⁿ). Le regole di conversione dei tipi si comportano in modi che a volte sono appropriati per un uso e talvolta in modi appropriati per l'altro. Avere tipi di wrapping e non wrapping separati raddoppierebbe il numero di tipi interi, ma potrebbe semplificare le regole ad essi associate:

  • Qualsiasi tipo intero senza anello di qualsiasi dimensione può essere assegnato a un anello di qualsiasi dimensione; un anello può essere assegnato solo a un anello di dimensioni uguali o inferiori .

  • Operazioni diverse dagli operatori relazionali che coinvolgono un numero intero senza anello e un anello convertiranno implicitamente il numero intero nel tipo di anello.

  • Gli anelli possono essere espressamente espressi in numeri o in anelli più grandi; il valore di un anello senza segno è il numero intero non negativo più piccolo che, se aggiunto allo zero dell'anello, produrrebbe il valore dell'anello. Il valore di un anello con segno è il numero intero di grandezza più piccola che, se aggiunto allo zero dell'anello, produrrebbe il valore dell'anello, con il valore negativo preferito in caso di pareggio.

  • Ad eccezione di quanto sopra menzionato, gli anelli sono limitati alle operazioni con anelli della stessa dimensione o più piccoli.

  • Le operazioni su numeri interi senza anello di tipi diversi devono eseguire l'upgrade dei numeri a un tipo che può contenere tutti i valori di entrambi gli operandi o devono essere respinti dal compilatore se non esiste un tipo adatto

La definizione dei tipi di suoneria sembrerebbe raddoppiare il numero di tipi interi, ma semplificherebbe notevolmente la scrittura di codice portatile. L'uso degli stessi tipi senza segno per numeri e squilli riduce il numero di tipi, ma porta a regole complicate che rendono quasi impossibile scrivere codice portatile efficiente.


+1 Completamente concordato. Un linguaggio "semplice" (semplice nel senso di avere una piccola specifica) non porta necessariamente a un semplice codice, o alla facilità di ragionamento per il programmatore.
Andres F.

Ottimo commento L'aggiunta di complessità dovrebbe essere vista in termini di costi e benefici.
user1071847

2

Probabilmente, Tcl è stato sviluppato seguendo queste linee. L'intera lingua può essere descritta in sole 12 regole in una singola pagina man . È straordinariamente semplice e coerente.

Il creatore di Tcl rivendicò quanto segue come obiettivi originali:

  • La lingua deve essere estensibile: deve essere molto facile per ogni applicazione aggiungere le proprie funzionalità alle funzionalità di base della lingua e le funzionalità specifiche dell'applicazione devono apparire naturali, come se fossero state progettate nella lingua dall'inizio.
  • La lingua deve essere molto semplice e generica, in modo che possa funzionare facilmente con molte applicazioni diverse e che non limiti le funzionalità che le applicazioni possono fornire.
  • Poiché la maggior parte delle funzionalità interessanti verrà dall'applicazione, lo scopo principale del linguaggio è integrare o "incollare" le estensioni. Pertanto la lingua deve avere buone strutture per l'integrazione.

Da " History of Tcl " - http://www.tcl.tk/about/history.html


2

Se una lingua è fissa nel suo design a causa di KISS, non può crescere. Una lingua che non può crescere morirà.

Nel seguente video Guy Steele spiega abilmente che un linguaggio di programmazione deve poter crescere e perché. Se applichi KISS, come può crescere una lingua perché una volta rilasciata, il suo set di strumenti è fisso e non può mai cambiare.

Il keynote di Guy Steele alla conferenza ACM OOPSLA del 1998 su "Crescere una lingua" discute l'importanza e le problematiche associate alla progettazione di un linguaggio di programmazione che può essere sviluppato dai suoi utenti.

È un video di un'ora ma vale la pena guardarlo. Se non sai chi è Guy Steele, dovresti davvero parlare di design del linguaggio.

Ho scelto questo video come risposta perché credo che applicare KISS al design del linguaggio in generale sia sbagliato e spero che vedere un discorso di una persona nota del design del linguaggio aiuterà ad ampliare la tua comprensione del futuro del design del linguaggio.

Da quando sei venuto qui per conoscere il design del linguaggio e ti ho dato una ragione per non usare KISS, è giusto che metta in evidenza qualcosa che trovo di aiuto nel design del linguaggio. Dimensioni cognitive delle notazioni

MODIFICARE

Quando ho scritto la risposta di cui sopra, si basava sul ragionamento di: se un motore può essere mantenuto solo con un set fisso di strumenti, la mia riformulazione di quel significato rispetto al design della lingua è che una lingua non può cambiare una volta rilasciata. I commenti indicano che non era quello che intendeva dire. Permettetemi quindi di presentare questa risposta modificata che sarà più in linea con la comprensione rivista.

Se uno dà un'occhiata alle dimensioni cognitive delle notazioni, allora impara che ci sono molte dimensioni concorrenti associate alla progettazione del linguaggio oltre alla semplice semplicità e se ti concentri troppo su una, soffrirai negli altri. Con la domanda di concentrarsi pesantemente sulla semplicità (KISS) e sostenuta da note persone del design del linguaggio, ho presentato il discorso di Guy Steele per dimostrare che cercare di mantenere un design solo semplice avrà un impatto su altre dimensioni. Ancora più importante, sto cercando di comunicare che è necessario esaminare molte dimensioni e valutare i pro ei contro di esse, non solo la semplicità.


3
Quindi, cosa succede se il video diventa non disponibile? O se non è accessibile in alcuni paesi? La tua risposta dovrebbe essere completa e autonoma, ti preghiamo di aggiornarla per darci almeno un breve riassunto del video, solo le risposte al link non sono davvero utili e potrebbero essere rimosse in qualsiasi momento.
yannis il

3
@AndreasScheinert La guida su come rispondere chiarisce che i collegamenti devono essere sempre accompagnati da riepiloghi e / o citazioni pertinenti.
Thomas Owens

3
Non sono sicuro di poter essere d'accordo con la tua valutazione. Tcl, ad esempio, è straordinariamente semplice. Durò per anni con solo 11 regole che ne governano l'utilizzo. Tuttavia, per quanto semplice, è cresciuto considerevolmente negli oltre 20 anni della sua esistenza. Ora ha 12 regole, a dimostrazione del fatto che non solo è cresciuta la sua biblioteca, ma è stata anche permessa la sua natura fondamentale, pur mantenendo tutta la sua semplicità.
Bryan Oakley,

1
"Se applichi KISS, come può crescere una lingua perché una volta rilasciata, il suo set di strumenti è fisso e non può mai cambiare". Dipende da cosa intendi per semplice e per crescita. Vuoi dire aggiungere nuove librerie (in inglese, aggiungere nuove parole al vocabolario) o aggiungere nuovi costrutti di lingua (in inglese questo significherebbe aggiungere, ad esempio nuovi tempi verbali, nuove preposizioni e così via). Le lingue naturali alla fine smettono di aggiungere nuove regole grammaticali mentre continuano ad aggiungere nuove parole. Quindi, nella mia intuizione, semplice si riferisce al numero di regole grammaticali, piuttosto che al numero di librerie / parole.
Giorgio,

3
@Guy Coder: D'altra parte, il video a cui hai pubblicato un link sembra dire qualcosa di diverso rispetto a quello che dici all'inizio della tua risposta, vale a dire che una lingua dovrebbe fornire alcune funzionalità di base che consentono ai suoi utenti (programmatori) di estendere la lingua (aggiungere nuove librerie). Non dice che il linguaggio di base dovrebbe crescere indefinitamente.
Giorgio,

1

Ecco una grande citazione di Hardcore Visual Basic di Bruce McKinney , che a sua volta mette le parole in bocca ai designer di BASIC, Kemeny e Kurtz . Sottolinea il mio.

Ogni linguaggio informatico ha la sua atmosfera, la sua atmosfera, il suo spirito. Non puoi davvero definire questo spirito, ma sai cos'è quando lo vedi. Penso a Basic come all'antitesi di un'affermazione attribuita ad Albert Einstein:

Rendi le cose il più semplice possibile, ma non più semplice.

Se quella citazione fosse stata scritta dai progettisti originali di Basic, John Kemeny e Thomas Kurtz, sarebbe stata ulteriormente semplificata:

Rendi le cose più semplici del possibile.

Questa è la contraddizione con cui vivono i programmatori di Visual Basic. Vogliamo che le cose siano semplici, eleganti e intuitive, ma non lo sono. Vogliamo che i nostri programmi modellino la realtà, ma non lo fanno. Vogliamo che la nostra lingua funzioni nel modo in cui pensiamo, non nel modo in cui i computer o i sistemi operativi vogliono farci pensare, ma non siamo disposti a pagare il prezzo .


In una nota correlata, il fatto che un costrutto linguistico "possa" essere fatto per servire molteplici scopi non significa che un tale progetto sia preferibile ad avere differenti costrutti per quei diversi scopi. Ad esempio, C utilizza tipi senza segno sia per rappresentare quantità numeriche sia per rappresentare membri di un anello algebrico avvolgente. L'aggiunta di un numero di qualsiasi dimensione o firma a un anello dovrebbe produrre un membro dello stesso anello, mentre l'aggiunta di due numeri di qualsiasi dimensione e firma dovrebbe produrre un risultato abbastanza grande da gestire qualsiasi valore di entrambi gli operandi. Utilizzo di tipi non firmati per entrambi gli scopi ...
supercat

... significa che le regole di C devono a volte considerarli come numeri e talvolta come membri dell'anello, in modi che rendono quasi impossibile scrivere un codice pulito e portatile.
supercat

1

Ma il principio KISS può essere applicato anche alla progettazione del linguaggio di programmazione? Conoscete dei linguaggi di programmazione che sono stati progettati specificamente tenendo conto di questo principio, vale a dire "consentire a un programmatore medio in condizioni di lavoro medie di scrivere e mantenere il maggior codice possibile con il minimo sforzo cognitivo"?

È una buona cosa che tu abbia chiarito cosa intendi con "semplice", perché nella mia mente un semplice linguaggio di programmazione è uno con una sintassi minima e poche funzionalità (Scheme, Forth, ML), che non si traduce direttamente nella tua definizione. Penso che tu stia davvero cercando la progettazione di linguaggi pensando a RAD (rapido sviluppo di applicazioni), e ce ne sono parecchi. Vedi questo thread StackOverflow, ad esempio: /programming/66227/what-is-the-best-multi-platform-rad-language


"perché nella mia mente un semplice linguaggio di programmazione è uno con una sintassi minima e poche funzionalità (Scheme, Forth, ML)": Beh, in realtà ho copiato la definizione da Wikipedia ma tendo a identificare le due cose. Ad esempio, Scheme può essere appreso molto rapidamente e successivamente posso concentrarmi sul problema da risolvere. Altre lingue (come C ++, che uso al lavoro) continuano a crescere e devi imparare nuove cose in ogni momento. Inoltre, il codice diventa meno gestibile perché diversi programmatori tendono a utilizzare diversi sottoinsiemi della lingua. Quindi, considererei SML e Schema "semplici".
Giorgio,

1

Sono sorpreso che nessuno abbia citato ancora C, anche se mette la semplicità al primo posto in molti modi importanti, spesso in modo così radicale che i programmatori non riescono ad apprezzare la semplicità:

  • Non c'è magia nascosta. Se scrivi a + bin C, hai la garanzia che verrà compilato al massimo in un'unica istruzione assembler.

    Anche in linguaggi relativamente semplici come Java, un'istruzione semplice come a + bpuò richiedere diversi microsecondi (se le variabili sono stringhe). Altre lingue aggiungono molto, molto di più a questo con l'esempio estremo di C ++ dove a + bpuò essere sovraccaricato per far apparire gli elefanti rosa. Non così in C: se non è una chiamata di funzione, non ci vorrà più di qualche nanosecondo. Questa prevedibilità delle prestazioni è una delle caratteristiche chiave di C ed è certamente una forma di semplicità.

  • I tipi di dati sono semplici quanto possono essere mentre descrivono ancora tutte le strutture di dati interessanti che potresti voler costruire in memoria: Esistono solo i tipi fondamentali che una CPU può gestire + aggregazione ( struct) + ripetizione (array) + riferimenti (puntatori ).

    È vero che i vari linguaggi basati su lisp sono molto più semplici di C in questo senso. Tuttavia, non tentano di consentire al programmatore di manipolare liberamente la memoria come fa C.

  • Ortogonalità delle funzionalità: puoi combinare liberamente le funzionalità e funzioneranno insieme come previsto. Molte lingue non riescono, consentendo ad alcuni costrutti di apparire solo in contesti definiti.

    Prendiamo ad esempio matrici a lunghezza variabile in C e C ++: C consente lunghezze di runtime ovunque mentre le richieste più liberali di espandere lo standard C ++ le consentono solo in determinati contesti come le matrici automatiche e anche lì solo nella prima dimensione. Ciò consente a C di gestire vere matrici multidimensionali con dimensioni note solo in fase di esecuzione, mentre i programmatori C ++ sono ridotti a scrivere data[k + (j + i*lineLength)*lineCount]più e più volte.

    Un altro esempio di questo è il puntatore: un puntatore di dati in C in realtà non è altro che una semplice variabile che contiene un indirizzo di memoria di qualche altra variabile. Poiché il puntatore è esso stesso una variabile, il doppio puntatore è una cosa ben definita. Vale a dire cosa inte cosa int*sono, è chiaro cosa int**deve essere. Confronta questo con riferimenti C ++ in cui non hai assolutamente idea di cosa int&&sia dato il significato di inte int&!)

È vero che è proprio questa semplicità che ha guadagnato a C un così tanto odio: la semplicità del linguaggio consente ai programmatori più libertà di quella che fa bene a loro, portando a molti problemi con comportamenti indefiniti e indicazioni mal gestite. Soprattutto la semplicità dell'ortogonalità che consente a un programmatore di definire una variabile in quanto int (*array[m])(struct foo* (*arg)[n])è del tipo che tende a dare mal di testa ai lettori perché roba davvero complessa può essere espressa in forma molto concisa dalla combinazione liberale di alcune semplici funzionalità . Questo è il tipo di semplicità con cui C eccelle e che gli conferisce la reputazione di essere un linguaggio difficile da usare.

Inoltre, la semplicità del linguaggio costringe il programmatore a scrivere molto più codice rispetto a linguaggi più ricchi di funzionalità, fornendo un terreno più fertile per far fiorire i bug. Tuttavia, rimane il linguaggio di alto livello più semplice possibile se il tuo obiettivo principale è programmare un computer reale e non una macchina virtuale.


Il downvoter può lasciare un messaggio che spiega il motivo del suo voto?
Giorgio,

C è un casino. Prova a capire cosa otterrai se aggiungi un short firmato a un long unsigned e memorizzi il risultato in un int. Anche senza "long long", ha otto diversi tipi interi. Non è semplice
Simon B,

@SimonB Chiaramente non hai capito di cosa tratta il mio post. La semplicità dei tipi interi è questa: un tipo intero ha una dimensione (in byte e bit) e può essere con segno o senza segno. È possibile utilizzare qualsiasi combinazione di queste due funzioni ortogonali. È questa ortogonalità di cui sto parlando. C ha tutte le funzionalità necessarie per sfruttare appieno l'hardware reale e ciò comporta una certa complessità. Tuttavia, il modo in cui C affronta questa complessità è combinando concetti semplici in modo ortogonale per consentire al programmatore di fare cose complesse.
cmaster - ripristina monica

0

Java Wikipedia - sebbene non sia esplicitamente dichiarato in Wikipedia, la semplificazione è menzionata più volte ed era un obiettivo di progettazione originale, poiché l'unico linguaggio serio in grado di OO (termine usato liberamente) in quei giorni era il C ++, che come tutti sappiamo, è potente ma ha più di alcune trappole per gli incauti.

La JVM era intesa come un modo per semplificare lo sviluppo multipiattaforma e "Write once Run ovunque" è diventato un mantra Java per alcuni anni - ancora una volta, l'intento era che il framework fosse semplice da implementare.

Credo che C # rientri in quella categoria di semplificazione della lingua.


Vuoi dire che C # è stato inizialmente progettato anche come una semplificazione del C ++?
Giorgio,

2
C ++ e OO? Alan Kay non la pensa così. C # Sinplyfication ???? Non so cosa intendi per semplice. Penso che sarebbe meglio affermarlo prima di dichiarare le cose come tali. LISP è semplice in quanto ha pochissima sintassi. C # al contrario ha tonnellate di sintassi e parole chiave.
AndreasScheinert,

La capacità di semplificare lo sviluppo multipiattaforma non significa che il linguaggio stesso sia semplice. Qualcosa può essere multipiattaforma ma non è ancora semplice in sé e per sé.
Bryan Oakley,

@Bryan Concordato: la progettazione di Java ha tenuto conto del fatto che i programmi multipiattaforma non erano (al momento) semplici e per creare programmi semplici, era necessario un linguaggio semplice e necessario per rimuovere la complessità della gestione del codice specifico della piattaforma nel programma stesso.
mattnz,

2
@Giorgio C # era una rivisitazione di Java. Java doveva essere sia meno complesso di C ++ (es. Nessuna eredità multipla) sia qualcosa di molto più grande (es. Vasta libreria standard, garbage collection).
Sean McSomething il

-2

Hm ... questa è in realtà una domanda difficile a cui rispondere "positivamente", perché quando penso alla semplicità nella progettazione del linguaggio di programmazione (e cosa è "più facile" con cui lavorare), penso immediatamente a:

  1. "Leggibilità" del codice: quanto bene il linguaggio incapsula oggetti, metodi, ecc.
  2. La coerenza delle API e delle interfacce linguistiche.

Ci sono un certo numero di lingue che fanno bene queste cose - ma ciò che mi viene in mente è una lingua che non fa bene "come linguaggio di programmazione": PHP.

[Disclaimer - Ho scritto PHP e PHP è ancora il mio 'go to language' per semplici progetti web. Questa è una critica d'amore ...]

In primo luogo, PHP funziona bene per l'ambiente in cui viene generalmente eseguito: i server Web. È facile da installare, facile da mantenere, ecc.

Dove faccio fatica con PHP: quando vuoi fare qualcosa di "insolito" - qualcosa che di solito non fai su base regolare (nel caso in cui sto pensando che stesse consumando un servizio web SOAP - non qualcosa che ho fatto molto con PHP), ti trovi di fronte a due opzioni:

1) Varie estensioni open source a PHP. Il modello a oggetti PHP è abbastanza allentato in cui anche il design dell'interfaccia non è terribilmente coerente da libreria a libreria, da sviluppatore a sviluppatore. Di fronte a una serie di codici in cui qualcuno ha utilizzato una libreria di cui non hai mai sentito parlare, passi molto tempo a capire "cosa diavolo fa" perché il linguaggio consente la creazione di API / librerie libere.

2) Le funzioni "integrate" - di cui ce ne sono molte . Ho attraversato alcuni buchi di coniglio per trovare un'altra biblioteca o implementare un po 'di funzionalità per in qualche modo inciampare suimpossiblyfound_basefunction()

Secondo me, la semplicità è coerenza.


-3

Ora, l'approccio KISS ai linguaggi di programmazione è una nozione divertente, almeno se si considera che i linguaggi di programmazione sono un livello di astrazione per il set di istruzioni di una CPU, ecc. Se non si definisce "KISS" più da vicino. Sto solo dicendo qui che un carro trainato da buoi è KISS applicato a un'auto al massimo.

Ora un'altra interpretazione di KISS potrebbe essere qualcosa di simile "fatto in modo intelligente senza ornamenti inutili e non eccessivamente complicato". Soprattutto si potrebbe sostenere che non dovrebbero esserci troppi casi specifici per cose simili, ecc. Di solito la matematica è abbastanza brava a ridurre le cose alla sua essenza, e - o meraviglia - i matematici hanno trascorso del tempo a pensare alla programmazione e anche ai computer .

Per la programmazione esistono 2 modelli astratti piuttosto famosi:

  • Uno è il turing machine che definisce una macchina e un semplice modello didattico in grado di calcolare tutto ciò che un computer potrebbe fare.
  • L'altro è il Lambda-Calculus di Church et. al. questo è equivalente al potere

La cosa divertente è: sebbene il turing machine sia abbastanza semplice nel suo layout, non è un sistema facile da gestire e non credo che si qualifichi per "KISS intelligente". Ma Lambda Calculus ha più a che fare con i linguaggi di programmazione che conosciamo - e con le caratteristiche pionieristiche di Lisp e Scheme del calcolo lambda si è fatto strada in molti linguaggi.

Lisp e Scheme sono DAVVERO semplici, almeno per quanto riguarda la sintassi. La sintassi è un grosso problema con i linguaggi di programmazione (che è probabilmente il motivo per cui vengono reinventati continuamente). Nel caso del C ++ è quasi inattuabile per il cervello umano prevedere come alcune linee di origine vengono interpretate dal compilatore.)

I lividi stanno riducendo del tutto la complessità sintattica introducendo un modulo comune per i comandi:

(command param1 param2 ...)

Questa può essere una chiamata di metodo, ad esempio

(max 1 2 3 4)

così come un ramo if, loop ecc.

(if (< 1 2) 
    (write 4)
    (write 5))

(tutto il codice qui è pseudo-Lisp / dialettale agnostico)

Il modulo

(command param1 param2 ...)

può anche essere interpretato come un elenco

(item1 item2 item3)

E questa è la base per la semplicità e la bellezza di Lisps. Perché gli elenchi nidificati (come nell'esempio delle ifdichiarazioni) costituiscono alberi e quelli possono essere facilmente compresi sia dalla macchina che dall'essere umano di fronte alla macchina.

Un'altra caratteristica di Lisps sono le macro che non entrerò nei dettagli sporchi qui, ma poiché non vi è alcuna differenza sintattica tra le normali chiamate di funzione e "Sintassi (uovo per loop, dichiarazione di variabili, ecc., Tutto ciò che il parser deve gestire in altri linguaggi di programmazione) è possibile creare la propria sintassi Le macro sono in sostanza Manipolazioni dell'Albero che costituisce il programma.

Penso che Lisp abbia un BACIO per la programmazione. Il fatto di poter manipolare la sintassi usando le macro ha portato a un fenomeno che Lisp si è evoluto in modo abbastanza dinamico. Hai bisogno di una nuova funzionalità linguistica come - diciamo l'orientamento agli oggetti - basta scrivere un sistema OOP con macro!

Mentre la C è stata estesa la rotatoria 2 volte con le funzionalità OOP (C ++, Obj. C) Lisp è stata estesa più volte, alla fine c'è stato un vincitore.

Questa è un'altra stranezza su Lisp, si evolve (vedi Clojure e Clojurescript per l'interessante nuova mutazione di lisp).

Per le sue proprietà KISS Lisps è favorito da alcuni come l'insegnamento delle lingue. Come Fogus delinea nel suo progetto di un linguaggio educativo ( http://blog.fogus.me/2013/01/21/enfield-a-programming-language-designed-for-pedagogy/ )

Per cominciare, sono fermamente convinto che quando apprendere argomenti nuovi, a volte complessi, è assolutamente dannoso sovraccaricare gli studenti con regole di sintassi frivole. Pertanto, Enfield è progettato con regole di sintassi minime e cosa c'è di più minimale di una sintassi simile a Lisp.

2
OP definisce KISS per il contesto di questa domanda piuttosto chiaramente, "consentire a un programmatore medio in condizioni di lavoro medie di scrivere e mantenere il maggior codice possibile con il minimo sforzo cognitivo" . OP menziona anche "interessato a conoscere le intenzioni (documentate) dei progettisti piuttosto che la tua opinione personale su un particolare linguaggio di programmazione"
moscerino del
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.