Linguagens como C, Java e C ++ requerem parêntese em torno de uma expressão inteira quando usado em um if
, while
ou switch
.
if (true) {
// Do something
}
em oposição a
if true {
// Do something
}
Isso me parece estranho, porque os parênteses são redundantes. Neste exemplo, true
é uma expressão única por si só. Os parênteses não transformam seu significado de nenhuma maneira que eu saiba. Por que essa sintaxe ímpar existe e por que é tão comum? Existe um benefício que eu não conheço?
THEN
).if
declaração, eles apenas criam uma declaração composta.Respostas:
É preciso haver uma maneira de dizer onde a condição termina e o ramo começa. Existem muitas maneiras diferentes de fazer isso.
Em algumas línguas, não há condicionais em tudo , por exemplo, em Smalltalk, Auto, Novilíngua, Io, Ioke, Seph e Fancy. A ramificação condicional é simplesmente implementada como um método normal, como qualquer outro método. O método é implementado em objetos booleanos e é chamado em um booleano. Dessa forma, a condição é simplesmente o receptor do método, e os dois ramos são dois argumentos, por exemplo, em Smalltalk:
Caso você esteja mais familiarizado com Java, isso é equivalente ao seguinte:
Na família de linguagens Lisp, a situação é semelhante: condicionais são apenas funções normais (na verdade, macros) e o primeiro argumento é a condição, o segundo e o terceiro argumentos são os ramos, portanto, são apenas argumentos de funções normais, e há nada de especial é necessário para delimitá-los:
Alguns idiomas usam palavras-chave como delimitadores, por exemplo, Algol, Ada, BASIC, Pascal, Modula-2, Oberon, Oberon-2, Oberon ativo, Componente Pascal, Zonnon, Modula-3:
No Ruby, você pode usar uma palavra-chave ou um separador de expressões (ponto-e-vírgula ou nova linha):
O Go requer que as ramificações sejam blocos e não permite expressões ou declarações, o que torna obrigatórias as chaves. Portanto, parênteses não são necessários, embora você possa adicioná-los, se quiser; Perl6 e Rust são semelhantes a este respeito:
Algumas linguagens usam outros caracteres não alfanuméricos para delimitar a condição, por exemplo, Python:
A linha inferior é: você precisa de alguma maneira de dizer onde a condição termina e o ramo começa. Existem muitas maneiras de fazê-lo, os parênteses são apenas uma delas.
fonte
Os parênteses são desnecessários apenas se você usar chaves.
Por exemplo, torna-se ambíguo sem eles.
fonte
if
: básico, montagem, python, bash / zsh, tcl, lote, foda-cérebro ou código de máquina. A falta de parênteses torna-if
se ambígua se o idioma foi projetado para depender deles.if Condition then ...
.{}
obrigatório e, portanto, não requer parênteses em torno da expressão. Não só é parens não é obrigatório, mas se eu me lembro acrescentando corretamente parens causaria um erro de compilação - eles estão proibidosParênteses em uma
if
instrução não têm o mesmo significado que os parênteses usados em uma expressão aritmética. Parênteses em uma expressão aritmética são usados para agrupar expressões. Parênteses em umaif
instrução são usados para delimitar a expressão booleana; isto é, para diferenciar a expressão booleana do restante daif
instrução.Em uma
if
instrução, parênteses não executam uma função de agrupamento (embora, dentro daif
instrução, você ainda possa usar parênteses para agrupar expressões aritméticas. O conjunto externo de parênteses serve para delimitar toda a expressão booleana). Torná-los necessários simplifica o compilador, já que o compilador pode confiar nesses parênteses sempre presentes.fonte
IF primary_expression statement
. Observe que o último é igualmente inequívoco.primary_expression
não pode ser distinguido de um operador prefixo em uma instrução de expressão. Para copiar a resposta de Telastynif true ++ x;
,. Além disso, se existirem instruções vazias,if a & f;
pode ser uma instrução vazia e binária&
dentro da condição ou unária&
no início da instrução. Mas, ao combinar parênteses, há exatamente uma correspondência para a abertura (IDENTIFIER
,CONSTANT
,STRING_LITERAL
e'(' expression ')'
.Como outros já apontaram parcialmente, isso se deve ao fato de que expressões também são instruções válidas e, no caso de um bloco com apenas uma instrução, você pode descartar chaves. Isso significa que o seguinte é ambíguo:
Porque pode ser interpretado como:
ao invés de:
Um número de idiomas (por exemplo, Python) permite evitar o parêntese, mas ainda possui um marcador de condição final:
No entanto, você está certo de que poderíamos definir um idioma em que os parênteses nunca sejam necessários: um idioma em que uma expressão não é uma declaração válida não terá esse problema.
Infelizmente, isso significa que coisas como:
seria não ser instruções válidas, então você teria que introduzir alguma sintaxe estranha para ser capaz de realizar tais ações sem criar expressões. Uma maneira simples de fazer isso é simplesmente acrescentar a expressão por um marcador como
[statement]
:Agora a ambiguidade desaparece, pois você teria que escrever:
Mas como você pode ver, não vejo essa linguagem difundida, pois colocar os parênteses em torno de uma
if
condição-(ou a:
no final) é muito melhor do que colocar um marcador para cada expressão.Nota : o uso de um
[statement]
marcador é apenas a sintaxe mais simples que eu poderia pensar. No entanto, você pode ter duas sintaxes completamente distintas para expressões e declarações sem ambiguidade entre elas, que não exigiriam esse marcador. O problema é: a linguagem seria extremamente estranha, pois, para fazer as mesmas coisas em uma expressão ou declaração, você teria que usar uma sintaxe completamente diferente.Uma coisa que vem à mente para ter duas sintaxes separados sem um marcador tão explícito seria, por exemplo: declarações de força para usar símbolos unicode (então ao invés de
for
você usar alguma variação unicode das letrasf
,o
er
), enquanto expressões para ser Somente ASCII.fonte
discard
seu valor em Nim . No entanto, isso é feito apenas para segurança do tipo, não por razões sintáticas.?
simbol, por exemplo, é uma função após o PP). Não existe;
. Claro, ele precisa de um marcador para a linha de continuação, mas isso é desencorajado. harbour.github.io/doc/clc53.html#if-cmd . O compilador é rápido e simples (criado com o Bison / Flex).if
,while
ECC são limitados em comparação com expressões genéricas usadas em outros idiomas. Claro: se você tiver mais de duas categorias sintáticas (como declaração, expressão, expressão lógica, expressão de café, ...), poderá trocar alguma liberdade.É comum que os idiomas da família C exijam esses parênteses, mas não universais.
Uma das mudanças sintáticas mais visíveis do Perl 6 é que eles modificaram a gramática de forma que você não tem que dar os parênteses ao redor
if
,for
e as condições de declarações semelhantes. Então, algo assim é perfeitamente válido no Perl 6:como é
No entanto, como são apenas expressões, você pode colocar parênteses em volta deles, se desejar. Nesse caso, são apenas agrupamentos comuns, em vez de uma parte necessária da sintaxe, como em C, C #, Java etc.
Rust possui sintaxe semelhante à Perl 6 neste departamento:
Parece-me que uma característica das linguagens mais modernas inspiradas em C é olhar para coisas assim e pensar em removê-las.
fonte
if
ou em loop com BLOCOS, os parâmetros são necessários, por exemplo, emif ( $x == 4 ) { ... }
ouforeach my $foo ( @bar ) { ... }
. Quando a notação postfix é usada, as parênteses são opcionais, como emreturn unless $foo;
ou++$x while s/foo/bar/g;
.Há um aspecto que me surpreende que nenhuma das respostas existentes tenha surgido.
C, e muitos derivados e similares C, têm uma peculiaridade em que o valor de uma atribuição é o valor atribuído. Uma conseqüência disso é que uma atribuição pode ser usada onde um valor é esperado.
Isso permite que você escreva coisas como
ou
ou
(que é implicitamente tratado como
while (n < m && *p1++ = *p2++ != 0) { n++; }
porque C trata diferente de zero como verdadeiro; aliás, acho que isso é apenas strncpy () na biblioteca padrão C)ou mesmo
e tudo é válido. Nem todas as combinações sintaticamente válidas são necessariamente úteis (e os compiladores modernos alertam especificamente sobre atribuições dentro de condicionais, porque é um erro comum), mas algumas delas são realmente úteis.
A análise de tais declarações provavelmente seria muito mais difícil se não houvesse uma maneira inequívoca de determinar onde a expressão condicional começa e termina.
Os parênteses já eram usados para delimitar nomes de funções dos argumentos das funções, então acho que eles pareciam uma escolha natural também para delimitar palavras-chave dos argumentos das palavras-chave.
Claro, sintaxes alternativas podem ser definidas para fazer a mesma coisa. Mas fazer isso aumentaria a complexidade, particularmente no analisador, que precisaria lidar com dois conjuntos diferentes de sintaxe para praticamente a mesma coisa. Quando C estava sendo projetado, o poder da computação (tanto em termos de capacidade de processamento de números, memória de trabalho e capacidade de armazenamento) era extremamente limitado; qualquer coisa que reduzisse a complexidade com pouco ou nenhum custo para facilitar a leitura era quase certamente uma mudança bem-vinda.
Atualmente, o uso de parênteses pode parecer um pouco arcaico, mas não é assim, dado que alguém com alguma familiaridade com o idioma prejudica a legibilidade em comparação com alguma outra sintaxe capaz de expressar as mesmas coisas.
fonte
O motivo é principalmente história.
No momento em que o primeiro compilador C foi escrito, os computadores tinham ram, cpu e compiladores muito limitados, onde eram escritos “manualmente” com poucas ferramentas para ajudar os escritores do compilador. Portanto , regras complexas eram caras para implementar em um compilador. C ++, C #, Java etc. foram todos projetados para facilitar a aprendizagem dos programadores em C, portanto , não foram feitas alterações "desnecessárias".
Em linguagens 'c', os condicionais (
if, while, etc
) não exigem umblock
código off explícito , você pode apenas usar uma declaração simples.ou você pode combinar instruções em uma
compound statement
colocando-as em{}
Gostamos do compilador para encontrar o erro que cometemos e enviar como uma mensagem de erro que possamos entender.
fonte
Java e C ++ foram desenvolvidos depois que o C se tornou uma linguagem de programação muito popular. Uma consideração no design de cada uma dessas linguagens era que ela atrairia os programadores em C e atrairia esses programadores a usar a nova linguagem. (Eu era um dos programadores em C que eles conquistaram com sucesso.) O C ++ foi projetado para ser (quase) intercambiável com o código C. A fim de apoiar estes objetivos, tanto C ++ e Java, adotado muito da sintaxe do C, incluindo os parênteses em torno das condições de
if
,while
eswitch
declarações.Portanto, a razão pela qual todas essas linguagens exigem parênteses em torno das condições dessas declarações é porque C exige, e a questão é realmente exatamente por que C exige esses parênteses.
As origens da linguagem C são descritas neste artigo por Dennis Ritchie, um dos principais autores de seu desenvolvimento (alguns podem até dizer o principal autor de seu desenvolvimento). Como dito naquele artigo, o C foi desenvolvido originalmente no início dos anos 70 como uma linguagem de programação de sistema para computadores com espaço extremamente limitado na memória principal. Era desejável ter um idioma de nível superior ao idioma assembly, mas, considerando os recursos disponíveis para trabalhar, a facilidade de analisar o idioma também era importante. Exigir os parênteses tornaria relativamente fácil identificar o código condicional.
Pode-se inferir também que a capacidade de escrever programas usando menos caracteres foi considerada uma vantagem, e dois parênteses ocupam menos espaço do que a palavra-chave
THEN
usada no FORTRAN e em outros idiomas de alto nível da época; de fato, como os parênteses também poderiam substituir espaços como delimitadores de símbolos,if(a==b)
quatro caracteres inteiros eram menores queIF a==b THEN
.De qualquer forma, foi necessário encontrar um equilíbrio entre a facilidade com que os seres humanos seriam capazes de ler, escrever e entender programas escritos em C, a facilidade com que um compilador poderia analisar e compilar programas escritos em C e quantos kilobytes (!) seria necessário para a fonte do programa e o próprio compilador. E parênteses em torno das condições de
if
,while
eswitch
declarações foram como as pessoas escolheram encontrar esse equilíbrio no design de C.Como evidenciado em várias outras respostas, uma vez que você remove as circunstâncias específicas sob as quais C foi desenvolvido, todos os tipos de formas alternativas de sintaxe foram usados para as condições de várias linguagens de programação. Portanto, os parênteses realmente se resumem a uma decisão de design que foi tomada por algumas pessoas sob certas restrições em um determinado momento da história.
fonte
Muitos aqui argumentam que, sem os parênteses, a sintaxe seria ambígua e implica silenciosamente que isso seria de alguma forma ruim ou até impossível.
De fato, os idiomas têm muitas maneiras de lidar com ambiguidades. A precedência do operador é apenas uma instância deste tópico.
Não, a ambiguidade não é a razão dos parênteses. Eu acho que alguém poderia simplesmente criar uma versão de C que não exija os parênteses em torno da condição (tornando-os opcionais) e que ainda crie código válido em todos os casos. O exemplo de
if a ++ b;
poderia ser interpretado como sendo equivalente aif (a) ++b;
ouif (a++) b;
, o que parecer mais apropriado.A questão de por que Dennis Ritchie optou por tornar obrigatório o () (e assim cunhar esse meme para muitas línguas derivadas) é bastante linguística. Acho que a noção de afirmar claramente que a condição é uma expressão e não um comando foi o pai do pensamento.
E, de fato, C foi projetado para ser um analisável usando um analisador de uma passagem. O uso de uma sintaxe com parênteses obrigatórios em torno da condição suporta esse aspecto.
fonte
Parênteses em torno das
if
condições não são necessários no Fortran, Cobol, PL / 1, Algol, Algo-68, Pascal, Modula, XPL, PL / M, MPL, ... ou em qualquer outro idioma que possua umathen
palavra - chave.then
serve para delimitarcondition
o seguintestatement
.O parêntese de fechamento em C etc. funciona como
then
e o de abertura é formalmente redundante.As observações acima se aplicam a idiomas analisados tradicionalmente.
fonte