2010-05-30 5 views
6

Estoy haciendo un compilador simple para un lenguaje de mascotas simple que estoy creando y que proviene de un fondo C (aunque lo estoy escribiendo en Ruby) Me pregunto si es necesario un preprocesador.¿Los preprocesadores están obsoletos en los idiomas modernos?

¿Qué opinas? ¿Es necesario un preprocesador "tonto" en los idiomas modernos? ¿Las capacidades de compilación condicional de C# se considerarían un "preprocesador"? ¿Todos los lenguajes modernos que no incluyen un preprocesador tienen las herramientas necesarias para reemplazarlo adecuadamente? (Por ejemplo, el preprocesador C++ ahora está obsoleto (aunque todavía depende de él) debido a las plantillas).

+1

me _No_ decir que el preprocesador es obsoleta en C++. Muchas cosas para las que se usó en C se pueden hacer usando plantillas, pero todavía hay muchos usos para eso. –

+3

C++ todavía necesita el preprocesador para archivos '# include' como mínimo, aunque espero que todos podamos estar de acuerdo en que hay maneras más seguras de manejar archivos múltiples que usar un preprocesador. – sepp2k

+0

@sepp @James Sí, eso es de lo que estoy hablando. Cualquiera que haga '#define foo (x) ...' en C++ o bien no conoce las plantillas de C++ o está trabajando en el código heredado. – Earlz

Respuesta

8

El preprocesamiento de C puede hacer cosas realmente ordenadas, pero si nos fijamos en las cosas que se utilizan para que se den cuenta, a menudo es para agregar otro nivel de abstracción.

  • ¿Preprocesamiento para diferentes operaciones en diferentes plataformas? Básicamente es una capa de abstracción para la independencia de la plataforma.
  • ¿Preprocesamiento para agregar fácilmente código complejo? Abstracción porque el lenguaje no es lo suficientemente genérico.
  • ¿Preprocesamiento para agregar extensiones en su código? Abstracción porque tu código/tu idioma no es lo suficientemente flexible.

Así que mi respuesta es: que no es necesario un preprocesador si su lenguaje es de alto nivel lo suficientemente *. Yo no llamaría preprocesamiento malvado o inútil, solo digo que cuanto más abstracto es el lenguaje, menos razón puedo pensar para que necesite preprocesamiento.

* ¿Qué es lo suficientemente alto? Eso es, por supuesto, completamente subjetivo.

EDIT: Por supuesto, sólo estoy refiriendo realmente a macros. El uso de preprocesadores para interactuar con otros archivos de código o para definir las constantes es malvado.

+0

+1 por * Es básicamente una capa de abstracción para la independencia de la plataforma. * Las macros –

+0

son solo malvadas si no las defines. Los desarrolladores de C deben ser forzados a usar solo macros en ámbitos específicos e indefinidos cuando terminen de usarlos. por ejemplo, #define opciones, #include encabezado, el encabezado hace un trabajo y define las opciones y deja la estructura en bruto atrás, o si es un encabezado de utilidad, usted #include, luego #define UNINSTALL y #incluye el encabezado nuevamente y debería limpiar todas sus macros. De lo contrario, el alcance global se carga bastante rápido, consulte la API de Windows para ver esto en un extremo. – Dmitry

7

El preprocesador es un método barato para proporcionar instalaciones de metaprogramación incompletas a un lenguaje de una manera desagradable.

Prefiere la metaprogramación verdadera o las macros estilo Lisp en su lugar.

+0

Bien dicho. Cualquiera que diseñe un idioma hoy sin macros o algo equivalente debería tener su licencia de diseño de lenguaje eliminada. Consulte Converge (http://ConvergePL.Org/) para saber cómo hacer un potente sistema de metaprogramación en tiempo de compilación en un lenguaje no homicónico con mucha sintaxis. –

2

Creo que los preprocesadores son una muleta para mantener un lenguaje con poco poder expresivo caminando.

He visto tanto abuso de preprocesadores que los odio con pasión.

0

Un preprocesador es una fase de compilación separada. Si bien el preprocesamiento puede ser útil en algunos casos, los dolores de cabeza y los errores que puede causar lo convierten en un problema.

En C, el preprocesador se utiliza sobre todo para:

  1. La inclusión de datos - Si bien poderosa, los casos de uso más comunes no tienen tal poder, e "importación"/"por medio de" cosas (como en Java/C#) es mucho más limpio de usar, y pocas personas necesitan los casos restantes;
  2. Definición de constantes: ¿por qué no proporciona una instrucción "const"?
  3. Macros: mientras que las macros de estilo C son muy potentes (pueden incluir declaraciones como devoluciones), también perjudican la legibilidad.Los genéricos/plantillas son más limpios y, aunque menos poderosos en algunos aspectos, son más fáciles de entender.
  4. Compilación condicional: este es posiblemente el caso de uso más legítimo para los preprocesadores, pero una vez más es doloroso para la legibilidad. Separar el código específico de la plataforma en el código fuente específico de la plataforma y usar declaraciones if comunes termina siendo mejor para la legibilidad.

Así que mi respuesta es mientras potente, el preprocesador perjudica la legibilidad y/o no es la mejor manera de hacer frente a algunos problemas. Los idiomas más nuevos tienden a considerar el mantenimiento de código muy importante, y por esas razones el preprocesador parece ser obsoleto.

+0

Creo que estás haciendo que el problema sea más grande de lo que es. Sí, lograr las transiciones de fase correctas es un problema difícil. Pero es un problema difícil * resuelto *: la comunidad Scheme lo descubrió hace décadas. Solo necesitas robar su trabajo. –

+0

En Scheme, no parece haber un preprocesador. Lo que significa que, si existe, parece que se hizo bien. – luiscubal

+0

¿Por qué la compilación condicional sería el caso de uso más legítimo para un preprocesador? Delphi maneja bien la compilación condicional sin un preprocesador ... –

0

Es su idioma para que pueda crear las capacidades que desee en el idioma en sí, sin necesidad de un preprocesador. No creo que un preprocesador sea necesario, y agrega una capa de complejidad y oscuridad sobre un idioma. La mayoría de los lenguajes modernos no tienen preprocesadores, y en C++ solo los usa cuando no tiene otra opción.

Por cierto, creo que D maneja la compilación condicional sin un preprocesador.

+1

por alguna razón, D se siente como una extensión ficticia de C++ que tiene un compilador real –

+2

D tiene 'static if' que es una declaración' if' que se pone evaluado en tiempo de compilación en lugar de tiempo de ejecución. –

0

Depende exactamente de qué otras características ofrezca. Por ejemplo, si tengo una const int N, ¿me ofrecen que tome N variables? Tener N variables miembro, ¿tomar un argumento para construir todas ellas? Crear N funciones? Realice N operaciones que no necesariamente funcionan en bucles (por ejemplo, pase N argumentos) N argumentos de plantilla? Compilación condicional? Constantes que no son integrales?

El preprocesador C es tan absurdamente poderoso en las manos adecuadas, que necesitaría crear un lenguaje seriamente poderoso para no justificar uno.

5

Un preprocesador es no es necesario. Para la metaprogramación real, debe tener algo como MetaML o Template Haskell o macros y agrave higiénicos; la Scheme. Para cosas rápidas y sucias, si sus usuarios absolutamente deben tenerlo, siempre hay m4.

Sin embargo, un lenguaje moderno debería admitir el equivalente a las directivas de C #line. Dichas directivas permiten al compilador localizar errores en la fuente original, incluso cuando esa fuente está incorporada en un generador de analizador sintáctico o un generador de lecturas o un programa alfabetizado. En otras palabras,

  • Diseñe su idioma para no necesitar un preprocesador.
  • No empaque su lenguaje con un bendito preprocesador.
  • Pero si otros tienen sus propias razones para usar un preprocesador (la generación del analizador es popular), brinde soporte para mensajes de error precisos.
0

Yo diría que aunque debe evitar el pre-procesador para casi todo lo que normalmente hace, sigue siendo necesario.

Por ejemplo, en C++, para escribir una biblioteca de pruebas unitarias como Catch, un pre-procesador es absolutamente necesario. Lo usan de dos maneras diferentes: uno para la expansión de aserción , y otro para las secciones de anidación en los casos de prueba .

Pero no se debe abusar del preprocesador para realizar cálculos en tiempo de compilación en C++ donde se pueden usar las expresiones const y la metaprogramación de plantillas.


Lo siento, no tienen la reputación suficiente para colocar más de dos enlaces, así que voy a poner esto aquí:

  1. github.com/philsquared/Catch/blob/master/ docs/assertions.md
  2. github.com/philsquared/Catch/blob/master/docs/test-cases-and-sections.md
Cuestiones relacionadas