Melhor resposta
O açúcar sintático, ou açúcar sintático, é um “atalho” visualmente ou logicamente atraente fornecido pela linguagem, que reduz a quantidade de código que deve ser escrito em alguma situação comum.
Por exemplo, ao definir uma variável para um valor que é dependente de uma condição, em uma linguagem mais simples com menos “açúcar”, você pode fazer isto:
int a;
if(SomeFunction() == 2)
a = 4;
else
a = 9;
Isso é um pouco demais para uma operação tão simples; em linguagens mais simples, os desenvolvedores geralmente criavam uma função “Inline If” para envolver essa lógica em algo mais conciso:
public T Iif
{
if(condition) return ifTrue;
return ifFalse;
}
...
//usage
int a = Iif(SomeFunction() == 2, 4, 9);
Agora, o uso real é muito mais conciso. Muitas linguagens modernas, incluindo C #, incorporam uma operação como essa diretamente na especificação da linguagem na forma de “operador condicional ternário”:
int a = SomeFunction() == 2 ? 4 : 9;
Este operador é um “açúcar de sintaxe” fornecido pela linguagem para uma operação condicional.
Agora, um sub-caso comum dessa configuração de variável condicional é que, se nossa primeira escolha para um meio de produzir um valor para definir como a variável avalia como nula, devemos usar um meio alternativo. Por exemplo:
MyClass theClass = GetMyClass();
if(theClass == null)
theClass = FailSafeMyClassGetter();
Nada mal, mas podemos melhorar isso:
MyClass theClass = GetMyClass() ?? FailSafeMyClassGetter();
O “??” O operador é conhecido como o “operador de coalescência nula” e basicamente produz o primeiro valor lido da esquerda para a direita que não é nulo.
Outro C # obteve recentemente foi a “propriedade automática”. De forma sucinta, C # tem o que se chama de “propriedades”; pares de blocos de código que representam um “membro de dados” de um objeto, que podem realizar validação mais complexa ou lógica de cálculo do que um campo simples, mas que podem ser acessados como se o membro fosse um campo em vez de usar GetX () e SetX () chamadas de método, de modo que se torna fácil diferenciar no código quando você “está acessando dados e executando operações. É prática recomendada em C #, por razões de consistência e manutenção, usar propriedades em vez de campos ao implementar membros de dados visíveis ao público . No entanto, nove em cada dez vezes, a propriedade “está apenas” envolvendo “uma variável de campo privada e, portanto, seguindo a prática recomendada, a implementação da propriedade para um valor de dados simples pode ser semelhante a:
private int \_myIntProperty;
public int MyIntProperty
{
get
{
return \_myIntProperty;
}
set
{
\_myIntProperty = value;
}
}
Meio feio, muito repetitivo e com muito mais linhas de código do que realmente precisamos. No passado, era tentador renunciar prática recomendada e apenas usar um campo nesses casos simples, para reduzir essa tentação e o efeito prejudicial que ela pode ter na base de código se mais tarde você decidiu que realmente precisava de uma propriedade, os designers do C # incluíram algum açúcar de sintaxe no C # 3.0 especificação:
public int MyIntProperty { get; set; }
Esta declaração de propriedade é tratada como sendo a mesma que a declaração acima, mas é muito mais rápido e fácil de escrever um classe cheia disso do que fazer da maneira antiga, e é muito mais fácil de manter também.
Esses são apenas alguns exemplos de “sintaxe de açúcar” disponível em C #. Outros incluem:
* Inferência de tipo de variável – var someInt = 5;
– O compilador pode determinar o tipo de uma variável local declarada a partir da atribuição inicial, então você não precisa para especificá-lo explicitamente (e, em seguida, alterá-lo se o tipo de que você precisa mudar).
* yield return
– Grande parte da programação .NET envolve coleções de objetos, e fazer tarefas repetitivas em cada elemento do mesmo. Costumava ser um processo bastante complicado implementar a interface IEnumerable
que permite vários loops integrados como foreach
para funcionar, exigindo uma segunda classe inteira que implementou IEnumerator
para lidar com a iteração na coleção. A palavra-chave yield return
simplificou isso drasticamente, permitindo que a própria lógica do iterador seja definida no método GetEnumerator () da própria coleção.
* async
/ await
– Da mesma forma, mais e mais tarefas de programação devem ser executadas “de forma assíncrona”, fornecendo o trabalhar para outro “thread” do aplicativo, para que o trabalho do programa possa ser dividido entre os vários processadores no PC moderno, enquanto a interface do usuário do aplicativo permanece “responsiva” às solicitações do sistema operacional para redesenhar a IU e executar outras tarefas visuais. O conceito de threading não é difícil de entender, mas até o C # 4.0 ele basicamente exigia dividir seu método em dois; um método inicia a operação assíncrona e, em seguida, um segundo é chamado quando o thread de segundo plano termina o trabalho. Não mais; essas duas novas palavras-chave permitem que uma função que faz trabalho assíncrono seja definida de uma maneira muito síncrona, enquanto o compilador faz a divisão do método nos bastidores ao construir o código.
Resposta
Não há uma definição formal de açúcar sintático, esta é uma noção nebulosa.
O açúcar sintático em sua definição mais aceita é uma sintaxe extra que é imediatamente traduzida para uma forma mais primitiva e complicada pelo compilador, mas permite uma experiência “mais doce” para o programador ao expressar certas instruções comuns.
O problema com esta definição é que a sintaxe “extra” não é uma descrição muito significativa. Em certos casos, é bastante claro que temos açúcar sintático, por exemplo, o relatório da linguagem Haskell define explicitamente certos elementos sintáticos (blocos do e compreensões de lista) por sua tradução em uma sintaxe mais simples. Este é um caso bem definido de açúcar sintático, eles existem apenas para facilitar a escrita de um programa, não em um sentido profundo na tradução do compilador do programa para uma árvore simbólica.
Em outros casos, é muito menos claro porque a linguagem não se preocupa com esse tipo de formalização, por exemplo, decoradores em Python são frequentemente descritos por como você escreveria o código equivalente sem eles, mas, pelo que eu sei, nunca é dito explicitamente: “você não deve compilar decoradores diretamente em sua representação intermediária, mas antes traduzi-los desta maneira ”. Algumas implementações de Python podem escolher fazer exatamente isso, mas outras podem ter adicionado decoradores como um recurso de sua representação intermediária.