Vantaggi di una sintassi della lingua da sinistra a destra


18

Ho visto un'intervista con Herb Sutter su Channel9 e alla fine del video ha menzionato che la sintassi da sinistra a destra sarebbe in cima alla sua lista dei desideri per un futuro standard C ++ (anche se riconosce che modificando C ++ in quel modo sarebbe praticamente una bestia completamente diversa).

Oltre ad:

  • più comprensibile per l'uomo, più chiaro a occhio nudo, ad es

    //C syntax
    
    /*pointer to function taking a pointer to function(which takes 2 integers as 
    
    arguments and returns an int), and an int as arguments and returning an int*/
    
    int (*fp)(int (*ff)(int x, int y), int b)
    
    //Go analogous syntax which is left to write
    
    f func(func(int,int) int, int) int
  • più facile da analizzare (porta a un migliore supporto degli strumenti come menzionato nel video - ad es. refactoring del codice)

quali altri vantaggi ci sono con una sintassi "da sinistra a destra" in un linguaggio di programmazione. Conosco solo Pascal e Go che utilizzano quel tipo di sintassi (e Go non va nemmeno per il verso completo come ho capito da questo post sul blog da cui ho preso anche gli esempi) Sarebbe possibile avere un linguaggio di programmazione di sistemi con quel tipo di sintassi?


1
haskell usa da sinistra a destra:f :: (Int -> Int -> Int) -> Int -> Int
Karoly Horvath il

1
ActionScript pure: function strlen(s:String):int {...}. Inoltre, digitava lambda calculus (quindi, Haskell).
Outis

2
Qualcuno potrebbe spiegare per favore i voti di chiusura :)? Non riesco a vedere alcun motivo per chiuderlo, ma forse sto facendo una domanda "sbagliata".

1
Non ho votato per chiudere, ma, il commento di @Devjosh è pertinente, è più appropriato per i programmatori, si spera che qualcuno lo migrerà ....
Nim,

3
@Frank: e non dimenticare, in caso di puntatori di funzioni, che la sintassi è scomoda perché il tipo effettivo è diviso ! È un colpo basso ...
Matthieu M.

Risposte:


12

Il vantaggio fondamentale è che l'analisi è più semplice e unica. Nota che dopo aver analizzato la riga, il compilatore saprà qual è il tipo esatto, quindi da quel momento in poi, come il tipo è stato definito è irrilevante.

Qualsiasi funzione che restituisce un argomento di tipo array o tipo di puntatore a funzione è attualmente difficile da leggere:

// common way of obtaining the static size in elements of an array:
template <typename T, int N>
char (&array_size_impl( T (&)[N] ))[N];
// alternative parser:
template <typename T, int N>               // this would probably be changed also
array_simple_impl function( T [N] & ) char [N] &;

E ci sarebbero meno possibilità di incomprensioni (come l' analisi più irritante ):

// Current C++
type x( another_type() );      // create an instance x of type passing a
                               // default constructed another_type temporary?
                               // or declare a function x that returns type and takes as argument
                               // a function that has no arguments and returns another_type
// How the compiler reads it:
x function( function() another_type ) type;

// What many people mean:
x type { another_type{} };

Utilizzando un approccio simile all'inizializzazione uniforme in C ++ 0x (ovvero {}per identificare l'inizializzazione). Si noti che con un approccio da sinistra a destra è molto più chiaro ciò che stiamo definendo. Molte persone (io di sicuro) sono state morse in qualsiasi momento da questo errore di analisi in passato (più di una volta), e questo non sarebbe il caso di una sintassi da sinistra a destra.


Che ne dici di espressioni? In che modo questa "sintassi da sinistra a destra" influirebbe sulla precedenza dell'operatore e sull'ordine di valutazione?

1
@celavek: Se torni al colloquio, noterai che non vuole cambiare l'intera sintassi della lingua, ma solo dichiarazioni e definizioni . Naturalmente, ciò potrebbe permeare in altre espressioni, non sono troppo sicuro che l'ultima riga degli esempi sopra sia corretta da sinistra a destra (pensa a come viene creato il temporaneo, che potrebbe essere necessario modificare ... in C # che viene risolto dando due semantiche newall'operatore per structo class, che non è applicabile a C ++ poiché in C ++ non ci sono distinzioni su tipi di valore / riferimento
David Rodríguez - dribeas,

5

Come siamo arrivati ​​qui

La sintassi C per dichiarare i punti funzione era intesa a rispecchiare l'utilizzo. Considera una dichiarazione di funzione regolare come questa da <math.h>:

double round(double number);

Per avere una variabile punto è possibile assegnarla a con la sicurezza del tipo utilizzando

fp = round;

dovresti aver dichiarato quella fpvariabile punto in questo modo:

double (*fp)(double number);

Quindi tutto ciò che devi fare è guardare come useresti la funzione e sostituire il nome di quella funzione con un riferimento a puntatore, trasformandolo roundin *fp. Tuttavia, è necessario un set aggiuntivo di parentesi, che alcuni direbbero che lo rende un po 'più disordinato.

Probabilmente, questo era più facile nella C originale, che non aveva nemmeno la firma della funzione, ma non torniamo lì, ok?

Il posto in cui diventa particolarmente brutto è capire come dichiarare una funzione che prende come argomento o restituisce un puntatore a una funzione, o entrambi.

Se avessi una funzione:

void myhandler(int signo);

potresti passarlo alla funzione di segnale (3) in questo modo:

signal(SIGHUP, myhandler);

o se vuoi mantenere il vecchio gestore, allora

old_handler = signal(SIGHUP, new_handler);

che è abbastanza facile. Ciò che è abbastanza facile - né carino, né facile - è ottenere le dichiarazioni giuste.

signal(int signo, ???)

Bene, torni semplicemente alla tua dichiarazione di funzione e scambia il nome con un riferimento di punto:

signal(int sendsig, void (*hisfunc)(int gotsig));

Poiché non stai dichiarando gotsig, potresti omettere di leggere se ometti:

signal(int sendsig, void (*hisfunc)(int));

O forse no. :(

Tranne che non è abbastanza buono, perché il segnale (3) restituisce anche il vecchio gestore, come in:

old_handler = signal(SIGHUP, new_handler);

Quindi ora devi capire come dichiarare tutti quelli.

void (*old_handler)(int gotsig);

è sufficiente per la variabile che si intende assegnare. Nota che non stai dichiarando davvero gotsigsolo qui old_handler. Quindi questo è davvero abbastanza:

void (*old_handler)(int);

Questo ci porta a una definizione corretta per segnale (3):

void (*signal(int signo, void (*handler)(int)))(int);

Typedefs to the Rescue

A questo punto, penso che tutti saranno d'accordo sul fatto che è un casino. A volte è meglio nominare le tue astrazioni; spesso, davvero. Con il diritto typedef, questo diventa molto più facile da capire:

typedef void (*sig_t) (int);

Ora diventa la tua variabile gestore

sig_t old_handler, new_handler;

e la tua dichiarazione per il segnale (3) diventa giusta

sig_t signal(int signo, sig_t handler);

che è improvvisamente comprensibile. Sbarazzarsi di * s anche sbarazzarsi di alcune delle parentesi confuse (e dicono che i genitori rendono sempre le cose più facili da capire - ah!). Il tuo utilizzo è sempre lo stesso:

old_handler = signal(SIGHUP, new_handler);

ma ora si ha la possibilità di comprendere le dichiarazioni per old_handler, new_handlere anche signalla prima volta che loro o necessità incontrano di scriverli.

Conclusione

Molto pochi i programmatori C, si scopre, sono in grado di elaborare le dichiarazioni corrette per queste cose da soli senza consultare i materiali di riferimento.

Lo so, perché una volta avevamo questa stessa domanda sulle domande del nostro colloquio per le persone che facevano il kernel e il driver del dispositivo. :) Certo, abbiamo perso molti candidati in quel modo quando si sono schiantati e bruciati sulla lavagna. Ma abbiamo anche evitato di assumere persone che sostenevano di avere precedenti esperienze in questo settore ma che in realtà non potevano svolgere il lavoro.

A causa di questa diffusa difficoltà, tuttavia, probabilmente non è solo ragionevole, ma in effetti ragionevole avere un modo per fare tutte quelle dichiarazioni che non richiedono più di essere un programmatore geek triplo alfa con tre sigmi sopra la media solo per usare questo una specie di cosa comodamente.


1
Ingannevole, difficile da seguire ... +1 per lo sforzo, anche se illustra il punto che a volte è difficile farlo bene in C.
celavek,

4

Penso che in qualche modo ti sia sfuggito il punto in cui ti sei concentrato sul bit da sinistra a destra.

Il problema di C e C ++ è l'orrenda grammatica che hanno, che è difficile sia da leggere (umani) sia da analizzare (strumenti).

Avere una grammatica più coerente (o regolare ) semplifica entrambi. E l'analisi più semplice significa strumenti più semplici: la maggior parte degli strumenti attuali non riesce a far funzionare correttamente C ++, nemmeno l'ultimo plug-in di Eclipse mentre cercavano di reinventare la ruota ... e fallivano, e probabilmente hanno più persone rispetto al progetto del sistema operativo medio.

Quindi probabilmente l'hai inchiodato quando ti concentri sulla lettura e l'analisi ... e questo è un grosso problema :)


Questa è una grande sorpresa per Eclipse che non è ancora in grado di analizzare cose come le dichiarazioni sopra. Perché non usano un vero parser C come da gcc?
tchrist,

@tchrist: ho rilevato due problemi con Eclipse ed entrambi sembrano collegati alle macro. Forse più un problema di preprocessore che la generazione AST così.
Matthieu M.,
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.