Expressão Versus


432

Estou perguntando em relação ao c #, mas presumo que seja o mesmo na maioria dos outros idiomas.

Alguém tem uma boa definição de expressões e declarações e quais são as diferenças?


4
Acho que a resposta que você escolheu é ambígua. Uma expressão também faz algo - ela é avaliada como um valor. Eu forneci uma resposta não ambígua.
Shelby Moore III

4
@ShelbyMooreIII - Não ambíguo e também errado. A resposta aceita é redigida de maneira informal, mas essa redação facilita a compreensão - e o mais importante, o significado que ela transmite é preciso.
Justin Morgan

@JustinMorgan Infelizmente, as definições na resposta aceita também estão obviamente erradas ("avalia como um valor" / "uma linha de código") para a maioria das linguagens contemporâneas, incluindo as do tipo C: expressões podem ser usadas em contextos não avaliados e declarações não têm nada a ver com linhas. Mesmo que haja algumas explicações, a resposta curta é confusa e enganosa.
precisa saber é o seguinte

Respostas:


521

Expressão: Algo que avalia um valor. Exemplo: 1 + 2 / x
Instrução: Uma linha de código que faz alguma coisa. Exemplo: GOTO 100

Nas primeiras linguagens de programação de uso geral, como FORTRAN, a distinção era clara. No FORTRAN, uma declaração era uma unidade de execução, algo que você fez. A única razão pela qual não foi chamada de "linha" foi porque, às vezes, abrangia várias linhas. Uma expressão por si só não poderia fazer nada ... você tinha que atribuí-la a uma variável.

1 + 2 / X

é um erro no FORTRAN, porque não faz nada. Você tinha que fazer algo com essa expressão:

X = 1 + 2 / X

FORTRAN não tinha uma gramática como a conhecemos hoje - essa idéia foi inventada, juntamente com a Forma Backus-Naur (BNF), como parte da definição de Algol-60. Nesse ponto, a distinção semântica ("ter um valor" versus "fazer alguma coisa") foi consagrada na sintaxe : um tipo de frase era uma expressão e outro era uma afirmação, e o analisador podia diferenciá-los.

Designers de línguas posteriores embaçaram a distinção: permitiram que expressões sintáticas fizessem coisas e permitiram declarações sintáticas que tinham valores. O exemplo mais antigo de linguagem popular que ainda sobrevive é C. Os projetistas de C perceberam que nenhum dano era causado se você pudesse avaliar uma expressão e jogar fora o resultado. Em C, toda expressão sintática pode ser transformada em uma declaração apenas com um ponto e vírgula no final:

1 + 2 / x;

é uma afirmação totalmente legítima, embora absolutamente nada aconteça. Da mesma forma, em C, uma expressão pode ter efeitos colaterais - pode mudar alguma coisa.

1 + 2 / callfunc(12);

porque callfuncpode fazer algo útil.

Depois de permitir que qualquer expressão seja uma instrução, você também pode permitir o operador de atribuição (=) dentro das expressões. É por isso que C permite que você faça coisas como

callfunc(x = 2);

Isso avalia a expressão x = 2 (atribuindo o valor de 2 a x) e depois passa esse (o 2) para a função callfunc.

Esse desfoque de expressões e instruções ocorre em todos os derivados C (C, C ++, C # e Java), que ainda possuem algumas instruções (como while), mas permitem que quase qualquer expressão seja usada como uma instrução (na atribuição somente em C #, expressões de chamada, incremento e decremento podem ser usadas como declarações; consulte a resposta de Scott Wisniewski ).

Ter duas "categorias sintáticas" (que é o nome técnico para o tipo de declaração e expressão de coisa) pode levar à duplicação de esforços. Por exemplo, C tem duas formas de condicional, o formulário de declaração

if (E) S1; else S2;

e a forma de expressão

E ? E1 : E2

E, às vezes, as pessoas querem duplicação que não existe: no padrão C, por exemplo, apenas uma instrução pode declarar uma nova variável local - mas essa capacidade é útil o suficiente para que o compilador GNU C forneça uma extensão GNU que permita que uma expressão declare uma variável local. variável local também.

Os designers de outras linguagens não gostaram desse tipo de duplicação e viram desde o início que, se expressões podem ter efeitos colaterais e valores, a distinção sintática entre declarações e expressões não é tão útil - então elas se livraram dela. . Haskell, Icon, Lisp e ML são todos os idiomas que não têm declarações sintáticas - eles só têm expressões. Até o loop estruturado de classe e as formas condicionais são considerados expressões e têm valores - mas não muito interessantes.


9
Se não estou interpretando mal você aqui, você parece afirmar que "(setf (terceiro foo) 'ganso)" é uma expressão, não uma declaração, tanto porque é Lisp, que "não possui declarações" e porque o Lisp é mais de uma década mais antigo que o C, que foi a "primeira linguagem popular a desfocar as linhas [entre expressões e afirmações]". Poderia explicar os detalhes disso para mim?
CJS

2
@ Dave Sampson, você fez isso como uma pergunta separada?
27579 Kelly S. French

5
Se não me engano, callfunc(x = 2);passa xpara callfunc, não 2. Se xfor um flutuador, callfunc(float)será chamado, não callfunc(int). E em C ++, se você passa x=ypara func, funcpega uma referência e a altera, ela muda x, não y.
Gabriel

Na resposta acima, está escrito que "Haskell, ... são todas as línguas que não têm declarações sintáticas - elas só têm expressões". Estou curioso para wheresaber por que a cláusula em haskell é considerada uma expressão e não uma declaração. learnyouahaskell.com/syntax-in-functions#where
skgbanga

@skgbanga Eu acredito que whereé realmente uma parte da declaração de função, não expressão ou declaração.
Akangka

22
  • uma expressão é qualquer coisa que produza um valor: 2 + 2
  • uma declaração é um dos "blocos" básicos da execução do programa.

Observe que em C, "=" é realmente um operador, que faz duas coisas:

  • retorna o valor da subexpressão à direita.
  • copia o valor da subexpressão do lado direito na variável do lado esquerdo.

Aqui está um extrato da gramática ANSI C. Você pode ver que C não possui muitos tipos diferentes de instruções ... a maioria das instruções em um programa são instruções de expressão, ou seja, uma expressão com ponto e vírgula no final.

statement
    : labeled_statement
    | compound_statement
    | expression_statement
    | selection_statement
    | iteration_statement
    | jump_statement
    ;

expression_statement
    : ';'
    | expression ';'
    ;

http://www.lysator.liu.se/c/ANSI-C-grammar-y.html


2
Lógica incorreta sobre o que é uma declaração. Um programa declarativo também pode ser executado, mas um programa declarativo não possui instruções. Uma declaração é e produz "efeitos colaterais" , isto é, é imperativa. cf. a minha resposta .
Shelby Moore III

15

Uma expressão é algo que retorna um valor, enquanto uma declaração não.

Por exemplo:

1 + 2 * 4 * foo.bar()     //Expression
foo.voidFunc(1);          //Statement

O grande problema entre os dois é que você pode encadear expressões, enquanto as instruções não podem ser encadeadas.


6
Declarações seguras podem ser encadeadas. {stmt1; stmt2; stmt3;} é uma cadeia e também é uma declaração (composta).
Hugh Allen

5
foo.voidFunc(1);é uma expressão com um valor nulo. whilee ifsão declarações.
tzot 02/12/2009

Estou curioso sobre o não encadeamento de declarações. Seria algo como "se (x> 1) retornar;" ser considerado encadeando duas afirmações?
Simon Tewsi

1
@SimonTewsi Eu acredito que o returné considerado uma subestação.
RastaJedi 17/03/19

1
@SimonTewsi A declaração de retorno aqui está implicitamente dentro do bloco da instrução if, portanto faz parte da instrução if, não acorrentada a ela. O compilador nos permite omitir as chaves aqui, pois é um bloco de linha única.
user2597608 5/06

9

Você pode encontrar isso na wikipedia , mas as expressões são avaliadas com algum valor, enquanto as instruções não têm valor avaliado.

Assim, expressões podem ser usadas em declarações, mas não o contrário.

Observe que algumas linguagens (como Lisp, e eu acredito que Ruby, e muitas outras) não diferenciam declaração x expressão ... nessas linguagens, tudo é uma expressão e pode ser encadeado com outras expressões.


8

Para uma explicação das diferenças importantes na composibilidade (encadeamento) de expressões versus declarações, minha referência favorita é o artigo do prêmio Turing de John Backus: A programação pode ser libertada do estilo de von Neumann? .

Linguagens imperativas (Fortran, C, Java, ...) enfatizam instruções para estruturar programas e têm expressões como uma espécie de reflexão tardia. Linguagens funcionais enfatizam expressões. Linguagens puramente funcionais têm expressões tão poderosas que as declarações podem ser completamente eliminadas.


5

Expressões podem ser avaliadas para obter um valor, enquanto que as instruções não retornam um valor (são do tipo nulo ).

Expressões de chamada de função também podem ser consideradas instruções, é claro, mas, a menos que o ambiente de execução possua uma variável interna especial para armazenar o valor retornado, não há como recuperá-lo.

Linguagens orientadas a instruções exigem que todos os procedimentos sejam uma lista de instruções. Linguagens orientadas a expressões, que provavelmente são todas linguagens funcionais, são listas de expressões ou, no caso do LISP, uma expressão S longa que representa uma lista de expressões.

Embora os dois tipos possam ser compostos, a maioria das expressões pode ser composta arbitrariamente, desde que os tipos correspondam. Cada tipo de declaração tem sua própria maneira de compor outras declarações, se elas puderem fazer tudo isso. As instruções foreach e if requerem uma única declaração ou que todas as instruções subordinadas sejam inseridas em um bloco de instruções, uma após a outra, a menos que as subestações tenham permitido suas próprias subestações.

Instruções também podem incluir expressões, onde uma expressão realmente não inclui nenhuma instrução. Uma exceção, no entanto, seria uma expressão lambda, que representa uma função, e portanto pode incluir qualquer coisa que uma função possa incluir, a menos que a linguagem permita apenas lambdas limitadas, como as lambdas de expressão única do Python.

Em uma linguagem baseada em expressão, tudo o que você precisa é de uma única expressão para uma função, pois todas as estruturas de controle retornam um valor (muitas delas retornam NIL). Não há necessidade de uma declaração de retorno, pois a última expressão avaliada na função é o valor de retorno.


O tipo de uma instrução é o tipo inferior. Voidnão é o tipo inferior. Veja minha resposta .
Shelby Moore III /

1
O tipo nulo não é o tipo inferior (valor único de null)? Não voidseria mais parecido com o tipo de unidade (mas com seu valor único inacessível)?
Mark Cidade

Se voidé o tipo de retorno de uma função que nunca retorna (por exemplo, uma função que throwé um erro), é o tipo inferior . Caso contrário, voidé o tipo de unidade . Você está certo de que uma declaração que não pode divergir tem o tipo de unidade. Mas uma afirmação que pode divergir é o tipo inferior. Devido ao teorema da parada, geralmente não podemos provar que uma função não diverge, então acho que a unidade é ficção. O tipo de fundo não pode ter um valor, por isso não pode ter um único valor null.
Shelby Moore III

1
Quanto ao que eu disse há três anos, não sei se ainda penso nas declarações como tendo um tipo de nulo ou qualquer outro tipo. Nas linguagens baseadas em instruções com as quais eu estou familiarizado, apenas valores e qualquer coisa que armazene ou retorne um valor (por exemplo, expressões, variáveis, membros e funções) podem ter tipos. Geralmente penso no tipo inferior como o conjunto vazio (sem valores) e, portanto, qualquer coisa que não exista ontologicamente teria esse tipo. Um nullvalor é realmente um pseudo-valor que denota que uma referência se refere a algo que não existe.
Mark Cidade

1
Mark, apreciei a racionalidade da sua resposta. Você basicamente tirou as palavras da minha boca. E espero que tenha ficado claro que eu admiti que você estava certo ao elevar o ponto da unidade. Eu acho que concordamos. Eu não me incomodaria em mencionar isso, mas parece que algumas pessoas aqui acham que eu estou sendo negativo. Estou apenas tentando ser factual.
Shelby Moore III

4

Simplesmente: uma expressão é avaliada como um valor, uma declaração não.


Então, o que uma declaração faz? Nada?
Shelby Moore III

1
Pode fazer alguma coisa, mas não avalia nada. Ou seja, você não pode atribuir o resultado a uma variável, enquanto que você pode com uma expressão.
Matthew Schinckel

E, portanto, uma declaração deve ter efeitos colaterais, como declara minha resposta com muito voto negativo. Que outro utilitário uma declaração poderia ter? Mesmo que um NO-OP fosse considerado uma declaração (é apenas "declaração" na gramática, mas não na camada semântica porque é apagada após a análise e a semântica é o que estamos discutindo aqui), não explicaria o que o heck a utilidade geral de uma declaração é.
Shelby Moore III

1
As declarações @ShelbyMooreIII não precisam fazer nada ou ter efeitos colaterais. por exemplo, {}é uma afirmação. Colocar a palavra entre aspas não muda isso. Declarações são construções sintáticas com semântica. Não existe "camada semântica" - você parece estar se referindo à execução . Você diz que está tentando ser preciso, mas falhou nisso. Sua queixa sobre "a ignorância dos que rejeitam os votos" é pura ad hominem; você não tem informações sobre os estados mentais dos que recusam.
Jim Balter

Sim, todo mundo está errado, exceto o intelectualmente desonesto. {}é definido como uma declaração na especificação de linguagem C #.
Jim Balter

4

Algumas coisas sobre linguagens baseadas em expressões:


Mais importante: tudo retorna um valor


Não há diferença entre colchetes e chaves para delimitar blocos e expressões de código, pois tudo é uma expressão. Isso não impede o escopo lexical: Uma variável local pode ser definida para a expressão na qual sua definição está contida e todas as instruções contidas nela, por exemplo.


Em uma linguagem baseada em expressões, tudo retorna um valor. Isso pode ser um pouco estranho a princípio - O que (FOR i = 1 TO 10 DO (print i))retorna?

Alguns exemplos simples:

  • (1) retorna 1
  • (1 + 1) retorna 2
  • (1 == 1) retorna TRUE
  • (1 == 2) retorna FALSE
  • (IF 1 == 1 THEN 10 ELSE 5) retorna 10
  • (IF 1 == 2 THEN 10 ELSE 5) retorna 5

Alguns exemplos mais complexos:

  • Algumas coisas, como algumas chamadas de função, realmente não têm um valor significativo para retornar (coisas que produzem apenas efeitos colaterais?). Ligar OpenADoor(), FlushTheToilet()ou TwiddleYourThumbs()retornar algum tipo de valor mundano, como OK, Concluído ou Sucesso.
  • Quando várias expressões desvinculadas são avaliadas em uma expressão maior, o valor da última coisa avaliada na expressão grande se torna o valor da expressão grande. Como exemplo (FOR i = 1 TO 10 DO (print i)), o valor do loop for é "10", faz com que a (print i)expressão seja avaliada 10 vezes, sempre retornando i como uma string. O tempo final através de retornos 10, nossa resposta final

Geralmente, é necessária uma ligeira mudança de mentalidade para tirar o máximo proveito de uma linguagem baseada em expressões, pois o fato de tudo ser uma expressão torna possível 'alinhar' muitas coisas

Como um exemplo rápido:

 FOR i = 1 to (IF MyString == "Hello, World!" THEN 10 ELSE 5) DO
 (
    LotsOfCode
 )

é um substituto perfeitamente válido para os não baseados em expressão

IF MyString == "Hello, World!" THEN TempVar = 10 ELSE TempVar = 5 
FOR i = 1 TO TempVar DO
(    
    LotsOfCode  
)

Em alguns casos, o layout que o código baseado em expressão permite parece muito mais natural para mim

Claro, isso pode levar à loucura. Como parte de um projeto de hobby em uma linguagem de script baseada em expressão chamada MaxScript, eu consegui criar essa linha monstruosa

IF FindSectionStart "rigidifiers" != 0 THEN FOR i = 1 TO (local rigidifier_array = (FOR i = (local NodeStart = FindsectionStart "rigidifiers" + 1) TO (FindSectionEnd(NodeStart) - 1) collect full_array[i])).count DO
(
    LotsOfCode
)

2

Uma declaração é um caso especial de uma expressão, uma com voidtipo. A tendência das linguagens em tratar declarações de maneira diferente geralmente causa problemas, e seria melhor se elas fossem generalizadas adequadamente.

Por exemplo, em C #, temos o Func<T1, T2, T3, TResult>conjunto sobrecarregado muito útil de delegados genéricos. Mas também temos que ter um Action<T1, T2, T3>conjunto correspondente , e a programação de ordem superior de propósito geral constantemente deve ser duplicada para lidar com essa infeliz bifurcação.

Exemplo trivial - uma função que verifica se uma referência é nula antes de chamar outra função:

TResult IfNotNull<TValue, TResult>(TValue value, Func<TValue, TResult> func)
                  where TValue : class
{
    return (value == null) ? default(TValue) : func(value);
}

O compilador poderia lidar com a possibilidade de TResultser void? Sim. Tudo o que precisa fazer é exigir que o retorno seja seguido por uma expressão do tipo void. O resultado de default(void)seria do tipo void, e a função que está sendo transmitida precisaria ter o formato Func<TValue, void>(que seria equivalente a Action<TValue>).

Várias outras respostas sugerem que você não pode encadear declarações como as expressões, mas não tenho certeza de onde essa idéia vem. Podemos pensar no ;que aparece depois das instruções como um operador de infixo binário, pegando duas expressões do tipo voide combinando-as em uma única expressão do tipo void.


Uma declaração não é um caso especial de expressão. Em alguns idiomas (isto é, na maioria dos sucessores C), é realmente o contrário.
Akangka

2

Declarações -> Instruções para seguir Sequencialmente
Expressões -> Avaliação que retorna um valor

As instruções são basicamente como etapas ou instruções em um algoritmo, o resultado da execução de uma instrução é a atualização do ponteiro de instruções (chamado de assembler)

Expressões não implicam ordem de execução à primeira vista; seu objetivo é avaliar e retornar um valor. Nas linguagens de programação imperativas, a avaliação de uma expressão tem uma ordem, mas é apenas por causa do modelo imperativo, mas não é sua essência.

Exemplos de declarações:

for
goto
return
if

(todos eles implicam o avanço da linha (declaração) de execução para outra linha)

Exemplo de expressões:

2+2

(não implica a ideia de execução, mas de avaliação)


E os efeitos colaterais?
Austin Henley

@AustinHenley, não há requisitos para isso. De fato, uma expressão pode definitivamente ter um efeito colateral.
Akangka 11/06

1

Declaração ,

Uma declaração é um bloco de construção procedural a partir do qual todos os programas C # são construídos. Uma instrução pode declarar uma variável ou constante local, chamar um método, criar um objeto ou atribuir um valor a uma variável, propriedade ou campo.

Uma série de instruções cercadas por chaves forma um bloco de código. Um corpo de método é um exemplo de bloco de código.

bool IsPositive(int number)
{
    if (number > 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

Instruções em C # geralmente contêm expressões. Uma expressão em C # é um fragmento de código que contém um valor literal, um nome simples ou um operador e seus operandos.

Expressão ,

Uma expressão é um fragmento de código que pode ser avaliado em um único valor, objeto, método ou espaço para nome. Os dois tipos mais simples de expressões são literais e nomes simples. Um literal é um valor constante que não tem nome.

int i = 5;
string s = "Hello World";

I e s são nomes simples que identificam variáveis ​​locais. Quando essas variáveis ​​são usadas em uma expressão, o valor da variável é recuperado e usado para a expressão.


Prefiro escrever if(number >= 0) return true; else return false; ou ainda melhor bool? IsPositive(int number) { if(number > 0) return true; else if(number < 0) return false; else return null;}:)
Mahdi Tahsildari

1

Prefiro o significado statementno sentido lógico formal da palavra. É aquele que altera o estado de uma ou mais das variáveis ​​na computação, permitindo que uma declaração verdadeira ou falsa seja feita sobre seus valores.

Eu acho que sempre haverá confusão no mundo da computação e na ciência em geral quando novas terminologias ou palavras forem introduzidas, as palavras existentes serão "reaproveitadas" ou os usuários ignorarão a terminologia existente, estabelecida ou "apropriada" para o que estão descrevendo


1

Não estou realmente satisfeito com nenhuma das respostas aqui. Eu olhei para a gramática do C ++ (ISO 2008) . No entanto, talvez por uma questão de didática e programação, as respostas sejam suficientes para distinguir os dois elementos (embora a realidade pareça mais complicada).

Uma declaração consiste em zero ou mais expressões, mas também pode ser outros conceitos de linguagem. Este é o formulário Extended Backus Naur para a gramática (trecho de instrução):

statement:
        labeled-statement
        expression-statement <-- can be zero or more expressions
        compound-statement
        selection-statement
        iteration-statement
        jump-statement
        declaration-statement
        try-block

Podemos ver os outros conceitos que são considerados declarações em C ++.

  • expressão-declaração s é auto-explicativa (uma declaração pode consistir em zero ou mais expressões, leia a gramática cuidadosamente, é complicado)
  • casepor exemplo, é uma declaração rotulada
  • afirmação de seleção s são if if/else,case
  • iteração declaração s são while, do...while,for (...)
  • jump-declaração s são break, continue, return(pode retornar expressão),goto
  • declaração-declaração é o conjunto de declarações
  • try-block é uma declaração que representa try/catchblocos
  • e pode haver um pouco mais na gramática

Este é um trecho que mostra a parte de expressões:

expression:
        assignment-expression
        expression "," assignment-expression
assignment-expression:
        conditional-expression
        logical-or-expression assignment-operator initializer-clause
        throw-expression
  • expressões são ou contêm frequentemente atribuições
  • condicional-expressão (sons enganosa) refere-se ao uso dos operadores ( +, -, *, /, &, |, &&, ||, ...)
  • jogar expressão - uh? a throwcláusula também é uma expressão

0

Declarações são frases gramaticalmente completas. Expressões não são. Por exemplo

x = 5

lê como "x recebe 5." Esta é uma frase completa. O código

(x + 5)/9.0

lê, "x mais 5 todos divididos por 9,0". Esta não é uma frase completa. A declaração

while k < 10: 
    print k
    k += 1

é uma frase completa. Observe que o cabeçalho do loop não é; "enquanto k <10", é uma cláusula subordinada.


whileé uma expressão em alguns idiomas como o Scala. Você está confundindo gramática com digitação. Veja minha resposta .
Shelby Moore III

Aqui está o loop while no scala: tutorialspoint.com/scala/scala_ while_loop.htm O loop com seu predicado e nenhum corpo não é uma frase gramaticalmente completa. Não é uma expressão completa. Você precisa do corpo para completá-lo como uma expressão.
Ncmathsadist

A whilecom um corpo ainda é uma expressão em Scala. Também pode ser uma afirmação, se criar efeitos colaterais, o que minha resposta com muita votação reduzida permite (uma expressão também pode ser uma afirmação). Minha resposta é a única correta. Desculpe a todos os leitores que não conseguem entender.
Shelby Moore III

O que você quer dizer com gramática completa? Em C, (x + 5)/9.0definitivamente pode ficar sozinho como uma declaração. Além disso, se por conclusão gramatical, você quer dizer um programa válido, C não permite que as instruções sejam independentes como um único programa.
Akangka 11/06

Gramaticalmente completa: constitui uma frase completa.
ncmathsadist 12/06

0

Aqui está o verão de uma das respostas mais simples que encontrei.

originalmente Respondido por Anders Kaseorg

Uma instrução é uma linha completa de código que executa alguma ação, enquanto uma expressão é qualquer seção do código que é avaliada como um valor.

As expressões podem ser combinadas “horizontalmente” em expressões maiores usando operadores, enquanto as instruções podem ser combinadas “verticalmente” escrevendo uma após a outra ou com construções de bloco.

Toda expressão pode ser usada como uma instrução (cujo efeito é avaliar a expressão e ignorar o valor resultante), mas a maioria das instruções não pode ser usada como expressões.

http://www.quora.com/Python-programming-language-1/Whats-the-difference-between-a-statement-and-an-expression-in-Python


0

A base de fato desses conceitos é:

Expressões : uma categoria sintática cuja instância pode ser avaliada para um valor.

Instrução : Uma categoria sintática cuja instância pode estar envolvida nas avaliações de uma expressão e o valor resultante da avaliação (se houver) não está garantida disponível.

Além do contexto inicial do FORTRAN nas primeiras décadas, as definições de expressões e afirmações na resposta aceita estão obviamente erradas:

  • Expressões podem ser operandos não avaliados. Valores nunca são produzidos a partir deles.
    • Subexpressões em avaliações não estritas podem ser definitivamente não avaliadas.
      • A maioria dos idiomas do tipo C possui as chamadas regras de avaliação de curto-circuito para pular condicionalmente algumas avaliações de subexpressão e não alterar o resultado final, apesar dos efeitos colaterais.
    • C e algumas linguagens do tipo C têm a noção de operando não avaliado que pode ser até normativamente definido na especificação da linguagem. Tais construções são usadas para evitar as avaliações definitivamente, para que as informações de contexto restantes (por exemplo, tipos ou requisitos de alinhamento) possam ser estaticamente distinguidas sem alterar o comportamento após a tradução do programa.
      • Por exemplo, uma expressão usada como operando do sizeofoperador nunca é avaliada.
  • Instruções não têm nada a ver com construções de linha. Eles podem fazer algo mais do que expressões, dependendo das especificações da linguagem.
    • Modern Fortran, como o descendente direto do antigo Fortran, tem conceitos de executável declaração s e não executáveis declaração s.
    • Da mesma forma, o C ++ define declarações como a subcategoria de nível superior de uma unidade de tradução. Uma declaração em C ++ é uma declaração. (Isso não é verdade em C.) Também existem declarações de expressão como as executáveis ​​de Fortran.
    • Para o interesse da comparação com expressões, apenas as instruções "executáveis" são importantes. Mas você não pode ignorar o fato de que as instruções já são generalizadas para serem construções que formam as unidades de tradução em tais idiomas imperativos. Então, como você pode ver, as definições da categoria variam muito. A (provavelmente) única propriedade comum que permaneceu preservada entre esses idiomas é que as declarações devem ser interpretadas na ordem lexical (para a maioria dos usuários, da esquerda para a direita e de cima para baixo).

(BTW, eu quero acrescentar [a citação necessária] a essa resposta sobre materiais sobre C, porque não me lembro se o DMR tem essas opiniões. Parece que não, caso contrário, não deve haver razões para preservar a duplicação de funcionalidade no design de C : notavelmente, o operador de vírgula x as instruções.)

(A lógica a seguir não é a resposta direta à pergunta original, mas acho necessário esclarecer algo que já foi respondido aqui.)

No entanto, é duvidoso que necessitemos de uma categoria específica de "declarações" em linguagens de programação de uso geral:

  • Não é garantido que as instruções tenham mais recursos semânticos sobre as expressões nos designs usuais.
    • Muitos idiomas já abandonaram com sucesso a noção de declarações para obter designs gerais limpos, limpos e consistentes.
      • Em tais línguas, expressões podem fazer tudo declarações de estilo antigo pode fazer: basta soltar os resultados não utilizados quando as expressões são avaliadas, seja por deixar os resultados explicitamente não especificada (por exemplo, em R n Esquema RS), ou ter um valor especial (como um valor de um tipo de unidade) não produzido a partir de avaliações de expressão normal.
      • As regras de ordem lexical de avaliação de expressões podem ser substituídas por um operador explícito de controle de sequência (por exemplo, beginno Esquema) ou por açúcar sintático de estruturas monádicas.
      • As regras de ordem lexical de outros tipos de "declarações" podem ser derivadas como extensões sintáticas (usando macros higiênicas, por exemplo) para obter a funcionalidade sintática semelhante. (E na verdade pode fazer mais .)
    • Pelo contrário, as afirmações não podem ter regras convencionais, porque elas não compõem a avaliação: simplesmente não existe uma noção comum de "avaliação de subestação". (Mesmo se houver, duvido que possa haver algo muito mais do que copiar e colar das regras existentes de avaliação de expressões.)
      • Normalmente, as instruções de preservação de idiomas também terão expressões para expressar cálculos, e há uma subcategoria de nível superior das instruções preservadas nas avaliações de expressão para essa subcategoria. Por exemplo, o C ++ tem a chamada expressão-declaração como a subcategoria e usa as regras de avaliação de expressão de valor descartado para especificar os casos gerais de avaliações de expressão completa nesse contexto. Algumas linguagens como o C # optam por refinar os contextos para simplificar os casos de uso, mas incham mais a especificação.
  • Para usuários de linguagens de programação, o significado das instruções pode confundi-las ainda mais.
    • A separação de regras de expressões e declarações nas línguas exige mais esforço para aprender uma língua.
    • A ingênua interpretação da ordem lexical oculta a noção mais importante: avaliação da expressão. (Isso é provavelmente o mais problemático de todos.)
      • Mesmo as avaliações de expressões completas em declarações são restritas à ordem lexical, as subexpressões não são (necessariamente). Em última análise, os usuários devem aprender isso, além de quaisquer regras associadas às instruções. (Considere como fazer um novato entender o que ++i + ++inão faz sentido em C.)
      • Algumas linguagens como Java e C # restringem ainda mais a ordem das avaliações das subexpressões para permitir a ignorância das regras de avaliação. Pode ser ainda mais problemático.
        • Isso parece superespecificado para usuários que já aprenderam a ideia de avaliação de expressão. Também incentiva a comunidade de usuários a seguir o modelo mental embaçado do design da linguagem.
        • Incha ainda mais a especificação da linguagem.
        • É prejudicial à otimização, perdendo a expressividade do não determinismo nas avaliações, antes que sejam introduzidas primitivas mais complicadas.
      • Algumas linguagens como C ++ (particularmente C ++ 17) especificam contextos mais sutis de regras de avaliação, como comprometimento dos problemas acima.
        • Incha bastante a especificação da linguagem.
        • Isso é totalmente contrário à simplicidade para usuários comuns ...

Então, por que declarações? Enfim, a história já está uma bagunça. Parece que a maioria dos designers de idiomas não faz a escolha com cuidado.

Pior ainda, fornece a alguns entusiastas do sistema de tipos (que não estão familiarizados o suficiente com a história do PL) alguns conceitos errôneos de que os sistemas de tipos devem ter coisas importantes a ver com os projetos de regras mais essenciais na semântica operacional.

Sério, o raciocínio dependendo dos tipos não é tão ruim em muitos casos, mas particularmente não é construtivo neste caso especial. Até especialistas podem estragar tudo.

Por exemplo, alguém enfatiza a natureza bem digitada como o argumento central contra o tratamento tradicional de continuações não limitadas . Embora a conclusão seja razoavelmente razoável e os insights sobre funções compostas sejam bons ( mas ainda muito ingênuos para a essência ), esse argumento não é sólido porque ignora totalmente a abordagem de "canal lateral" na prática como _Noreturn any_of_returnable_types(em C11) para codificar Falsum. E, estritamente falando, uma máquina abstrata com estado imprevisível não é idêntica a "um computador travado".


0

Em uma linguagem de programação orientada a instruções, um bloco de código é definido como uma lista de instruções. Em outras palavras, uma instrução é uma parte da sintaxe que você pode colocar dentro de um bloco de código sem causar um erro de sintaxe.

A Wikipedia define a declaração de palavras da mesma forma

Na programação de computadores, uma declaração é uma unidade sintática de uma linguagem de programação imperativa que expressa alguma ação a ser realizada. Um programa escrito nesse idioma é formado por uma sequência de uma ou mais instruções

Observe a última declaração. (embora "um programa" neste caso esteja tecnicamente errado, porque C e Java rejeitam um programa que não consiste em nada de instruções.)

Wikipedia define a palavra expressão como

Uma expressão em uma linguagem de programação é uma entidade sintática que pode ser avaliada para determinar seu valor

Isso é, no entanto, falso, porque em Kotlin, throw new Exception("") é uma expressão, mas quando avaliado, ele simplesmente gera uma exceção, nunca retornando valor algum.

Em uma linguagem de programação estaticamente tipada, toda expressão tem um tipo. Essa definição, no entanto, não funciona em uma linguagem de programação digitada dinamicamente.

Pessoalmente, defino uma expressão como uma parte da sintaxe que pode ser composta por um operador ou função para gerar uma expressão maior. Na verdade, isso é semelhante à explicação da expressão da Wikipedia:

É uma combinação de uma ou mais constantes, variáveis, funções e operadores que a linguagem de programação interpreta (de acordo com suas regras particulares de precedência e associação) e calcula para produzir ("retornar", em um ambiente com estado) outro valor

Mas, o problema está na linguagem de programação C, dada a função executeAlgo como isto:

void executeSomething(void){
    return;
}

É executeSomething()uma expressão ou é uma afirmação? De acordo com minha definição, é uma declaração porque, conforme definido na gramática de referência C da Microsoft,

Você não pode usar o valor (inexistente) de uma expressão que tenha o tipo void de forma alguma, nem converter uma expressão void (por conversão implícita ou explícita) em qualquer tipo, exceto void

Mas a mesma página indica claramente que essa sintaxe é uma expressão.


-6

Para aprimorar e validar minha resposta anterior, as definições dos termos da linguagem de programação devem ser explicadas a partir da teoria dos tipos de ciência da computação, quando aplicável.

Uma expressão tem um tipo diferente do tipo Bottom, ou seja, tem um valor. Uma instrução tem o tipo Unidade ou Parte inferior.

A partir disso, segue-se que uma instrução só pode ter efeito em um programa quando cria um efeito colateral, porque ela não pode retornar um valor ou apenas retorna o valor do tipo de Unidade que não é atribuível (em alguns idiomas, como um C void ) ou (como em Scala) podem ser armazenados para uma avaliação atrasada da declaração.

Obviamente, a @pragmaou a /*comment*/não têm tipo e, portanto, são diferenciadas de declarações. Portanto, o único tipo de declaração que não teria efeitos colaterais seria uma não operação. A não operação é útil apenas como espaço reservado para futuros efeitos colaterais. Qualquer outra ação devido a uma declaração seria um efeito colateral. Novamente, uma dica do compilador, por exemplo @pragma, não é uma declaração porque não tem tipo.


2
A distinção não tem nada a ver com o tipo de expressões. Instruções sintaticamente definidas não têm nenhum tipo em muitos idiomas. Embora eu não seja contra a atribuição de um tipo nesses termos na teoria, diferentes tratamentos @pragmaou /*comment*/são logicamente inconsistentes.
FrankHB 23/08/19

-11

Mais precisamente, uma declaração deve ter um "efeito colateral" (isto é, ser imperativo ) e uma expressão deve ter um tipo de valor (isto é, não o tipo inferior).

O tipo de uma declaração é o tipo de unidade, mas devido ao teorema de Halting a unidade é ficção, digamos que seja o tipo inferior .


Voidnão é exatamente o tipo inferior (não é o subtipo de todos os tipos possíveis). Existe em idiomas que não possuem um sistema de tipos completamente sonoros . Pode parecer uma afirmação esnobe, mas completa , como anotações de variação é fundamental para a criação de software extensível.

Vamos ver o que a Wikipedia tem a dizer sobre esse assunto.

https://en.wikipedia.org/wiki/Statement_(computer_science)

Na programação de computadores, uma declaração é o menor elemento independente de uma linguagem de programação imperativa que expressa alguma ação a ser realizada.

Muitos idiomas (por exemplo, C) fazem uma distinção entre instruções e definições, com uma instrução contendo apenas código executável e uma definição declarando um identificador, enquanto uma expressão é avaliada apenas como um valor.


5
Uma declaração não precisa ter um efeito colateral. Por exemplo, em python passé uma declaração. É um não-op, e não avalia a nada.
Matthew Schinckel

9
-1 Isso está errado. Uma declaração não precisa ter um efeito colateral. Consulte a seção 1.5 da especificação de idioma C # . Não só ele não especificar que as declarações devem ter efeitos colaterais, mas também lista várias declarações que podem ter sem efeitos colaterais.
NullUserException

2
@NullUserException Eu li essa seção. Instruções de declaração, expressão, seleção, iteração e salto podem criar efeitos colaterais. Mas se houver uma expressão RT, não será uma declaração. Sei que a especificação está equiparando expressões com declarações, mas essa pergunta pedia a diferença entre elas. Portanto, a pergunta não tem resposta ou você está analisando as especificações do C # muito literalmente. A resposta mais votada é tentar dizer o que eu fiz. Mas "faz alguma coisa" não tem sentido. "efeito colateral" é a maneira significativa de dizer "faz alguma coisa". Temos que pensar, não apenas regurgitar.
Shelby Moore III

13
@ShelbyMooreIII Você está certo. A documentação oficial está errada . Marc Gravell e Jon Skeet, que são possivelmente os mais respeitados pôsteres de C # ativos no SO fora de Eric Lippert, estão errados . Eu e todos os outros que votamos contra você e deixaram comentários explicando nossa posição estão errados . Você está certo. Você é claramente a única pessoa que sabe do que está falando, já que é muito mais inteligente do que todo o resto do SO.
NullUserException

3
Conhecer a definição precisa de conceitos como declaração, expressão, conversão, conversão etc. tem zero impacto em 99,999% das tarefas diárias de programação. Pense sobre isso . Além disso: a maioria das pessoas não se importa com Haskell e Scala.
NullUserException 12/12
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.