¿Cuál es la diferencia entre "sintaxis" y "azúcar sintáctico"

45

Antecedentes

La página de Wikipedia sobre el azúcar sintáctico dice:

En informática, el azúcar sintáctico es la sintaxis dentro de un lenguaje de programación que está diseñado para facilitar la lectura o la expresión. Hace que el lenguaje sea "más dulce" para que lo usen los humanos: las cosas se pueden expresar más claramente, de manera más concisa o en un estilo alternativo que algunos prefieran.

Realmente no entiendo cuál es la diferencia entre Syntactic Sugar y Syntax.

Aprecio el punto de que la versión azucarada puede ser más clara, más concisa, tal vez hervir un poco. Pero siento que, en algún nivel, toda la sintaxis lo está haciendo esencialmente para formar una abstracción sobre lo que se compila el código.

Desde la misma página de Wikipedia:

Los procesadores de lenguaje, incluidos los compiladores, los analizadores estáticos y similares, a menudo expanden las construcciones azucaradas en construcciones más fundamentales antes del procesamiento, un proceso a veces llamado "desugaring".

Como ejercicio de reflexión, si considero "a menudo" en esta declaración que significa "siempre": si la diferencia fuera solo si el compilador "desugará" la sintaxis antes de pasar a la siguiente etapa, ¿cómo podría un codificador que no conoce las entrañas? del compilador sabe (o le importa) ¿cuál es la sintaxis de Sugar'd o no?

Una pregunta muy relacionada en este sitio "¿Definición rigurosa de azúcar sintáctico?" tiene una respuesta que comienza:

En mi humilde opinión, no creo que pueda tener una definición para el azúcar sintáctico, porque la frase es BS y es probable que sea utilizada por personas que hablan de "programadores reales" que usan "herramientas reales" en "sistemas operativos reales".

¿Qué podría indicarme que quizás no hay una gran diferencia para el codificador que usa el idioma? ¿Quizás la diferencia solo es perceptible para el escritor del compilador? ¿Aunque puede haber casos en los que es útil que el codificador use el lenguaje para saber qué hay bajo el capó del Syntactic Sugar? (¿Pero quizás en realidad algún discurso sobre el tema tiende a usar el término como cebo de fuego?)

El corazón de la pregunta.

Entonces ... la versión corta de la pregunta:

  • ¿Existe una diferencia real entre Syntax y Syntactic Sugar?
  • ¿A quién le importa?

Comida extra para el pensamiento

Bonificación por contradicción de tema:

En la página de Wikipedia se da un ejemplo:

Por ejemplo, en el lenguaje C la a[i]notación es azúcar sintáctica para*(a + i)

Mientras que otra respuesta a la pregunta vinculada anteriormente se refiere al mismo ejemplo:

Ahora considera a[i] == *(a + i). Piense en cualquier programa de C que use matrices de cualquier manera sustantiva.

Y resume que:

La []notación facilita esta abstracción. No es azúcar sintáctico.

¡La conclusión opuesta para el mismo ejemplo!

Don vince
fuente
99
En mi respuesta a la pregunta citada, explico que el azúcar sintáctico es una sintaxis alternativa (para alguna sintaxis que ya existe en el lenguaje) que hace que sea más fácil expresar algunas expresiones idiomáticas comunes pero no introduce una nueva semántica. En este sentido, el azúcar sintáctico depende del contexto (del idioma en el que se usa): la misma notación puede ser sintaxis normal en un idioma y azúcar sintáctico en otro idioma. ¿Te ayuda esta explicación?
Giorgio
77
Un problema es que algunas personas parecen pensar que "azúcar sintáctico" es una mala palabra, cuando no lo es. Cada función o clase que agregue a un sistema podría considerarse "azúcar sintáctica", ya que hacen que las ideas que claramente ya se pueden expresar en el idioma sean un poco (o mucho) más fáciles de expresar.
Joris Timmermans
Aparentemente, te importa.
SShaheen 05 de
11
Al final, todo es solo azúcar sintético sobre electricidad.
Anthony Pegram

Respuestas:

34

La principal diferencia es que la sintaxis es una gramática definida en un lenguaje que le permite exponer algunas funcionalidades. Tan pronto como pueda llegar a esa funcionalidad, cualquier otra sintaxis que le permita hacer lo mismo se considera azúcar. Eso, por supuesto, se encuentra con escenarios extraños sobre cuál de las dos sintaxis es el azúcar, especialmente porque no siempre está claro cuál fue primero.

En la práctica, el azúcar sintáctico solo se usa para describir la sintaxis agregada a un idioma para facilitar su uso, como hacer un lhs + rhsmapa infijo lhs.Add(rhs). Consideraría que la indexación de la matriz de C es azúcar sintáctica.

Importa principalmente porque los diseños elegantes tienden a limitar la cantidad de duplicación. Necesitar (o al menos querer) azúcar sintáctico es visto por algunos como un signo de un diseño fallido.

Telastyn
fuente
"Tan pronto como pueda llegar a esa funcionalidad, cualquier otra sintaxis que le permita hacer lo mismo se considera azúcar": esto no es suficiente para tener azúcar sintáctica, porque cualquier otro programa que calcule la misma función sería azúcar sintáctica . El programa azucarado y el no azucarado deben tener la misma semántica .
Giorgio
3
@Giorgio ¿Cómo es "estos dos programas calculan la misma función" diferente de "estos dos programas tienen la misma semántica"? Aparte de eso, te estás enfocando en programas, no en elementos sintácticos. Los programas completos no pueden ser azúcar sintáctica. Un operador, un tipo de enunciado, etc. puede ser azúcar sintáctico.
@Giorgio: de hecho, estoy considerando una funcionalidad similar con una semántica diferente como una funcionalidad diferente. Y sí, podría haber saltos de aro como escribir su propio compilador que tiene la misma semántica y llamarlo "azúcar". Francamente, una definición formal no va a suceder para un concepto tan informal.
Telastyn 05 de
1
@Giorgio Una vez más, mi problema no es su opinión sobre la equivalencia, sino que intente aplicar el concepto de azúcar sintáctico a los programas. ¡El término no se refiere a programas completos! Dependiendo de su definición, se trata solo de bloques de construcción atómicos, o solo fragmentos cortos del programa (el primero parece cubrir> 80%, pero no estoy seguro de que cubra todo lo que comúnmente se considera azúcar sintáctico).
3
@Giorgio Por ejemplo, programas completos ;-) O algo lo suficientemente grande como para que ambas formulaciones involucren varias palabras clave de lenguaje no relacionadas. Algo que nunca he sido tratado como azúcar sintáctico es if (a) return blah; ...versus result_type res; if (a) res = blah; else {...}; return res;. Tendría que asumir idiomas específicos y obtener un lenguaje extremadamente legal (a menudo hasta el punto de la semántica operativa de pequeños pasos), para encontrar alguna diferencia entre esos programas.
10

La sintaxis es lo que utiliza un procesador de idiomas para comprender lo que significan las construcciones de un lenguaje. Las construcciones que se consideran azúcar sintáctico también deben ser interpretadas por el procesador de idiomas y, por lo tanto, son parte de una sintaxis de idiomas.

Lo que diferencia al azúcar sintáctico del resto de la sintaxis de un idioma es que sería posible eliminar el azúcar sintáctico del idioma sin afectar los programas que se pueden escribir en el idioma.

Para dar una definición más formalista, diría

El azúcar sintáctico son aquellas partes de la sintaxis de un lenguaje cuyos efectos se definen en términos de otras construcciones de sintaxis en el lenguaje.

Esto de ninguna manera pretende denigrar el azúcar sintáctico, o los idiomas que lo tienen, porque el uso del azúcar sintáctico a menudo conduce a programas cuya intención es más comprensible.

Bart van Ingen Schenau
fuente
"No hay forma de decir definitivamente 'esto es azúcar sintáctico y eso es sintaxis', porque el azúcar sintáctico es parte de la sintaxis de un lenguaje". Falso. Es el diseñador del lenguaje el que introduce cierta sintaxis como azúcar sintáctica para alguna construcción que ya está en el lenguaje y tiene una sintaxis. El azúcar sintáctico es normalmente ad-hoc (menos general) pero más legible / conveniente de usar.
Giorgio
@Giorgio: reformulé mi primer párrafo porque era un poco incómodo. Pero no estoy de acuerdo en que el azúcar sintáctico normalmente se agrega ad-hoc. El bit de azúcar sintáctico más conocido es probablemente el ->operador de C y no veo cómo ese operador es menos general que cualquiera de los otros.
Bart van Ingen Schenau
1
@Giorgio: en ese caso, todo lo que no se asigne directamente a una sola instrucción de ensamblaje debe considerarse como azúcar sintáctico, ya que siempre se puede dividir en partes más simples (esto incluye funciones). No creo que encuentres a muchas personas compartiendo esa opinión.
Bart van Ingen Schenau
1
"Ad-hoc" significa que se utiliza en una situación especial y restringida. El término no tiene una connotación negativa en general. El término solución ad-hoc tiene una connotación negativa, porque normalmente se desean soluciones generales, no particulares (para evitar resolver problemas similares una y otra vez).
Giorgio
1
Dado que las "soluciones ad-hoc" a menudo son malas, puede parecer que "ad-hoc" en sí significa malo. Pero también existe la sobrecarga de la función AKA "polimorfismo ad-hoc" ( en.wikipedia.org/wiki/Ad_hoc_polymorphism ), que no está mal. Al menos en italiano (mi lengua materna), el uso del latín "ad-hoc" no es negativo en sí mismo. Si tiene una connotación negativa en inglés, perdone mi ignorancia.
Giorgio
6

Las otras respuestas no han mencionado un concepto clave: sintaxis abstracta ; sin él, el término "azúcar sintáctico" no tiene ningún sentido.

La sintaxis abstracta define los elementos y la estructura de los idiomas, y cómo las frases de ese idioma se pueden combinar para construir frases más grandes. La sintaxis abstracta es independiente de la sintaxis concreta. El término "azúcar sintáctico", según tengo entendido, se refiere a la sintaxis concreta.

En general, al diseñar un idioma, querrá crear una sintaxis concreta para cada término de su sintaxis abstracta, de modo que las personas puedan escribir código en su idioma usando texto sin formato.

Ahora supongamos que crea una sintaxis concreta incómoda para foo . Los usuarios se quejan e implementa una nueva sintaxis concreta para representar la misma sintaxis abstracta . El resultado es que su sintaxis y semántica abstracta no han cambiado, pero ahora tiene dos sintaxis concretas para el mismo término de sintaxis abstracta.

Esto, creo, es lo que las personas quieren decir cuando dicen "azúcar sintáctico": cambios que solo afectan la sintaxis concreta, pero que no afectan la sintaxis abstracta o la semántica.

Y así, la diferencia entre "azúcar sintáctico" y "sintaxis concreta" ahora está clara. A mi. :)

Esta interpretación también ayuda a explicar lo que Alan Perlis podría haber querido decir cuando dijo "el azúcar sintáctico causa cáncer de punto y coma": todo el azúcar sintáctico concreto en el mundo no puede reparar la sintaxis abstracta débil, y todo el esfuerzo que gastas agregando ese azúcar es esfuerzo que no está gastando para lidiar con el problema real: la sintaxis abstracta.


También debo señalar que esta es únicamente mi opinión; Solo lo creo porque es la única interpretación que puedo pensar que tiene sentido para mí.


fuente
1
También había pensado en la sintaxis abstracta de comparación versus sintaxis concreta, pero no estoy seguro de que esto siempre explique el azúcar sintáctico. Por ejemplo, en C, da un puntero pa una estructura que contiene un campo x, hacer las expresiones (*p).xy p->xtener la misma sintaxis abstracta? Pero creo que sería genial si todo se redujera a sintaxis abstracta versus concreta.
Giorgio
@Giorgio desafortunadamente, no sé suficiente C para indicar con confianza si alguno de esos es azúcar sintáctico para el otro, o cómo serían sus árboles de sintaxis abstracta. O incluso si la especificación de C en realidad define una sintaxis abstracta. :(
1
La primera expresión se puede analizar como un árbol con un .en la raíz. El subnodo izquierdo de la raíz es a *, y su hijo es p. El subnodo correcto de la raíz es x. Para la segunda expresión, el árbol de sintaxis abstracta tiene un ->en la raíz y la raíz tiene dos hijos py x. Estoy tratando de averiguar si tiene sentido analizar ambas expresiones de manera diferente para que tengan el mismo árbol de sintaxis abstracta, pero no veo cómo en este momento.
Giorgio
3
No creo que este árbol de análisis, incluso si a menudo se describe como un AST, sea igual a la sintaxis abstracta de la que habla Matt. Ambas expresiones tienen la misma acción ( convertir el tipo de puntero a tipo de referencia, luego obtener referencia al miembrox )
Inútil
1
"Ambas expresiones tienen la misma acción (convertir el tipo de puntero a tipo de referencia, luego obtener referencia al miembro x)": Esto es semántica, no sintaxis abstracta. La sintaxis abstracta se refiere a omitir detalles inútiles de la sintaxis concreta (como (o ;) para producir un árbol que refleje la estructura real de un programa (ver en.wikipedia.org/wiki/Abstract_syntax_tree ). Sin embargo, en sintaxis abstracta no se dice nada (todavía) sobre la semántica del programa.
Giorgio
4

El azúcar sintáctico es un subconjunto de la sintaxis de idiomas. La idea básica es que hay más de una forma de decir lo mismo.

Lo que hace que sea difícil decir qué partes son azúcar sintáctica y cuáles son "sintaxis pura" son declaraciones como "es difícil decir qué forma vino primero" o "es difícil saber de qué manera el autor del lenguaje quiso" o "es algo arbitrario para decidir qué forma es más simple ".

Lo que facilita decidir qué piezas son puras o azucaradas es hacer la pregunta dentro del marco de un compilador o intérprete específico. La sintaxis pura es lo que un compilador convierte directamente en código de máquina o al que el intérprete responde directamente. El azúcar es lo que primero se convierte en otras cosas de sintaxis antes de que sucedan estas cosas directas. Dependiendo de la implementación, esto puede o no ser lo mismo que pretendía el autor o incluso lo que dice la especificación del lenguaje.

En la práctica, esta es la forma en que se decide la realidad del asunto.

Jeff Wolski
fuente
Esta respuesta conecta erróneamente la implementación de la sintaxis a si es azúcar o no. Nunca he visto argumentos = sobre si un elemento de un lenguaje es "azúcar" o no que se refiere a cómo se implementa el elemento. Se trata únicamente de si duplica un elemento diferente, más feo, sintácticamente.
GreenAsJade
3

Realmente, su primera cita de Wikipedia lo dice todo "... hace que las cosas sean más fáciles de leer ...", "... más dulce para que lo usen los humanos ...".

Por escrito, las formas abreviadas como "no" o "no" podrían considerarse azúcar sintáctico.

ozz
fuente
Considere (1) "Debería irme ahora" versus (2) "Debería irme ahora": ¿Es (1) azúcar sintáctico para (2)?
Giorgio
1
@ Jorge, yo diría que no.
ozz
Debido a la legibilidad ("debería" no es más legible que "debería") o debido al significado ("debería" y "debería" tener diferentes significados).
Giorgio
@Giorgio lo suficientemente justo :)
ozz
1
Ah, ya veo :) más de una intuición, supongo, no creo que uno sea más legible que el otro en ese ejemplo
ozz
3

Por lo general, el azúcar de sintaxis es la parte del lenguaje que puede expresarse mediante la parte existente del lenguaje (sintaxis) sin pérdida de generalidad pero posiblemente con claridad perdida. A veces, los compiladores tienen un paso de desagüe explícito que transforma el AST creado por el código fuente y aplican pasos simples para eliminar los nodos correspondientes al azúcar.

Por ejemplo, Haskell tiene azúcar de sintaxis para mónadas con las siguientes reglas aplicadas recursivamente

do { f }            ~> f
do { g; h }         ~> g >> do h
do { x <- f; h }    ~> f >>= \x -> do h
do { let x = f; h } ~> let x = f in do h

En este momento, no importa lo que signifique exactamente; sin embargo, puede ver que la sintaxis especial en LHS se puede transformar en algo más básico en RHS (es decir, aplicaciones de función, lambdas y let's). Estos pasos permiten mantener lo mejor de ambos mundos:

  1. La sintaxis en LHS es más fácil para el programador (azúcar de sintaxis) que expresa las ideas existentes de manera más clara
  2. Sin embargo, como el soporte en el compilador para las construcciones de RHS ya existe en el compilador, no necesita tratarlo como algo especial fuera del analizador y desagüe (excepto para el informe de errores).

De manera similar, en C puede imaginarse desregular la regla de reescritura (debido a la sobrecarga del operador, etc., no es cierto para C ++):

f->h ~> (*f).h
f[h] ~> *(f + h)

Puedes imaginar escribir todos los programas sin usar ->o []en C que usen esta construcción hoy. Sin embargo, sería más difícil para los programadores usarlo, por lo tanto, proporcionó azúcar de sintaxis (supongo que en los años 70 también podría simplificar el trabajo para los compiladores). Posiblemente sea menos claro, ya que técnicamente puede agregar la siguiente regla de reescritura perfectamente válida:

*f ~> f[0] -- * and [] have the same expressiveness 

¿Es mala la sintaxis del azúcar? No necesariamente, existe el peligro de que se use como culto de carga sin comprender un significado más profundo. Por ejemplo, las siguientes funciones son equivalentes en Haskell, sin embargo, muchos principiantes escribirían la primera forma sin comprender que están usando demasiado el azúcar de sintaxis:

f1 = do x <- doSomething
        return x
f2 = doSomething

Además, el azúcar de sintaxis podría complicar demasiado el lenguaje o ser demasiado limitado para permitir un código idiomático generalizado. También puede significar que el lenguaje no es lo suficientemente poderoso como para hacer ciertas cosas fácilmente; podría ser por diseño (no les dé a los desarrolladores herramientas afiladas o un lenguaje de nicho muy específico que agregar una construcción más poderosa dañaría otros objetivos) o por omisión: este último La forma le dio a la sintaxis Sugar el mal nombre Si el lenguaje es lo suficientemente poderoso como para usar otras construcciones sin agregar azúcar de sintaxis, se considera más elegante usarlas.

Maciej Piechotka
fuente
3

Creo que el ejemplo más obvio sería la sintaxis "+ =" en C.

i = i + 1;

y

 i +=  1;

hacer exactamente lo mismo y compilar exactamente el mismo conjunto de instrucciones de la máquina. La segunda forma guarda un par de caracteres al escribir, pero, lo que es más importante, deja muy claro que está modificando un valor en función de su valor actual.

Iba a citar el operador de post / prefijo "++" como ejemplo canónico, pero me di cuenta de que esto era más que azúcar sintáctica. No hay forma de expresar la diferencia entre ++ i e i ++ en una sola expresión utilizando la i = i + 1sintaxis.

James Anderson
fuente
+ = puede ser útil en casos como a[f(x)] += 1.
Florian F
1

Primero, abordaré algunas de las otras respuestas con un ejemplo concreto. El bucle de C ++ 11 basado en el rango (al igual que los bucles foreach en varios otros idiomas)

for (auto value : container) {
    do_something_with(value);
}

es exactamente equivalente a (es decir, una versión azucarada de)

for (auto iterator = begin(container); iterator != end(container); ++iterator) {
    do_something_with(*iterator);
}

Ahora, a pesar de no agregar nueva sintaxis abstracta o semántica al lenguaje, tiene una utilidad real.

La primera versión hace explícita la intención (visitar cada elemento en un contenedor). También prohíbe comportamientos inusuales, como modificar el contenedor durante el recorrido, avanzar más iteratoren el cuerpo del bucle u obtener las condiciones del bucle sutilmente incorrectas. Esto evita posibles fuentes de errores y, al hacerlo, reduce la dificultad de leer y razonar sobre el código.

Por ejemplo, un error de un carácter en la segunda versión:

for (auto iterator = begin(container); iterator <= end(container); ++iterator) {
    do_something_with(*iterator);
}

da un error de un pasado y un comportamiento indefinido.

Entonces, la versión azucarada es útil precisamente porque es más restrictiva y, por lo tanto, más fácil de confiar y comprender.


Segundo, a la pregunta original:

¿Existe una diferencia real entre Syntax y Syntactic Sugar?

No, "azúcar sintáctico" es una sintaxis (concreta) del lenguaje, considerada "azúcar" porque no extiende la sintaxis abstracta o la funcionalidad central del lenguaje. Me gusta la respuesta de Matt Fenwick sobre esto.

¿A quién le importa?

Es importante para los usuarios del lenguaje, tanto como cualquier otra sintaxis, y en ese sentido se proporciona azúcar para apoyar (y en cierto sentido bendecir) modismos específicos.

Finalmente, sobre la pregunta de bonificación

La notación [] facilita esta abstracción.

Esto se parece mucho a la definición de azúcar sintáctico: admite (y proporciona la bendición de los autores del lenguaje) el uso de punteros como matrices. La p[i]forma no es realmente más restrictiva que *(p+i), por lo que la única diferencia es la comunicación clara de la intención (y una ligera ganancia de legibilidad).

Inútil
fuente
Primero dice "[el rango basado en el bucle] es exactamente equivalente a (es decir, una versión azucarada de) [alguna otra cosa]". Pero luego dice que es diferente, ya que prohíbe modificar el contenedor durante el recorrido ... y hay otras diferencias que lo hacen más que la simple transformación sintáctica que describió (por ejemplo, el comportamiento cuando el "contenedor" es temporal). Estas diferencias implican que no se trata solo de azúcar sintáctico, ¿verdad? Entonces, me parece que este no es un buen ejemplo de azúcar sintáctica.
Don Hatch
No dije que fuera equivalente a un ciclo general , dije que era equivalente al ciclo específico dado. El bucle específico no modifica el contenedor y representa un modismo muy común, pero aún necesita leer cada bucle general cuidadosamente para saber si está siguiendo ese modismo común o si algo inusual está al acecho en el cuerpo del bucle. El nuevo bucle es el azúcar para ese idioma común , siendo menos detallado y comunicando más claramente el idioma en uso. No es, y nunca dije que fuera, de alguna manera azúcar para la idea general de un bucle.
Inútil
0

Cualquiera que sea la connotación original de la frase, hoy en día es principalmente un peyorativo, casi siempre expresado como azúcar sintáctico "solo" o "solo". Prácticamente solo es importante para los programadores a quienes les gusta hacer las cosas de forma ilegible y quieren una forma concisa de justificar eso ante sus colegas. Una definición de aquellos que usan principalmente el término hoy, desde su punto de vista, sería algo así como:

Sintaxis que es redundante con otra sintaxis más ampliamente aplicable, con el fin de proporcionar una muleta para los programadores que realmente no entienden el lenguaje.

Es por eso que obtienes dos conclusiones opuestas para el mismo elemento sintáctico. Su primer ejemplo en notación de matriz es usar el significado positivo original del término, algo similar a la respuesta de Bart. Su segundo ejemplo es defender la notación de matriz contra la acusación de ser azúcar sintáctica en sentido peyorativo. En otras palabras, argumenta que la sintaxis es una abstracción útil más que una muleta.

Karl Bielefeldt
fuente
Creo que el significado peyorativo del término ("es solo azúcar sintáctico") proviene del hecho de que el azúcar sintáctico no agrega ninguna información.
Giorgio
1
Podría surgir de la idea de que la sintaxis no agrega ninguna información , pero esa idea no es un hecho. La información sobre la intención (por ejemplo, usar un idioma conocido) sigue siendo información.
Inútil
@ Inútil: por información quise decir que un programa se comporta igual con o sin azúcar sintáctico. Por supuesto, puede ser más legible con azúcar sintáctico (agrega información / documentación para el lector), lo cual es una ventaja.
Giorgio
Falso. El azúcar sintáctico no es peyorativo. Cualquier programador que valga la pena creará bibliotecas que encapsulan y simplifican tareas más complejas, en lugar de copiar y pegar el mismo código en todo el lugar. Esto conduce a un código de mejor comportamiento y más fácil de mantener. Esto es esencialmente lo que el azúcar sintáctico logra al abstraer patrones comunes, aunque complejos, en una sintaxis más simple.
Craig
Estoy diciendo que las personas generalmente se refieren al término como un insulto, no estoy comentando sobre la práctica subyacente en sí. Decir que la palabra "idiota" es un deleite no implica que todas las personas sean idiotas. Cuando las personas quieren hablar sobre la práctica de manera positiva, generalmente usan términos como "abstracción" o "encapsulación".
Karl Bielefeldt