2009-08-20 8 views
6

Pseudo-código:¿Por qué algunos lenguajes de programación le impiden editar la matriz por la que está pasando?

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

no recuerdo el nombre de la excepción de esto arroja en algunos idiomas.

Tengo curiosidad por saber por qué algunos idiomas prohíben este caso de uso, mientras que otros idiomas lo permiten. ¿Los idiomas permitidos son inseguros, abiertos a algún inconveniente? ¿O los lenguajes de prohibición son simplemente demasiado cautos, o quizás perezosos (podrían haber implementado el lenguaje para manejar este caso con elegancia, pero simplemente no se molestaron)?

Gracias!

+1

¿por qué los votos hacia abajo? esta es una pregunta legítima de diseño de lenguaje de programación. –

+0

No puedo pensar en un lenguaje (que he usado) que no le permita _intentar_ editarlo. Sin embargo, podría encontrarse con problemas de concurrencia si eliminara la 'x' de' someArray', entre otras cosas. –

+0

Esto necesita el nombre de los idiomas, y las excepciones que se lanzan, e incluso el código que causó el problema. En pocas palabras, tal vez no estabas haciendo lo que pensabas que estabas haciendo. A menos que se complemente, votaré para cerrarlo. –

Respuesta

9

¿Cuál le gustaría que fuera el comportamiento?

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

comportamientos posibles:

lista es alguna lista vinculada iterador tipo, donde las supresiones no afectan su repetidor actual:

[1,2,3,4] 

lista es cierta matriz, donde el iterador itera a través incremento de puntero:

[1,2,4] 

igual que antes, solo el sistema intenta hacer cac que la iteración contar

[1,2,4,<segfault>] 

El problema es que las diferentes colecciones implementar esta interfaz enumerables/secuencia que permite la foreach-bucle tener diferentes comportamientos.

3

Supongamos que su matriz tiene 10 elementos. Llegas al séptimo elemento y decides que necesitas agregar un nuevo elemento antes en la matriz. ¡UH oh! ¡Ese elemento no se itera! for each tiene la semántica, al menos para mí, de operar en cada elemento de la matriz, una vez y solo una vez.

1

Su código de pseudo ejemplo daría lugar a un bucle infinito. Para cada elemento que mires, agrega uno a la colección, por lo tanto, si tienes al menos 1 elemento para empezar, tendrás i (contador iterativo) + 1 elementos.

+1

Él dice "posiblemente agregue" no "siempre agregue" :) – nos

1

Las matrices se suelen fijar en la cantidad de elementos. Obtiene anchos de tamaños flexibles a través de objetos envueltos (como Lista) que permiten que se produzca la flexibilidad. Sospecho que el lenguaje puede tener problemas si el mecanismo que utilizaron creó una matriz completamente nueva para permitir la edición.

4

Dependiendo del idioma (o plataforma, como .Net), la iteración puede implementarse de manera diferente.

Normalmente, un foreach crea un objeto Iterator o Enumerator en la matriz, que internamente mantiene su estado sobre los detalles de la iteración. Si modifica la matriz (agregando o eliminando un elemento), el estado del iterador sería inconsistente con respecto al nuevo estado de la matriz.

Las plataformas como .Net le permiten definir sus propios enumeradores que pueden no ser susceptibles de agregar/eliminar elementos de la matriz subyacente.

Una solución genérica al problema de agregar/eliminar elementos al iterar es recolectar los elementos en una nueva lista/colección/matriz, y agregar/eliminar los elementos recopilados después de que la enumeración se haya completado.

0

Para poner en práctica las listas y los enumeradores para manejar esto, significaría un montón de gastos generales. Esta sobrecarga siempre estaría allí, y solo sería útil en una amplia minoría de casos.

Además, cualquier aplicación que se han elegido no siempre tendría sentido. Tomemos, por ejemplo, el caso simple de insertar un elemento en la lista al enumerarlo, ¿el nuevo elemento siempre se incluiría en la enumeración, siempre excluido, o debería depender de en qué parte de la lista se agregó el elemento? Si inserto el ítem en la posición actual, ¿cambiaría eso el valor de la propiedad Actual del enumerador, y debería omitir el ítem actualmente en curso que es entonces el próximo ítem?

0

Esto solo ocurre dentro de los bloques foreach. Use un bucle for con un valor de índice y se le permitirá. Solo asegúrese de repetir hacia atrás para poder eliminar elementos sin causar problemas.

0

Desde lo alto de la cabeza podría haber dos escenarios de implementación de iteración en una colección.

  1. se repite el iterador sobre la colección para la que fue creada

  2. se repite el iterador sobre una copia de la colección para la que fue creada

cuando se realizan cambios en el sobre la marcha, la primera opción debería actualizar su secuencia de iteración (que podría ser muy difícil o incluso imposible de realizar de manera confiable) o simplemente negar la posibilidad (lanzar una excepción). El último de los cuales, obviamente, es la opción segura.

En el segundo de los cambios de opción se puede hacer sobre la colección original sin molestar a la secuencia de iteración. Pero cualquier ajuste no se verá en la iteración, esto podría ser confuso para los usuarios (abstracción con fugas).

que podía imaginar lenguajes/librerías que implementan cualquiera de estas posibilidades con igual mérito.

1

Muchos lenguajes compilados implementan "para" bucles con el supuesto de que el número de iteraciones se calculará una vez al inicio del bucle (o mejor aún, el tiempo de compilación). Esto significa que si cambia el valor de la variable "to" dentro del ciclo "for i = 1 to x", no cambiará el número de iteraciones. Hacer esto permite una legión de optimizaciones de bucle, que son muy importantes para acelerar las aplicaciones de procesamiento de números.

Si no le gusta esa semántica, la idea es que debe usar el lenguaje "while" en su lugar.

Tenga en cuenta que en esta vista del mundo, C y C++ no tienen los bucles "para" adecuados, solo loops "while" de fantasía.

Cuestiones relacionadas