2009-08-20 5 views
6

pseudo-codice:Perché alcuni linguaggi di programmazione ti impediscono di modificare l'array che stai trasmettendo?

for each x in someArray { 
    // possibly add an element to someArray 
} 

ho dimenticato il nome dell'eccezione questo getta in alcune lingue.

Sono curioso di sapere perché alcune lingue vietano questo caso di utilizzo, mentre altre lingue lo consentono. Le lingue autorizzate sono pericolose - aperte a qualche trabocchetto? Oppure le lingue proibitive sono semplicemente eccessivamente caute, o forse pigre (potrebbero aver implementato la lingua per gestire con grazia questo caso, ma semplicemente non si sono preoccupati).

Grazie!

+1

perchè il down vota? questa è una domanda legittima di design del linguaggio di programmazione. –

+0

Non riesco a pensare a un linguaggio (che ho usato) che non ti permette di _attempt_ di modificarlo. Potresti incappare in problemi di concorrenza se tra l'altro stavi rimuovendo 'x' da' someArray'. –

+0

Ciò richiede il nome delle lingue e le eccezioni generate, nonché il codice che ha causato il problema. In poche parole, forse non stavi facendo quello che pensavi di fare. A meno che non sia completato, voterò per chiuderlo. –

risposta

9

Cosa vorresti che fosse il comportamento?

list = [1,2,3,4] 
foreach x in list: 
    print x 
    if x == 2: list.remove(1) 

possibili comportamenti:

lista è un certo tipo lista concatenata iteratore, in cui le cancellazioni non influenzano il vostro iteratore corrente:

[1,2,3,4] 

lista è un po 'array, dove il vostro iteratore iterazione tramite incremento di indice:

[1,2,4] 

uguale a prima, solo il sistema prova a cac ha l'iterazione contare

[1,2,4,<segfault>] 

Il problema è che diverse collezioni implementa questa interfaccia enumerable/sequenza che permette foreach-loop avere comportamenti differenti.

3

Supponiamo che l'array abbia 10 elementi. Arrivi al settimo elemento e decidi lì che devi aggiungere un nuovo elemento prima nell'array. Uh Oh! Questo elemento non viene iterato! for each ha la semantica, almeno per me, di operare su ogni elemento dell'array, una volta e una sola volta.

1

Il codice di pseudo esempio porta a un ciclo infinito. Per ogni elemento che guardi, ne aggiungi uno alla raccolta, quindi se hai almeno 1 elemento con cui iniziare, avrai i (contatore iterativo) + 1 elementi.

+1

Dice "possibilmente aggiungere" non "aggiungi sempre" :) – nos

1

Gli array sono in genere fissati nel numero di elementi. Si ottengono larghezze di dimensioni flessibili tramite oggetti avvolti (come List) che consentono la flessibilità. Ho il sospetto che la lingua potrebbe avere problemi se il meccanismo che hanno usato ha creato un intero nuovo array per consentire la modifica.

4

A seconda della lingua (o della piattaforma, come .Net), l'iterazione può essere implementata in modo diverso.

In genere un foreach crea un oggetto Iterator o Enumerator sull'array, che mantiene internamente il suo stato sui dettagli di iterazione. Se si modifica l'array (aggiungendo o eliminando un elemento), lo stato iteratore sarebbe incoerente rispetto al nuovo stato dell'array.

Piattaforme come .Net consentono di definire i propri enumeratori che potrebbero non essere suscettibili di aggiungere/rimuovere elementi dell'array sottostante.

Una soluzione generica al problema dell'aggiunta/rimozione di elementi durante l'iterazione consiste nel raccogliere gli elementi in una nuova lista/raccolta/matrice e aggiungere/rimuovere gli elementi raccolti dopo che l'enumerazione è stata completata.

0

Per implementare le liste e gli enumeratori per gestirli, significherebbe un sacco di spese generali. Questo sovraccarico sarebbe sempre presente, e sarebbe utile solo in una vasta miniorità dei casi.

Inoltre, qualsiasi implementazione scelta non avrebbe sempre senso. Prendiamo ad esempio il semplice caso di inserire un elemento nell'elenco mentre lo si enumera, il nuovo elemento dovrebbe sempre essere incluso nell'enumerazione, sempre escluso, o dovrebbe dipendere da dove è stato aggiunto l'elemento nell'elenco? Se inserisco l'articolo nella posizione corrente, cambierebbe il valore della proprietà Current dell'enumeratore e dovrebbe saltare l'elemento attualmente corrente che è quindi l'elemento successivo?

0

Questo succede solo all'interno di blocchi foreach. Utilizza un ciclo for con un valore di indice e sarai autorizzato a farlo. Assicurati di eseguire l'iterazione all'indietro in modo da poter eliminare gli elementi senza causare problemi.

0

Dall'alto della mia testa potrebbero esserci due scenari di implementazione dell'iterazione su una raccolta.

  1. le itera iteratore sulla collezione per cui è stato creato

  2. le itera iteratore su una copia della collezione per la quale è stato creato

quando vengono apportate modifiche al raccolta al volo, la prima opzione dovrebbe aggiornare la sequenza di iterazione (che potrebbe essere molto difficile o addirittura impossibile da fare in modo affidabile) o semplicemente negare la possibilità (lanciare un'eccezione). L'ultimo dei quali ovviamente è l'opzione sicura.

Nella seconda opzione è possibile apportare modifiche alla raccolta originale senza infastidire la sequenza di iterazione. Tuttavia, qualsiasi aggiustamento non verrà visualizzato nell'iterazione, ciò potrebbe creare confusione per gli utenti (astrazione che perde).

Potrei immaginare linguaggi/biblioteche che implementano una di queste possibilità con lo stesso valore.

1

Molti linguaggi compilati implementano cicli "for" con l'ipotesi che il numero di iterazioni verrà calcolato una volta all'avvio del ciclo (o, meglio ancora, in fase di compilazione). Ciò significa che se cambi il valore della variabile "a" all'interno del ciclo "for i = 1 to x", non cambierà il numero di iterazioni. Ciò consente una legione di ottimizzazioni del ciclo, che sono molto importanti per accelerare le applicazioni di sgranatura numerica.

Se non ti piace quella semantica, l'idea è che dovresti usare invece il costrutto "while" della lingua.

Si noti che in questa visione del mondo, C e C++ non hanno loop "for" appropriati, ma solo cicli "while".