2009-05-08 17 views
42

En la conferencia de la biblioteca de Boost hoy, Andrei Alexandrescu, autor del libro Modern C++ Design y la biblioteca Loki C++, dio una charla titulada "Iterators Must Go" (video, slides) sobre por qué los iteradores son malos y tuvo una mejor solución .iteradores de C++ considerados dañinos?

Intenté leer las diapositivas de la presentación, pero no pude obtener mucho de ellas.

  1. ¿Los iteradores son malos?
  2. ¿Es su reemplazo realmente mejor?
  3. ¿Los implementadores de C++ recogerán sus ideas?
+2

Probablemente debería ser una wiki de la comunidad. – Brian

+5

Demasiado tarde, pero no lo creo: es una discusión relacionada con la programación que definitivamente intercambia hechos, no (solo) opiniones. –

+0

Me pregunto por qué no tiene su función find() devuelve algo así como boost :: optional –

Respuesta

38

En primer lugar, para responder a sus preguntas:

  1. No. De hecho, argumenté elsewhere que los iteradores son el concepto más importante/fundamental de la ciencia de la computación. Yo (a diferencia de Andrei) también creo que los iteradores son intuitivo.
  2. Sí, definitivamente pero eso no debería ser una sorpresa.
  3. Hmm. En cuanto a Boost.Range y C++ 0x, ¿no es cierto?

La gran contribución de Andrei aquí es solo decir: elimine el concepto de iteradores en conjunto, vea los rangos no solo como una envoltura de conveniencia sino como una construcción central. Otros lenguajes ya lo han hecho (muchos de los conceptos de Andrei solo hacen eco de LINQ de .NET o los iteradores de Python) pero todos solo ofrecen rangos de salida . Andrei defiende diferentes tipos de rangos, al igual que las categorías de iteradores convencionales.

En esa luz, es extraño que empiece burlándose de la arbitrariedad de estas categorías de iteradores.

También creo que sus ejemplos están desactivados, especialmente su copia de archivos: sí, la variante del iterador es una gran mejora sobre el código de 1975. Reduce un ciclo con una condición de interrupción complicada hasta una declaración. Lo que realmente está teniendo problema aquí es solo la sintaxis. Bueno, discúlpeme: estamos hablando de C++ aquí - por supuesto la sintaxis es fea. Y sí, usar rangos aquí es una mejora, pero solo sintácticamente.

También creo que la implementación de Andrei find está apagada. Lo que realmente define allí es la operación DropUntil (nombrar es difícil) de LINQ. La operación find realmente debería devolver uno o cero elementos (¡o un iterador!). Evitar los iteradores aquí no es útil en mi opinión, ya que es posible que deseemos modificar el valor directamente en lugar de copiarlo. Devolver un rango de un elemento aquí solo agrega sobrecarga sin un beneficio. Hacerlo de la manera de Andrei es malo porque entonces el nombre del método es simplemente incorrecto y engañoso.

Dicho esto, esencialmente estoy de acuerdo con Andrei en casi todos los puntos. Los iteradores, aunque son mi concepto favorito de la informática, son ciertamente una gran carga sintáctica y muchos rangos (especialmente generadores infinitos) pueden (y deben) implementarse cómodamente sin ellos.

+4

+1: No estoy seguro de que estoy de acuerdo con todo aquí, pero es muy interesante de leer. Casi tan provocativo como el propio gran Alexandrescu :-) –

+0

Es por eso que me encanta programar más que las matemáticas. Hay opiniones y podemos discutir. Mucho más interesante de esta forma. También: los iteradores de flujo resolvieron el problema del rango infinito, por lo que ES POSIBLE. Por supuesto, con una variable de miembro adicional para la señalización del constructor predeterminado, el iterador final sí impone una sobrecarga, en comparación con un ciclo 'while (true)', pero ¿qué tan significativa es esta sobrecarga? – wilhelmtell

+1

@wilhelmtell: Tiene razón, los intervalos infinitos son absolutamente expresables a través de iteradores, pero la sintaxis es engorrosa, ya que tenemos que definir algún iterador "final" arbitrario cuya semántica básica sea justamente distinta de todos los demás iteradores. Eso es bastante artificial. No creo que la sobrecarga del tiempo de ejecución sea significativa aquí, posiblemente inexistente (realmente no tengo idea). Me resulta extraño llamar a una operación con inicio y final cuando en realidad no hay fin. –

3

Estoy de acuerdo con él en que los iteradores son en su mayoría inferiores a los rangos, y no sé si 'algo mejor' será recogido.

"Lo bueno es enemigo de lo mejor" está muy en juego aquí, como suele ser. Los iteradores son útiles y están firmemente arraigados, por lo que es difícil saber si algo mejor, como los rangos, puede suplantarlos en un tiempo razonable.

0

Creo que los implementadores de C++ tendrán sus manos llenas produciendo soporte de trabajo completo para C++ 0x, sin implementar nuevos paradigmas no estándar.

+0

¿No son los rangos estándar en algunos otros idiomas? – Unknown

+0

¿Y qué? Hay muchas cosas disponibles en otros idiomas que no están, y probablemente nunca lo estarán, disponibles en C++. –

1
  1. veces
  2. Probablemente
  3. No es probable, al menos no por muchos años
+6

Casi un haiku, bien hecho muchacho del siglo veinte, danos más? –

2

Creo que deberíamos usar rangos próximos a los iteradores, es decir, deberíamos elegir la forma de evolución, no de revolución.

3

C++ 0x ya está haciendo los primeros pasos:

  • referencias rvalue resolver algunos problemas con el tratamiento de contenedores como rangos
  • rangos se han añadido a la biblioteca núcleo, incluidos los conceptos de rango

La transición a rangos sin perder ninguna funcionalidad de iterador (piense en todas las combinaciones de categorías de iterador, const-ness y rvalue-ness) es difícil, especialmente si trata de factorizar los rangos infinito y mutable.

4
  1. La mayoría de nosotros hace un uso simple de ellos en lo que se han convertido en expresiones idiomáticas bien conocidas, como en bucles para iterar a través de un std :: vector. Un desarrollador lo lee y sabe lo que está pasando. En nuestra vida de codificación diaria, los iteradores no son buenos o malos, simplemente son "lo que hace el trabajo".
  2. Probablemente, sí.
  3. No lo creo.
4

Andrei a veces puede ser un poco provocativo. Los iteradores son un concepto razonable, y bastante fundamentales en el sentido de que los bits sí lo son. Pero al igual que la mayoría de los bits en C++ no son bools, sino que forman parte de tipos más grandes, la mayoría de los iteradores deben tratarse en un nivel alto. Andrei tiene razón en que el nivel adecuado para hacerlo es el objeto rango. Pero no todos los rangos están adecuadamente expuestos como rangos de iteradores, como lo muestra istream_iterator sentinel. Eso es solo un truco para crear un iterador final artificial. Sin embargo, no creo que sus ideas sean recogidas por implementaciones. C++ 1x será tan relevante como C99.

0

El único argumento que puedo ver en esa presentación es la incapacidad de definir rangos, y la propuesta "Range for statement" de C++ 0x parece eliminar ese problema hasta cierto punto de todos modos. tal vez no debería ser un argumento sobre si los iteradores deberían/​​no deberían ser utilizados en absoluto, pero ¿para qué situaciones deberían/​​no deberían usarse?

1

Como cualquier API o función, si se usa incorrectamente puede crear muchos problemas de identificación difíciles. Los iteradores se han utilizado en muchos proyectos, pero siempre manteniendo la atención necesaria según sus características. Su uso debe ir precedido de una buena comprensión de sus limitaciones. Los iteradores pueden ser muy útiles si el usuario lo usa correctamente.Este
preguntas están relacionadas:
Is there any way to check if an iterator is valid?
Should I prefer iterators over const_iterators?

1

estoy de acuerdo tanto con Andrei y Konrad y yo :-)

El concepto más fundamental no es una interfaz de un iterador y que es bastante obvio en cualquier trabajo que alguien haga hoy (que tiene que ver con biblioteca cruzada, lenguaje cruzado, compilador cruzado, sistema operativo cruzado, plataforma cruzada, nombre cruzado :-)

Ni iterador ni rango (aparte de la fuente -lev el use) ofrece algo más que un puntero limpio y simple, no intrusivo o intrusivo, no compartido o compartido, no único o único. Limpiar el puntero a los datos mecanografiados simplemente se pone universal y puede hacer que los datos sean mutables o inmutables y muchas otras cosas. Toda la interfaz es solo otro nivel de direccionamiento indirecto a la vez que sigue siendo amigable con la máquina y el compilador de todo tipo, además de mucho más segura, relegando los iteradores y el uso del rango a un detalle de implementación.

Hasta ese punto, IEnumerable y IQueryable hacen la mitad de 'lo correcto' TM pero son claramente inferiores en sus conceptos de iteración y mucho más que lo que puede hacer con STL, retener el control y así sucesivamente (pero otoh, tienen mejores metadatos y, por lo tanto, un modelo mejor y más limpio). Siendo un punto con las interfaces puede construir cualquier abstracción que desee y satisfaga, probablemente contraversial pero esencialmente no obvia: óptimo, y representación y código de datos neutrales en tiempo de ejecución o en tiempo de compilación (diablos esencial para algoritmos y compiladores y máquinas virtuales y lo que no) .

Incluso es posible optimizarlo para sistemas 'dinámicos'/componentes hasta la alineación 'en tiempo de ejecución' (tornillo HotSpot VM :-) .. Hasta ese punto, el avance a 1975 es mínimo como lo evidencia una enorme industria de interoperabilidad carga de trabajo (está donde sea que mire, incluyendo este sitio, su uso de tecnología patentada y abierta, etc., en idealismo informático, bueno, este tipo de 'trabajo' de interfaz no debería existir si) ..

+0

El punto es que necesita una * interfaz * bien definida (o un conjunto de la misma). Entonces la pregunta es realmente: * ¿qué * interfaz usar? ¿El ofrecido por los iteradores? Rangos? ... –

+0

Totalmente de acuerdo .. imho, algo que nunca será una tecnología o una idea única específica es el camino a seguir, las herramientas de dominio y de modelos tendrán el mismo tiempo difícil allí. Además, el mundo es tal que impone una solución patentada sobre otra para el bloqueo de proveedores, especialmente con máquinas virtuales y sus propias ideas de integración (participación de mercado). Pero todo sigue favoreciendo a la idea de K & R como mínima y completa, al igual que las plantillas y los conceptos en C++ push forward, o de hecho los metadatos de los entornos de ejecución ayudan a otro aspecto de la 'remodelación'/reutilización. Los protocolos son simplemente difíciles de hacer y seguir. –

+0

En una nota lateral, lo que es peor, hace que tweats como Linus en C++ sean un objetivo móvil para el cambio de abstracción casi fundamental que afecta considerablemente al código del cliente (o al punto de facilidad de ruptura). Por otra parte, el kernel de Linux está en un estado tal que no sería adecuado para nada más que para el sistema operativo y la construcción básica (que es suficiente, supongo, pero aún inflexible para el futuro). No es que otros OS-es no estén copiando y reinventando * nix, es decir. W6.0, W7 especialmente, pero la modularidad no proviene solo de la ruptura de la dependencia. [Alguien soluciona las molestas restricciones HTML de ASP.NET para este sitio POR FAVOR] –

2

No es Andrei tratando de hacer un marketing oculto para el lenguaje D (actualmente está trabajando con él) ...?

Andrei afirma que los contenedores están bien, pero los iteradores son feos, no intuitivos, propensos a errores y peligrosos, difíciles de implementar (bueno, este último parece ser bastante cierto ...) Y qué tenemos en C++ ... punteros? ¿No son feos /.../ peligrosos? Pero felizmente los abrazamos y vivimos con ellos.

¿Cuál es más intuitiva para escribir:

for(auto i=foo.begin();i!=foo.end();++i) 
    bar(*i); 

o

for (auto r=foo.all(); !foo.empty(); foo.popFront()) 
     bar(r.front()); 

Iteradores concepto se puede complementar con rangos y otras ideas, pero creo que ellos tienen su lugar y no se ser reemplazado

+1

"¿No está tratando Andrei de hacer marketing oculto para el lenguaje D?" Estaba preguntándose exactamente lo mismo. – Unknown

+1

Lo es, y también está detrás de algunos de los constructos que se volvieron mucho más refinados.Boost se expande continuamente y se reescribe a sí mismo en tiempo de compilación STL, pero rompe interfaces y trae complejidad que mata con muchos errores. No me importa si es C++, D o C#, iterador o no. Solo quiero un código fácil de mantener sin entrar en ese nivel de detalle, así como no quiero entrar en MPL en detalle (es un suicidio, algo que la traducción automática debería estar haciendo en tu intento y no una conjetura sobre la sintaxis para captar su significado con el habitual reflejo de teclado :). Ellos irán'. –

3
  1. No, no están nada mal, de hecho son una idea muy inteligente. Sin embargo, no son ideales y hay espacio para mejoras en el concepto de iterador.

  2. Resuelve el número de problemas de la vida real con iteradores. Por ejemplo, es tedioso (también propenso a errores) en muchos casos consultar dos objetos separados, iteradores, desde un solo contenedor y luego pasarlos como dos objetos separados a un algoritmo. ¿Por qué no pasar un solo objeto? Incluso std::pair<iterator, iterator> crearía un rango crudo que es más fácil de manipular: un objeto, no dos. Además, es una buena idea considerar a range is an iterator.De hecho, eso es lo que sugiere Andrei. Por cierto, algunos de estos problemas ya han sido resueltos por Boost.Range.

  3. Esperaría que sucediera, pero no será una revolución, sino una evolución.