Quali sono i problemi nel portare in una lingua C ++ come const?

17

Mi interessa l'idea di C ++ - come const non quella particolare esecuzione (come castare lontano const ).

Prendiamo ad esempio C # - manca C ++ - come const, e la ragione è il solito - persone e tempo. Qui in aggiunta sembra che il team C # abbia esaminato l'esecuzione in C ++ di const , il CLR di marketing e ne ha avuto abbastanza a questo punto (vedere perché non vi è alcun const metodo membro in c # e parametro const ; grazie Svick). Sii se noi ci spingiamo oltre, è qualsiasi altra cosa?

C'è qualcosa di più profondo? Prendiamo ad esempio il multi-ereditarietà - è solitamente considerato difficile da comprendere (per l'utente) e quindi non aggiunto alla lingua (come il problema dei diamanti).

C'è qualcosa in NATURE di const che pone un problema che è meglio che il linguaggio lo eviti? Qualcosa come decidere se const dovrebbe essere profondo o superficiale (avendo const container vuol dire che non posso aggiungere un nuovo elemento o modificare gli elementi esistenti, e se gli elementi sono di tipo di riferimento)?

UPDATE : mentre menziono C #, e quindi sto facendo una prospettiva storica, sono interessato alla natura dei potenziali problemi di const alla lingua.

Questa non è una sfida delle lingue. Si prega di ignorare tali fattori come le tendenze attuali o la popolarità - Sono interessato solo a problemi tecnici - grazie.

    
posta greenoldman 04.03.2014 - 22:25
fonte

4 risposte

9

Nota se questo è valido per te, ma in linguaggi funzionali come Standard ML tutto è immutabile per impostazione predefinita. La mutazione è supportata da un generico tipo ref erence. Quindi una variabile int è immutabile e una variabile ref int è un contenitore mutabile per int s. Fondamentalmente, le variabili sono reali variabili in senso matematico (un valore sconosciuto ma fisso) e ref s sono "variabili" nel senso di programmazione imperativo - una cella di memoria che può essere scritta e letta da . (Mi piace chiamarli assegnabili .)

Penso che il problema con const sia doppio. Innanzitutto, il C ++ manca della garbage collection, che è necessaria per avere strutture dati persistenti non banali. const deve essere profondi per avere senso, ma avere valori completamente immutabili in C ++ è poco pratico.

In secondo luogo, in C ++ è necessario optare per const piuttosto che rinunciare ad esso. Ma quando ti dimentichi di const qualcosa e successivamente lo aggiusti, finirai nella situazione di "avvelenamento da cost" menzionata nella risposta di @ RobY in cui la modifica di const si sovrapporrà a tutto il codice. Se const era il valore predefinito, non ti ritroverai ad applicare const in modo retroattivo. Inoltre, dover aggiungere const ovunque aggiunge molto rumore al codice.

Sospetto che i linguaggi mainstream che seguirono (ad esempio Java) fossero pesantemente influenzati dal successo e dal modo di pensare di C e C ++. Caso in questione, anche con la raccolta dei rifiuti Le API di raccolta della maggior parte dei linguaggi presuppongono strutture di dati mutabili. Il fatto che tutto sia mutevole e l'immutabilità è visto come un caso isolato parla della mentalità imperativa dietro le lingue popolari.

EDIT : dopo aver riflettuto su commento di greenoldman Mi sono reso conto che const non riguarda direttamente l'immutabilità dei dati; const codifica nel tipo del metodo indipendentemente dal fatto che abbia effetti collaterali sull'istanza.

È possibile utilizzare la mutazione per ottenere il comportamento referenzialmente trasparente . Supponiamo di avere una funzione che, quando viene chiamata, restituisce successivamente valori diversi, ad esempio una funzione che legge un singolo carattere da stdin . Potremmo usare cache / memoize dei risultati di questa funzione per produrre un flusso di valori referenzialmente trasparente. Lo stream sarebbe un elenco collegato i cui nodi chiameranno la funzione la prima volta che si tenta di recuperarne il valore, ma in seguito il risultato verrà memorizzato nella cache. Quindi se stdin contiene Hello, world! , la prima volta che provi a recuperare il valore del primo nodo, leggerà un char e restituirà H . Successivamente continuerà a restituire H senza ulteriori chiamate per leggere char . Allo stesso modo, il secondo nodo leggerà un char da stdin la prima volta che proverai a recuperare il suo valore, questa volta restituendo e e memorizzando il risultato in cache.

La cosa interessante qui è che hai trasformato un processo intrinsecamente statico in un oggetto apparentemente senza stato. Tuttavia, per ottenere questo risultato era necessario mutare lo stato interno dell'oggetto (memorizzando nella cache i risultati) - la mutazione era un effetto benigno . È impossibile rendere il nostro CharStream const anche se lo stream si comporta come un valore immutabile. Ora immagina ci sia un'interfaccia Stream con metodi const , e tutte le tue funzioni prevedono const Streams . Il tuo CharStream non può implementare l'interfaccia!

( EDIT 2: Apparentemente c'è una parola chiave C ++ chiamata mutable che ci consentirebbe di imbrogliare e rendere CharStream const . Tuttavia, questa scappatoia distrugge le garanzie di const - ora non puoi davvero essere sicuro che qualcosa vince 'm mutare attraverso i suoi metodi const . Suppongo che non sia poi così male dal momento che devi richiedere esplicitamente la scappatoia, ma sei ancora completamente dipendente dal sistema d'onore.)

In secondo luogo, si supponga di avere funzioni di ordine elevato, ovvero, è possibile passare funzioni come argomenti ad altre funzioni. const ness fa parte della firma di una funzione, quindi non potresti passare le funzioni non- const come argomenti alle funzioni che aspettano const funzioni. L'imposizione ciecamente di const qui comporterebbe una perdita di generalità.

Infine, la manipolazione di un oggetto const non garantisce che non stia modificando uno stato esterno (statico o globale) dietro la schiena, quindi le garanzie di const non sono così forti come appaiono inizialmente.

Non è chiaro per me che codificare la presenza o l'assenza di effetti collaterali nel sistema dei tipi sia universalmente una buona cosa.

    
risposta data 05.03.2014 - 14:29
fonte
6

Il problema principale è che i programmatori tendono a non usarlo a sufficienza, quindi quando colpiscono un punto in cui è richiesto o un manutentore in un secondo momento desidera correggere la cost-correttezza, c'è un enorme effetto a catena. Puoi ancora scrivere un codice immutabile perfettamente buono senza const , il tuo compilatore semplicemente non lo applicherà, e avrà un tempo più difficile per l'ottimizzazione. Alcune persone preferiscono che il loro compilatore non li aiuti. Non capisco quelle persone, ma ce ne sono molte.

Nei linguaggi funzionali, praticamente tutto è const , ed essere mutabile è la rara eccezione, se è consentito a tutti. Questo ha diversi vantaggi, come una concorrenza più facile e un ragionamento più semplice sullo stato condiviso, ma ci si abitua se si proviene da una lingua con una cultura mutevole. In altre parole, non volere const è un problema di persone, non tecnico.

    
risposta data 05.03.2014 - 14:26
fonte
6

Vedo gli svantaggi come:

  • "avvelenamento da cost" è un problema quando una dichiarazione di const può forzare una dichiarazione precedente o successiva all'uso di const, e ciò può causare la sua precedente delle seguenti dichiarazioni all'uso di const, ecc. E se l'avvelenamento const scorre in una classe in una libreria su cui non hai il controllo, puoi rimanere bloccato in un brutto posto.

  • non è una garanzia assoluta. Di solito ci sono casi in cui il const protegge solo il riferimento, ma non è in grado di proteggere i valori sottostanti per un motivo o per un altro. Anche in C, ci sono casi limite che const non può ottenere, il che indebolisce la promessa fornita da const.

  • in generale, il sentimento del settore sembra essersi allontanato dalle forti garanzie in fase di compilazione, per quanto possa essere di grande conforto per te e per te. Quindi per il pomeriggio trascorro toccando il 66% della mia base di codice perché di avvelenamento const, alcuni tipi di Python hanno colpito 10 moduli Python perfettamente funzionanti, ben progettati, ben collaudati e completamente funzionanti. E non ha nemmeno hackerato quando l'ha fatto.

Quindi forse la domanda è, perché portare avanti una caratteristica potenzialmente controverso che anche alcuni esperti sono ambivalenti quando stai cercando di ottenere l'adozione della tua nuova lingua spiffy?

EDIT: risposta breve, una nuova lingua ha una collina ripida da scalare per l'adozione. I progettisti hanno davvero bisogno di riflettere su quali caratteristiche ha bisogno per ottenere l'adozione. Take Go, per esempio. Google ha brutalmente troncato alcune delle più profonde battaglie religiose facendo alcune scelte di design in stile Conan-the-Barbarian, e in realtà penso che il linguaggio sia migliore per questo, da quello che ho visto.

    
risposta data 05.03.2014 - 08:31
fonte
0

Ci sono alcuni problemi filosofici nell'aggiunta di const a una lingua. Se dichiari const in una classe, significa che la classe non può cambiare. Ma una classe è un insieme di variabili accoppiate con metodi (o mutatori). Raggiungiamo l'astrazione nascondendo lo stato di una classe dietro un insieme di metodi. Se una classe è progettata per nascondere lo stato, è necessario che i mutatori cambino quello stato dall'esterno e quindi non sia più const . Quindi è possibile solo dichiarare const a classi che sono immutabili. Quindi const sembra possibile solo in scenari in cui le classi (oi tipi che vuoi dichiarare const ) sono banali ...

Quindi abbiamo bisogno di const ? Non lo penso. Penso che puoi facilmente fare a meno di const se hai un buon design. Di quali dati hai bisogno e dove, quali metodi sono i metodi data-to-data e quali astrazioni ti servono per I / O, rete, vista, ecc. Quindi si dividono naturalmente moduli e classi che si occupano di stato e si hanno metodi e classi immutabili che non hanno bisogno di stato.

Penso che la maggior parte dei problemi sorgano con oggetti big fat-objects che possono salvare, trasformare e disegnare se stessi e quindi si desidera passarlo ad un renderer, ad esempio. Quindi non è possibile copiare il contenuto dei dati, perché è troppo costoso per un grande oggetto di dati. Ma non vuoi neanche che cambi, quindi hai bisogno di qualcosa come const che pensi. Lascia che il compilatore capisca i tuoi difetti di progettazione. Tuttavia, se si suddividono questi oggetti solo in un oggetto dati immutabile e si implementano i metodi nel modulo responsabile, è possibile passare (solo) il puntatore e fare le cose che si desidera fare con i dati, garantendo al tempo stesso l'immutabilità.

So che è possibile in C ++ dichiarare alcuni metodi const e non dichiarare su altri metodi, perché sono mutatori. E poi qualche tempo dopo hai bisogno di una cache e poi un getter muta un oggetto (perché carica pigro) e non è più const più. Ma questo era il punto centrale di questa astrazione vero? Non sai quale stato viene mutato ad ogni chiamata.

    
risposta data 05.03.2014 - 13:26
fonte

Leggi altre domande sui tag