Qual é a diferença entre "sintaxe" e "açúcar sintático"

45

fundo

A página da Wikipedia no Syntactic Sugar afirma:

Na ciência da computação, o açúcar sintático é uma sintaxe dentro de uma linguagem de programação projetada para facilitar a leitura ou a expressão. Torna a linguagem "mais doce" para os humanos usarem: as coisas podem ser expressas de forma mais clara, concisa ou em um estilo alternativo que alguns preferem.

Eu realmente não entendo qual a diferença entre o Syntactic Sugar e o Syntax.

Aprecio o argumento de que a versão açucarada pode ser mais clara, mais concisa, talvez se refira a alguns clichês. Mas, em algum nível, sinto que toda a sintaxe está fazendo isso para formar uma abstração sobre o que o código é compilado.

Da mesma página da Wikipedia:

Processadores de linguagem, incluindo compiladores, analisadores estáticos e similares, geralmente expandem construções açucaradas em construções mais fundamentais antes do processamento, um processo às vezes chamado de "dessugar".

Como exercício de pensamento, se eu entendi "frequentemente" nesta declaração como "sempre": se a diferença fosse apenas se o compilador "dessugera" a sintaxe antes de passar para o próximo estágio, como pode um codificador que não conhece as entranhas do compilador sabe (ou se importa) o que é Sugar'd Syntax ou não?

Uma pergunta muito relacionada neste site "Definição rigorosa de açúcar sintático?" tem uma resposta que começa:

IMHO Acho que você não pode definir o açúcar sintático, porque a frase é BS e provavelmente será usada por pessoas que falam sobre "programadores reais" usando "ferramentas reais" em "sistemas operacionais reais"

O que pode indicar para mim que talvez não haja uma grande diferença para o codificador que usa a linguagem? Talvez a diferença seja perceptível apenas para o escritor do compilador? Embora possa haver casos em que é útil para o codificador usar a linguagem saber o que está por trás do Syntactic Sugar? (Mas talvez, na realidade, qualquer discurso sobre o assunto tenda a usar o termo como isca de chama?)

O cerne da questão

Então ... a versão curta da pergunta:

  • Existe uma diferença real entre a sintaxe e o açúcar sintático?
  • Para quem isso importa?

Alimento Extra para Pensamento

Bônus por contradição de tópico:

Na página da Wikipedia, é dado um exemplo:

Por exemplo, na linguagem C, a a[i]notação é açúcar sintático para*(a + i)

Enquanto outra resposta à pergunta vinculada acima menciona o mesmo exemplo:

Agora considere a[i] == *(a + i). Pense em qualquer programa C que use matrizes de maneira substantiva.

E resume que:

A []notação facilita essa abstração. Não é açúcar sintático.

A conclusão oposta para o mesmo exemplo!

Don Vince
fonte
9
Na minha resposta à pergunta citada, explico que o açúcar sintático é uma sintaxe alternativa (para alguma sintaxe que já existe na linguagem) que facilita a expressão de alguns idiomas comuns, mas não introduz novas semânticas. Nesse sentido, o açúcar sintático depende do contexto (do idioma em que é usado): a mesma notação pode ser sintaxe normal em um idioma e açúcar sintático em outro idioma. Esta explicação ajuda você?
Giorgio
7
Um problema é que algumas pessoas parecem pensar que "açúcar sintático" é uma palavra suja, quando não é. Cada função ou classe que você adiciona a um sistema pode ser considerada "açúcar sintático", pois torna as idéias que já eram claramente expressáveis ​​na linguagem um pouco (ou muito) mais fáceis de expressar.
Joris Timmermans
Aparentemente, isso é importante para você.
SShaheen
11
No final, tudo é apenas açúcar sintático sobre eletricidade.
Anthony Pegram

Respostas:

34

A principal diferença é que a sintaxe é a gramática definida em um idioma para permitir que você exponha alguma funcionalidade. Assim que você pode acessar essa funcionalidade, qualquer outra sintaxe que permita fazer a mesma coisa é considerada açúcar. É claro que isso ocorre em cenários estranhos sobre qual das duas sintaxes é o açúcar, especialmente porque nem sempre é claro o que ocorreu primeiro.

Na prática, o açúcar sintático é usado apenas para descrever a sintaxe adicionada a um idioma para facilitar a facilidade de uso, como fazer o lhs + rhsmapeamento de infixos para lhs.Add(rhs). Eu consideraria a indexação de array de C um açúcar sintático.

É importante principalmente porque os designs elegantes tendem a limitar a quantidade de duplicação. A necessidade (ou pelo menos a falta) de açúcar sintático é vista por alguns como um sinal de falha no design.

Telastyn
fonte
"Assim que você pode acessar essa funcionalidade, qualquer outra sintaxe que permita fazer a mesma coisa é considerada açúcar.": Isso não é suficiente para obter açúcar sintático, porque qualquer outro programa que calcule a mesma função seria açúcar sintático . O programa com e sem açúcar deve ter a mesma semântica .
Giorgio
3
@Giorgio Como é que "esses dois programas calculam a mesma função" diferente de "esses dois programas têm a mesma semântica"? Além disso, você está focando em programas, não em elementos sintáticos. Programas inteiros não podem ser açúcar sintático. Um operador, um tipo de afirmação etc. pode ser um açúcar sintático.
@Giorgio - Na verdade, estou considerando uma funcionalidade semelhante com semântica diferente para ser uma funcionalidade diferente. E sim, pode haver muita confusão como escrever seu próprio compilador que tenha a mesma semântica e chamar isso de "açúcar". Francamente, uma definição formal não vai acontecer para um conceito tão informal.
Telastyn
1
@Giorgio Novamente, minha carne não é com a sua opinião sobre equivalência, mas com a tentativa de aplicar o conceito de açúcar sintático aos programas. O termo não se refere a programas inteiros! Dependendo da sua definição, são apenas blocos de construção atômicos ou apenas pequenos fragmentos de programa (o primeiro parece cobrir> 80%, mas não tenho certeza de que ele cobre tudo o que é comumente considerado açúcar sintático).
3
@Giorgio Por exemplo, programas inteiros ;-) Ou qualquer coisa grande o suficiente para que ambas as formulações envolvam várias palavras-chave de linguagem não relacionadas. Algo que eu nunca fui tratado como açúcar sintático é if (a) return blah; ...contra result_type res; if (a) res = blah; else {...}; return res;. Você precisaria assumir idiomas específicos e obter um advogado especializado em idiomas (muitas vezes ao ponto da semântica operacional em pequenos passos), para encontrar qualquer diferença entre esses programas.
10

Sintaxe é o que um processador de linguagem usa para entender o que significam as construções de uma linguagem. Construções que são consideradas açúcar sintático também precisam ser interpretadas pelo processador de idiomas e, portanto, fazem parte de uma sintaxe de idiomas.

Que o que diferencia o açúcar sintático do restante da sintaxe de um idioma é que seria possível remover o açúcar sintático do idioma sem afetar os programas que podem ser escritos no idioma.

Para dar uma definição mais formalista, eu diria

Açúcar sintático são aquelas partes da sintaxe de uma linguagem cujos efeitos são definidos em termos de outras construções de sintaxe na linguagem.

Isso não significa, de maneira alguma, denegrir o açúcar sintático, ou os idiomas que o contêm, porque o uso de açúcar sintático geralmente leva a programas cuja intenção é mais compreensível.

Bart van Ingen Schenau
fonte
"Não há como dizer definitivamente 'isso é açúcar sintático e isso é sintaxe', porque o açúcar sintático faz parte da sintaxe de um idioma.": Falso. É o designer da linguagem que introduz alguma sintaxe como açúcar sintático para alguma construção que já está na linguagem e tem uma sintaxe. O açúcar sintático é normalmente ad-hoc (menos geral), mas mais legível / conveniente de usar.
Giorgio
@Giorgio: Eu reformulei meu primeiro parágrafo, pois era um pouco estranho. Mas não concordo que o açúcar sintático seja normalmente adicionado ad-hoc. O pedaço de açúcar sintático mais conhecido é provavelmente o ->operador de C e não vejo como esse operador é menos geral do que qualquer outro.
Bart van Ingen Schenau
1
@Giorgio: Nesse caso, tudo o que não mapeia diretamente para uma única instrução de montagem deve ser considerado como açúcar sintático, porque sempre pode ser dividido em partes mais simples (isso inclui funções). Acho que você não encontrará muitas pessoas compartilhando essa opinião.
Bart van Ingen Schenau
1
"Ad-hoc" significa que é usado em uma situação restrita especial. O termo não tem uma conotação negativa em geral. O termo solução ad-hoc tem uma conotação negativa, porque normalmente se deseja soluções gerais, e não particulares (para evitar a solução de problemas semelhantes repetidamente).
Giorgio
1
Como as "soluções ad-hoc" geralmente são ruins, pode parecer que "ad-hoc" seja ruim. Mas também existe a sobrecarga da função AKA "polimorfismo ad-hoc" ( en.wikipedia.org/wiki/Ad_hoc_polymorphism ), o que não é ruim. Pelo menos em italiano (minha língua materna), o uso do latim "ad-hoc" não é negativo em si. Se tem uma conotação negativa em inglês, perdoe minha ignorância.
Giorgio
6

As outras respostas não mencionaram um conceito-chave: sintaxe abstrata ; sem ele, o termo "açúcar sintático" não faz sentido.

A sintaxe abstrata define os elementos e a estrutura dos idiomas e como as frases desse idioma podem ser combinadas para criar frases maiores. A sintaxe abstrata é independente da sintaxe concreta. O termo "açúcar sintático", como eu o entendo, refere-se a sintaxe concreta.

Em geral, ao projetar uma linguagem, você deseja criar uma sintaxe concreta para cada termo da sua sintaxe abstrata, para que as pessoas possam escrever código no seu idioma usando texto simples.

Agora, digamos que você crie uma sintaxe concreta estranha para foo . Os usuários reclamam e você implementa uma nova sintaxe concreta para representar a mesma sintaxe abstrata . O resultado é que sua sintaxe e semântica abstratas não foram alteradas, mas agora você tem duas sintaxes concretas para o mesmo termo de sintaxe abstrata.

Creio que é isso que as pessoas querem dizer quando dizem "açúcar sintático" - mudanças que afetam apenas a sintaxe concreta, mas que não afetam a sintaxe abstrata ou a semântica.

E assim a diferença entre "açúcar sintático" e "sintaxe concreta" agora está clara. Para mim. :)

Essa interpretação também ajuda a explicar o que Alan Perlis poderia ter significado quando disse que "o açúcar sintático causa câncer de ponto e vírgula": todo o açúcar sintático concreto do mundo não pode consertar uma sintaxe abstrata fraca e todo o esforço que você gasta adicionando esse açúcar é necessário. esforço que você não está gastando para lidar com o problema real - a sintaxe abstrata.


Devo também observar que esta é apenas minha opinião; Só acredito porque é a única interpretação que consigo pensar que faz sentido para mim.


fonte
1
Eu também tinha pensado na comparação abstrata versus sintaxe concreta, mas não tenho certeza de que isso sempre explique o açúcar sintático. Por exemplo, em C, dado um ponteiro ppara uma estrutura que contém um campo x, as expressões (*p).xe p->xtêm a mesma sintaxe abstrata? Mas acho que seria ótimo se tudo se resumisse à sintaxe abstrata versus sintaxe concreta.
Giorgio
@Giorgio, infelizmente, não sei C o suficiente para afirmar com segurança se um deles é açúcar sintático para o outro ou como seriam suas árvores de sintaxe abstrata. Ou mesmo se a especificação de C realmente definir uma sintaxe abstrata. :(
1
A primeira expressão pode ser analisada como uma árvore com a .na raiz. O subnó esquerdo da raiz é a *e seu filho é p. O subnó certo da raiz é x. Para a segunda expressão, a árvore de sintaxe abstrata tem a ->na raiz e a raiz tem dois filhos pe x. Estou tentando descobrir se faz sentido analisar as duas expressões de maneira diferente para que elas tenham a mesma árvore de sintaxe abstrata, mas não vejo como no momento.
Giorgio
3
Eu não acho que essa árvore de análise, mesmo que frequentemente seja descrita como AST, seja a mesma que a sintaxe abstrata de que Matt está falando. Ambas as expressões têm a ação idêntica ( ponteiro tipo convertido ao tipo de referência, então, fazer referência ao membrox )
Useless
1
"Ambas as expressões têm a ação idêntica (converter o tipo de ponteiro em tipo de referência e obter referência ao membro x)": Esta é a semântica, não a sintaxe abstrata. Sintaxe abstrata refere-se a deixar de fora detalhes inúteis da sintaxe concreta (como (ou ;) para produzir uma árvore que reflete a estrutura real de um programa (consulte en.wikipedia.org/wiki/Abstract_syntax_tree ). No entanto, na sintaxe abstrata, nada é dito (ainda) sobre a semântica do programa.
Giorgio
4

O açúcar sintático é um subconjunto da sintaxe de idiomas. A idéia básica é que há mais de uma maneira de dizer a mesma coisa.

O que torna difícil dizer quais peças são açúcar sintático e quais são "sintaxe pura" são declarações como "é difícil dizer qual forma veio primeiro" ou "é difícil saber para que lado o autor da linguagem pretendia" ou "é um tanto arbitrário decidir qual forma é mais simples ".

O que facilita a decisão de quais peças são puras ou açucaradas é fazer a pergunta no quadro de um compilador ou intérprete específico. A sintaxe pura é o material que um compilador converte diretamente em código de máquina ou ao qual o intérprete responde diretamente. O açúcar é o material que primeiro se transforma em outro material de sintaxe antes que essas coisas diretas aconteçam. Dependendo da implementação, isso pode ou não ser o mesmo que o autor pretendia ou mesmo o que a especificação de idioma afirma.

Na prática, é assim que a realidade da questão é decidida.

Jeff Wolski
fonte
Essa resposta conecta incorretamente a implementação da sintaxe, seja ela açúcar ou não. Eu nunca vi argumentos = sobre se um elemento de uma linguagem é "açúcar" ou não, que se preocupa com a maneira como o elemento é implementado. Trata-se apenas de duplicar um elemento diferente, mais feio, sintaticamente.
GreenAsJade
3

Realmente, sua primeira citação da Wikipedia diz tudo "... torna as coisas mais fáceis de ler ...", ".... mais doce para os humanos usarem ...".

Por escrito, formas abreviadas como "não" ou "não" podem ser consideradas açúcar sintático.

ozz
fonte
Considere (1) "eu devo ir agora" versus (2) "eu devo ir agora": (1) é açúcar sintático para (2)?
Giorgio
1
@Giorgio eu diria que não.
ozz
Por causa da legibilidade ("deveria" não é mais legível do que "deveria") ou por causa do significado ("deveria" e "deveria" ter significados diferentes).
Giorgio
@Giorgio fair enough :)
ozz
1
Ah eu vejo :) mais de um instinto eu acho, eu não acho que um é mais legível do que o outro nesse exemplo
ozz
3

Normalmente, o açúcar da sintaxe é a parte da linguagem que pode ser expressa pela parte existente da linguagem (sintaxe) sem perda de generalidade, mas com possível perda de clareza. Às vezes, os compiladores têm uma etapa de remoção de açúcar explícita, que transforma o AST criado pelo código-fonte e aplica etapas simples para remover os nós correspondentes ao açúcar.

Por exemplo, Haskell possui açúcar de sintaxe para mônadas, com as seguintes regras 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

No momento, não importa exatamente o que isso significa - no entanto, você pode ver que uma sintaxe especial no LHS pode ser transformada em algo mais básico no RHS (ou seja, aplicativos de função, lambdas e let's). Essas etapas permitem manter o melhor dos dois mundos:

  1. A sintaxe no LHS é mais fácil para o programador (açúcar de sintaxe) expressar as idéias existentes de maneira mais clara
  2. No entanto, como o suporte no compilador para construções RHS já existe no compilador, ele não precisa tratá-lo como algo especial fora do analisador e dessugar (exceto para o relatório de erros).

Da mesma forma, em C, você pode imaginar uma regra de reescrita desagradável (devido à sobrecarga do operador etc., não é verdade para C ++):

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

Você pode imaginar escrever todos os programas sem usar ->ou []em C que usam essa construção hoje. No entanto, seria mais difícil para os programadores usá-lo, portanto fornecia açúcar de sintaxe (acho que nos anos 70 também poderia simplificar o trabalho para compiladores). É possivelmente menos claro, pois você pode adicionar tecnicamente a seguinte regra de reescrita perfeitamente válida:

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

O açúcar da sintaxe é ruim? Não necessariamente - existe o perigo de que seja usado como culto à carga sem entender um significado mais profundo. Por exemplo, as seguintes funções são equivalentes no Haskell, mas muitos iniciantes escrevem a primeira forma sem entender que estão usando demais o açúcar da sintaxe:

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

Além disso, o açúcar da sintaxe pode complicar demais o idioma ou ser muito estreito para permitir código idiomático generalizado. Também pode significar que a linguagem não é poderosa o suficiente para fazer certas coisas facilmente - pode ser por design (não ofereça aos desenvolvedores ferramentas precisas ou linguagem de nicho muito específica que a adição de uma construção mais poderosa prejudique outros objetivos) ou por omissão - a última O formulário deu o nome errado ao açúcar da sintaxe. Se a linguagem é poderosa o suficiente para usar outras construções sem adicionar açúcar de sintaxe, é considerado mais elegante usá-las.

Maciej Piechotka
fonte
3

Eu acho que o exemplo mais óbvio seria a sintaxe "+ =" em C.

i = i + 1;

e

 i +=  1;

faça exatamente a mesma coisa e compile exatamente o mesmo conjunto de instruções da máquina. O segundo formulário salva alguns caracteres digitando, mas, mais importante, deixa muito claro que você está modificando um valor com base no valor atual.

Eu citaria o operador de postagem / prefixo "++" como exemplo canônico, mas percebi que isso era mais do que açúcar sintático. Não há como expressar a diferença entre ++ ie i ++ em uma única expressão usando a i = i + 1sintaxe.

James Anderson
fonte
+ = pode ser útil em casos como a[f(x)] += 1.
Florian F
1

Primeiro, abordarei algumas das outras respostas com um exemplo concreto. O loop for C ++ 11 baseado em intervalo (bem como loops foreach em várias outras linguagens)

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

é exatamente equivalente a (ou seja, uma versão açucarada de)

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

Agora, apesar de não adicionar nenhuma nova sintaxe ou semântica abstrata ao idioma, ele tem utilidade real.

A primeira versão torna explícita a intenção (visitando todos os itens de um contêiner). Ele também proíbe comportamentos incomuns, como modificar o contêiner durante a travessia, avançar ainda mais iteratorno corpo do loop ou obter as condições do loop sutilmente erradas. Isso evita possíveis fontes de erros e, ao fazer isso, reduz a dificuldade de ler e raciocinar sobre o código.

Por exemplo, um erro de um caractere na segunda versão:

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

fornece um erro do passado-final e comportamento indefinido.

Portanto, a versão açucarada é útil precisamente porque é mais restritiva e, portanto, mais simples de confiar e entender.


Segundo, para a pergunta original:

Existe uma diferença real entre a sintaxe e o açúcar sintático?

Não, "açúcar sintático" é uma sintaxe da linguagem (concreta), considerada "açúcar" porque não estende a sintaxe abstrata ou a funcionalidade principal da linguagem. Eu gosto da resposta de Matt Fenwick sobre isso.

Para quem isso importa?

É importante para os usuários do idioma, tanto quanto qualquer outra sintaxe, e nesse açúcar é fornecido para suportar (e de alguma forma abençoar) idiomas específicos.

Finalmente, na questão do bônus

A notação [] facilita essa abstração.

isso se parece muito com a definição de açúcar sintático: suporta (e fornece a bênção dos autores do idioma) usar ponteiros como matrizes. O p[i]formulário não é realmente mais restritivo do que *(p+i), portanto, a única diferença é a comunicação clara da intenção (e um leve ganho de legibilidade).

Sem utilidade
fonte
Primeiro você diz "[o intervalo baseado no loop] é exatamente equivalente a (ou seja, uma versão com açúcar de) [alguma outra coisa]". Mas então você diz que é diferente, pois proíbe modificar o contêiner durante a travessia ... e há outras diferenças que o tornam mais do que apenas a simples transformação sintática que você descreveu (por exemplo, comportamento quando "contêiner" é temporário). Estas diferenças implicam que é não apenas açúcar sintático, certo? Parece-me que talvez este não seja um bom exemplo de açúcar sintático.
Don Hatch
Eu não disse que era equivalente a algum loop geral , eu disse que era equivalente ao loop específico fornecido. O loop específico não modifica o contêiner e representa um idioma muito comum - mas você ainda precisa ler cada loop geral com atenção para saber se está seguindo esse idioma comum ou se algo incomum está oculto no corpo do loop. O loop mais recente é o açúcar para esse idioma comum , sendo menos detalhado e comunicando mais claramente o idioma em uso. Não é, e eu nunca afirmei que fosse, de alguma forma, açúcar para a idéia geral de um loop.
Inutil)
0

Qualquer que fosse a conotação original da frase, hoje em dia é principalmente pejorativa, quase sempre formulada como "apenas" ou "apenas" açúcar sintático. É importante apenas para programadores que gostam de fazer as coisas da maneira ilegível e desejam uma maneira concisa de justificar isso para seus colegas. Uma definição daqueles que usam principalmente o termo hoje, do ponto de vista deles, seria algo como:

Sintaxe redundante com outra sintaxe mais amplamente aplicável, a fim de fornecer uma muleta para programadores que realmente não entendem o idioma.

É por isso que você obtém duas conclusões opostas para o mesmo elemento sintático. Seu primeiro exemplo de notação de matriz é usar o significado positivo original do termo, algo semelhante à resposta de Bart. Seu segundo exemplo é defender a notação de matriz contra a acusação de ser açúcar sintático no sentido pejorativo. Em outras palavras, ele argumenta que a sintaxe é uma abstração útil e não uma muleta.

Karl Bielefeldt
fonte
Eu acho que o significado pejorativo do termo ("é apenas açúcar sintático") vem do fato de que o açúcar sintático não adiciona nenhuma informação.
Giorgio
1
Pode vir da ideia de que a sintática não adiciona nenhuma informação , mas essa ideia não é um fato. Informações sobre intenção (por exemplo, para usar um idioma conhecido) ainda são informações.
Inutil)
@ Useless: Por informações, eu quis dizer que um programa se comporta da mesma forma com ou sem açúcar sintático. É claro que pode ser mais legível com o açúcar sintático (adiciona informações / documentação para o leitor), o que é uma vantagem.
Giorgio
Falso. O açúcar sintático não é pejorativo. Qualquer programador que se preze criará bibliotecas que encapsulam e simplificam tarefas mais complexas, em vez de copiar e colar o mesmo código em todo o lugar. Isso leva a um código mais comportável e mais sustentável. Isso é essencialmente o que o açúcar sintático realiza abstraindo padrões comuns, embora complexos, em uma sintaxe mais simples.
22413 Craig
Estou dizendo que as pessoas geralmente querem dizer o termo como um insulto, não estou comentando a própria prática subjacente. Dizer que a palavra "idiota" é uma constante não implica que todas as pessoas sejam idiotas. Quando as pessoas querem falar sobre a prática de maneira positiva, geralmente usam termos como "abstração" ou "encapsulamento".
Karl Bielefeldt