Expresión versus declaración


432

Pregunto con respecto a c #, pero supongo que es lo mismo en la mayoría de los otros idiomas.

¿Alguien tiene una buena definición de expresiones y declaraciones y cuáles son las diferencias?


44
Encuentro que la respuesta que elegiste es ambigua. Una expresión también hace algo: se evalúa como un valor. Proporcioné una respuesta no ambigua.
Shelby Moore III

44
@ShelbyMooreIII: no ambiguo y también equivocado. La respuesta aceptada está redactada de manera informal, pero esa redacción hace que sea fácil de entender, y lo más importante, el significado que transmite es preciso.
Justin Morgan

@JustinMorgan Lamentablemente, las definiciones en la respuesta aceptada también son obviamente erróneas ("evalúa a un valor" / "una línea de código") para la mayoría del lenguaje contemporáneo incluyen las de tipo C: las expresiones se pueden usar en contextos no evaluados y las declaraciones no tienen nada que ver con lineas. Incluso hay algunas explicaciones, la respuesta corta es confusa y engañosa.
FrankHB

Respuestas:


521

Expresión: algo que se evalúa como un valor. Ejemplo: 1 + 2 / x
Declaración: Una línea de código que hace algo. Ejemplo: GOTO 100

En los primeros lenguajes de programación de propósito general, como FORTRAN, la distinción era muy clara. En FORTRAN, una declaración era una unidad de ejecución, algo que usted hizo. La única razón por la que no se llamaba "línea" era porque a veces abarcaba varias líneas. Una expresión por sí sola no podía hacer nada ... tenía que asignarla a una variable.

1 + 2 / X

es un error en FORTRAN, porque no hace nada. Tenías que hacer algo con esa expresión:

X = 1 + 2 / X

FORTRAN no tenía una gramática tal como la conocemos hoy en día, esa idea fue inventada, junto con Backus-Naur Form (BNF), como parte de la definición de Algol-60. En ese momento, la distinción semántica ("tener un valor" versus "hacer algo") estaba consagrada en la sintaxis : un tipo de frase era una expresión, y otra era una declaración, y el analizador podía distinguirlas.

Los diseñadores de lenguajes posteriores desdibujaron la distinción: permitieron que las expresiones sintácticas hicieran cosas, y permitieron declaraciones sintácticas que tenían valores. El primer ejemplo de lenguaje popular que aún sobrevive es C. Los diseñadores de C se dieron cuenta de que no se hacía daño si se le permitía evaluar una expresión y desechar el resultado. En C, cada expresión sintáctica se puede convertir en una declaración simplemente agregando un punto y coma a lo largo del final:

1 + 2 / x;

Es una declaración totalmente legítima, aunque absolutamente nada sucederá. De manera similar, en C, una expresión puede tener efectos secundarios: puede cambiar algo.

1 + 2 / callfunc(12);

porque callfuncpodría hacer algo útil

Una vez que permita que cualquier expresión sea una declaración, también podría permitir el operador de asignación (=) dentro de las expresiones. Es por eso que C te permite hacer cosas como

callfunc(x = 2);

Esto evalúa la expresión x = 2 (asignando el valor de 2 a x) y luego pasa eso (el 2) a la función callfunc.

Este desenfoque de expresiones y declaraciones ocurre en todos los derivados C (C, C ++, C # y Java), que todavía tienen algunas declaraciones (como while) pero que permiten que casi cualquier expresión se use como una declaración (en la asignación de C # solamente, las expresiones call, increment y decrement pueden usarse como declaraciones; ver la respuesta de Scott Wisniewski ).

Tener dos "categorías sintácticas" (que es el nombre técnico para el tipo de cosas que son las declaraciones y expresiones) puede conducir a la duplicación de esfuerzos. Por ejemplo, C tiene dos formas de condicional, la forma de declaración

if (E) S1; else S2;

y la forma de expresión

E ? E1 : E2

Y a veces la gente quiere una duplicación que no existe: en el estándar C, por ejemplo, solo una declaración puede declarar una nueva variable local, pero esta capacidad es lo suficientemente útil como para que el compilador GNU C proporcione una extensión GNU que permite que una expresión declare un variable local también.

A los diseñadores de otros lenguajes no les gustó este tipo de duplicación, y vieron desde el principio que si las expresiones pueden tener efectos secundarios y valores, entonces la distinción sintáctica entre declaraciones y expresiones no es tan útil, por lo que se deshicieron de ella. . Haskell, Icon, Lisp y ML son todos lenguajes que no tienen enunciados sintácticos, solo tienen expresiones. Incluso los bucles estructurados de clase y las formas condicionales se consideran expresiones y tienen valores, pero no muy interesantes.


99
Si no te estoy interpretando mal aquí, parece que afirmas que "(setf (third foo) 'goose)" es una expresión, no una declaración, tanto porque es Lisp, que "no tiene declaraciones" y porque Lisp es más de una década mayor que C, que fue el "lenguaje popular más antiguo para difuminar las líneas [entre expresiones y declaraciones]". ¿Podría explicarme los detalles de eso?
cjs

2
@Curt Sampson, ¿has hecho eso como una pregunta separada?
Kelly S. French el

55
Si no me equivoco, callfunc(x = 2);pasa xa callfunc, no 2. Si xes un flotador, callfunc(float)se llamará, no callfunc(int). Y en C ++, si pasa x=ya func, y functoma una referencia y la cambia, cambia x, no y.
Gabriel

En la respuesta anterior, está escrito que "Haskell, ... son todos los idiomas que no tienen declaraciones sintácticas, solo tienen expresiones". Tengo curiosidad por qué la wherecláusula en Haskell se considera una expresión y no una declaración. learnyouahaskell.com/syntax-in-functions#where
skgbanga

@skgbanga, creo que wherees en realidad una parte de la declaración de función, no una expresión o declaración.
Akangka

22
  • una expresión es cualquier cosa que produce un valor: 2 + 2
  • Una declaración es uno de los "bloques" básicos de la ejecución del programa.

Tenga en cuenta que en C, "=" es en realidad un operador, que hace dos cosas:

  • devuelve el valor de la subexpresión de la mano derecha.
  • copia el valor de la subexpresión de la mano derecha en la variable del lado izquierdo.

Aquí hay un extracto de la gramática ANSI C. Puede ver que C no tiene muchos tipos diferentes de declaraciones ... la mayoría de las declaraciones en un programa son declaraciones de expresión, es decir, una expresión con un punto y coma al 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 incorrecta sobre qué es una declaración. Un programa declarativo también puede ejecutarse, pero un programa declarativo no tiene declaraciones. Una declaración es y hace "efectos secundarios" , es decir, es imprescindible. cf. mi respuesta .
Shelby Moore III

15

Una expresión es algo que devuelve un valor, mientras que una declaración no lo hace.

Por ejemplo:

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

El gran problema entre los dos es que puedes encadenar expresiones, mientras que las declaraciones no se pueden encadenar.


66
Las declaraciones seguras se pueden encadenar. {stmt1; stmt2; stmt3;} es una cadena, y también es una declaración (compuesta) en sí misma.
Hugh Allen

55
foo.voidFunc(1);es una expresión con un valor nulo. whiley ifson declaraciones.
tzot 02 de

Tengo curiosidad por la no cadena de declaraciones. Algo así como "if (x> 1) return;" ser considerado como encadenar dos declaraciones juntas?
Simon Tewsi

1
@SimonTewsi Creo que returnse considera una subestimación.
RastaJedi

1
@SimonTewsi La declaración de retorno aquí está implícitamente dentro del bloque de la declaración if, por lo que es parte de la declaración if, no encadenada con ella. El compilador nos permite omitir las llaves aquí, ya que es un bloque de una sola línea.
user2597608

9

Puede encontrar esto en wikipedia , pero las expresiones se evalúan con algún valor, mientras que las declaraciones no tienen valor evaluado.

Por lo tanto, las expresiones se pueden usar en declaraciones, pero no al revés.

Tenga en cuenta que algunos lenguajes (como Lisp, y creo que Ruby, y muchos otros) no diferencian la declaración frente a la expresión ... en tales lenguajes, todo es una expresión y puede encadenarse con otras expresiones.


8

Para una explicación de las diferencias importantes en la componibilidad (posibilidad de encadenamiento) de las expresiones frente a las declaraciones, mi referencia favorita es el artículo del premio Turing de John Backus, ¿Se puede liberar la programación del estilo de von Neumann? .

Los lenguajes imperativos (Fortran, C, Java, ...) enfatizan las declaraciones para estructurar programas y tienen expresiones como una especie de pensamiento posterior. Los lenguajes funcionales enfatizan las expresiones. Los lenguajes puramente funcionales tienen expresiones tan poderosas que las declaraciones pueden eliminarse por completo.


5

Las expresiones se pueden evaluar para obtener un valor, mientras que las declaraciones no devuelven un valor (son de tipo nulo ).

Las expresiones de llamada a funciones también pueden considerarse declaraciones, por supuesto, pero a menos que el entorno de ejecución tenga una variable incorporada especial para contener el valor devuelto, no hay forma de recuperarlo.

Los lenguajes orientados a declaraciones requieren que todos los procedimientos sean una lista de declaraciones. Los lenguajes orientados a la expresión, que probablemente sean todos lenguajes funcionales, son listas de expresiones o, en el caso de LISP, una expresión S larga que representa una lista de expresiones.

Aunque ambos tipos pueden estar compuestos, la mayoría de las expresiones pueden estar compuestas arbitrariamente siempre que los tipos coincidan. Cada tipo de declaración tiene su propia forma de componer otras declaraciones, si pueden hacerlo todo. Foreach y si las declaraciones requieren una sola declaración o que todas las declaraciones subordinadas van en un bloque de declaración, una tras otra, a menos que las subestimaciones permitan sus propias subenunciaciones.

Las declaraciones también pueden incluir expresiones, donde una expresión realmente no incluye ninguna declaración. Sin embargo, una excepción sería una expresión lambda, que representa una función, por lo que puede incluir cualquier cosa que una función pueda incluir a menos que el lenguaje solo permita lambdas limitadas, como las lambdas de expresión única de Python.

En un lenguaje basado en expresiones, todo lo que necesita es una sola expresión para una función, ya que todas las estructuras de control devuelven un valor (muchas de ellas devuelven NIL). No hay necesidad de una declaración de retorno ya que la última expresión evaluada en la función es el valor de retorno.


El tipo de una declaración es el tipo inferior. VoidNo es el tipo de fondo. Mira mi respuesta .
Shelby Moore III

1
¿No es el tipo nulo el tipo inferior (valor único de null)? ¿No voidsería más como el tipo de unidad (pero con su valor único inaccesible)?
Mark Cidade

Si voides el tipo de retorno de una función que nunca regresa (por ejemplo, una función que throwes un error), es el tipo inferior . De voidlo contrario, es el tipo de unidad . Tiene razón en que una declaración que no puede divergir tiene el tipo de unidad. Pero una declaración que puede divergir es el tipo inferior. Debido al Teorema de detención, generalmente no podemos probar que una función no diverja, por lo que creo que la unidad es ficción. El tipo inferior no puede tener un valor, por lo que no puede tener un solo valor de null.
Shelby Moore III

1
Con respecto a lo que dije hace tres años, no sé si todavía pienso que las declaraciones tienen un tipo nulo o algún tipo realmente. En los lenguajes basados ​​en declaraciones con los que estoy familiarizado, solo los valores y todo lo que almacena o devuelve un valor (por ejemplo, expresiones, variables, miembros y funciones) pueden tener tipos. Generalmente pienso en el tipo de fondo como el conjunto vacío (sin valores) y, por lo tanto, cualquier cosa que no exista ontológicamente tendría este tipo. Un nullvalor es realmente un pseudovalor que denota que una referencia se refiere a algo que no existe.
Mark Cidade

1
Mark, aprecié la racionalidad de tu respuesta. Básicamente sacaste las palabras de mi boca. Y espero que haya quedado claro que te admití que estabas en lo correcto al elevar el punto unitario. Creo que estamos de acuerdo. No iba a molestarme en mencionar esto, pero parece que algunas personas aquí piensan que estoy siendo negativo. Solo estoy tratando de ser factual.
Shelby Moore III

4

Simplemente: una expresión se evalúa como un valor, una declaración no.


Entonces, ¿qué hace una declaración? ¿Nada?
Shelby Moore III

1
Puede hacer algo, pero no evalúa nada. Es decir, no puede asignar el resultado a una variable, mientras que puede hacerlo con una expresión.
Matthew Schinckel

Y por lo tanto, una declaración debe tener efectos secundarios, como dice mi respuesta muy rechazada. ¿Qué otra utilidad podría tener una declaración? Incluso si un NO-OP se considerara como una declaración (es solo una "declaración" en gramática pero no en la capa semántica porque se borra después del análisis y la semántica es lo que estamos discutiendo aquí), no explicaría qué diablos, la utilidad general de una declaración es.
Shelby Moore III

1
@ShelbyMooreIII Las declaraciones no necesitan hacer nada ni tener efectos secundarios. Por ejemplo, {}es una declaración. Poner la palabra entre comillas de miedo no cambia eso. Las declaraciones son construcciones sintácticas con semántica. No existe tal cosa como "la capa semántica": parece que se refiere a la ejecución . Dices que estás tratando de ser preciso, pero has fallado en eso. Su queja acerca de "la ignorancia de los votantes negativos" es puramente ad hominem; no tienes información sobre los estados mentales de los votantes negativos.
Jim Balter

Sí, todos están equivocados, excepto los intelectualmente deshonestos. {}se define como una declaración en la especificación del lenguaje C #.
Jim Balter

4

Algunas cosas sobre los lenguajes basados ​​en expresiones:


Lo más importante: todo devuelve un valor


No hay diferencia entre llaves y llaves para delimitar bloques de código y expresiones, ya que todo es una expresión. Sin embargo, esto no impide el alcance léxico: se podría definir una variable local para la expresión en la que está contenida su definición y todas las declaraciones contenidas en ella, por ejemplo.


En un lenguaje basado en expresiones, todo devuelve un valor. Esto puede ser un poco extraño al principio: ¿qué (FOR i = 1 TO 10 DO (print i))devuelve?

Algunos ejemplos simples:

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

Un par de ejemplos más complejos:

  • Algunas cosas, como algunas llamadas a funciones, realmente no tienen un valor significativo para devolver (¿Cosas que solo producen efectos secundarios?). Llamar OpenADoor(), FlushTheToilet()o TwiddleYourThumbs()devolverá algún tipo de valor mundano, como Aceptar, Listo o Éxito.
  • Cuando se evalúan varias expresiones no vinculadas dentro de una expresión más grande, el valor de lo último evaluado en la expresión grande se convierte en el valor de la expresión grande. Para tomar el ejemplo de (FOR i = 1 TO 10 DO (print i)), el valor del bucle for es "10", hace que la (print i)expresión se evalúe 10 veces, cada vez que devuelve i como una cadena. El tiempo final a través de devoluciones 10, nuestra respuesta final

A menudo se requiere un ligero cambio de mentalidad para sacar el máximo provecho de un lenguaje basado en expresiones, ya que el hecho de que todo sea una expresión permite 'alinear' muchas cosas

Como un ejemplo rápido:

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

es un reemplazo perfectamente válido para el no basado en expresiones

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

En algunos casos, el diseño que permite el código basado en expresiones me parece mucho más natural.

Por supuesto, esto puede conducir a la locura. Como parte de un proyecto de pasatiempo en un lenguaje de scripting basado en expresiones llamado MaxScript, logré crear esta línea 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

Una declaración es un caso especial de una expresión, una con voidtipo. La tendencia de los lenguajes a tratar las declaraciones de manera diferente a menudo causa problemas, y sería mejor si se generalizaran adecuadamente.

Por ejemplo, en C # tenemos el Func<T1, T2, T3, TResult>conjunto sobrecargado muy útil de delegados genéricos. Pero también tenemos que tener un Action<T1, T2, T3>conjunto correspondiente , y la programación de orden superior de propósito general debe duplicarse constantemente para lidiar con esta desafortunada bifurcación.

Ejemplo trivial: una función que verifica si una referencia es nula antes de llamar a otra función:

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

¿Podría el compilador lidiar con la posibilidad de TResultser void? Si. Todo lo que tiene que hacer es requerir que el retorno sea seguido por una expresión de tipo void. El resultado de default(void)sería de tipo void, y el func que se pasaría tendría que ser de la forma Func<TValue, void>(que sería equivalente a Action<TValue>).

Varias otras respuestas implican que no puede encadenar declaraciones como puede con expresiones, pero no estoy seguro de dónde viene esta idea. Podemos pensar en lo ;que aparece después de las declaraciones como un operador infijo binario, tomando dos expresiones de tipo voidy combinándolas en una sola expresión de tipo void.


Una declaración no es un caso especial de expresión. En algunos lenguajes (es decir, la mayoría de los sucesores de C), en realidad es al revés.
Akangka

2

Declaraciones -> Instrucciones para seguir secuencialmente
Expresiones -> Evaluación que devuelve un valor

Los enunciados son básicamente pasos o instrucciones en un algoritmo, el resultado de la ejecución de un enunciado es la actualización del puntero de instrucción (denominado ensamblador)

Las expresiones no implican y orden de ejecución a primera vista, su propósito es evaluar y devolver un valor. En los lenguajes de programación imperativos, la evaluación de una expresión tiene un orden, pero es solo por el modelo imperativo, pero no es su esencia.

Ejemplos de declaraciones:

for
goto
return
if

(todos ellos implican el avance de la línea (declaración) de ejecución a otra línea)

Ejemplo de expresiones:

2+2

(no implica la idea de ejecución, sino de la evaluación)


¿Qué pasa con los efectos secundarios?
Austin Henley

@AustinHenley no hay ningún requisito para eso. De hecho, una expresión definitivamente puede tener un efecto secundario.
Akangka

1

Declaración ,

Una declaración es un componente de procedimiento a partir del cual se construyen todos los programas de C #. Una declaración puede declarar una variable local o constante, llamar a un método, crear un objeto o asignar un valor a una variable, propiedad o campo.

Una serie de declaraciones rodeadas de llaves forman un bloque de código. Un cuerpo de método es un ejemplo de un bloque de código.

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

Las declaraciones en C # a menudo contienen expresiones. Una expresión en C # es un fragmento de código que contiene un valor literal, un nombre simple o un operador y sus operandos.

Expresión ,

Una expresión es un fragmento de código que se puede evaluar en un solo valor, objeto, método o espacio de nombres. Los dos tipos más simples de expresiones son literales y nombres simples. Un literal es un valor constante que no tiene nombre.

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

Tanto i como s son nombres simples que identifican variables locales. Cuando esas variables se usan en una expresión, el valor de la variable se recupera y se usa para la expresión.


Prefiero escribir if(number >= 0) return true; else return false;o incluso mejor bool? IsPositive(int number) { if(number > 0) return true; else if(number < 0) return false; else return null;}:)
Mahdi Tahsildari

1

Prefiero el significado statementen el sentido lógico formal de la palabra. Es uno que cambia el estado de una o más de las variables en el cálculo, permitiendo que se haga una declaración verdadera o falsa sobre su (s) valor (es).

Supongo que siempre habrá confusión en el mundo de la informática y la ciencia en general cuando se introducen nuevas terminologías o palabras, las palabras existentes se 'reutilizan' o los usuarios ignoran la terminología existente, establecida o 'adecuada' para lo que están describiendo.


1

No estoy realmente satisfecho con ninguna de las respuestas aquí. Miré la gramática de C ++ (ISO 2008) . Sin embargo, tal vez por el bien de la didáctica y la programación, las respuestas podrían ser suficientes para distinguir los dos elementos (aunque la realidad parece más complicada).

Una declaración consta de cero o más expresiones, pero también puede ser otros conceptos del lenguaje. Esta es la forma extendida de Backus Naur para la gramática (extracto de la declaración):

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 los otros conceptos que se consideran declaraciones en C ++.

  • el enunciado de expresión s se explica por sí mismo (un enunciado puede consistir en cero o más expresiones, lea la gramática cuidadosamente, es complicado)
  • casepor ejemplo es una declaración etiquetada
  • las declaraciones de selección son if if/else,case
  • iteración de los estados s son while, do...while,for (...)
  • salto-declaración s son break, continue, return(se puede volver expresión),goto
  • declaración-declaración es el conjunto de declaraciones
  • try-block es una declaración que representa try/catchbloques
  • y podría haber algo más en la gramática

Este es un extracto que muestra la parte de expresiones:

expression:
        assignment-expression
        expression "," assignment-expression
assignment-expression:
        conditional-expression
        logical-or-expression assignment-operator initializer-clause
        throw-expression
  • las expresiones son o contienen a menudo asignaciones
  • condicional expresión (sonidos engañosa) se refiere al uso de los operadores ( +, -, *, /, &, |, &&, ||, ...)
  • tirar-expresión - ¿eh? la throwcláusula también es una expresión

0

Las declaraciones son oraciones gramaticalmente completas. Las expresiones no son. Por ejemplo

x = 5

se lee como "x obtiene 5." Esta es una oración completa. El código

(x + 5)/9.0

lee, "x más 5 todo dividido por 9.0". Esta no es una oración completa. La declaración

while k < 10: 
    print k
    k += 1

Es una oración completa. Observe que el encabezado del bucle no es; "while k <10" es una cláusula subordinante.


whileEs una expresión de algunos lenguajes como Scala. Estás combinando gramática con mecanografía. Mira mi respuesta .
Shelby Moore III

Aquí está el ciclo while en scala: tutorialspoint.com/scala/scala_while_loop.htm El ciclo con su predicado y ningún cuerpo no es una oración gramaticalmente completa. No es una expresión completa. Necesitas el cuerpo para completarlo como una expresión.
ncmathsadist

A whilecon cuerpo sigue siendo una expresión en Scala. También puede ser una declaración si crea efectos secundarios, lo que permite mi respuesta fuertemente rechazada (una expresión también puede ser una declaración). Mi respuesta es la única correcta. Perdón por todos esos lectores que no pueden entender.
Shelby Moore III

¿Qué quieres decir con gramaticalmente completo? En C, (x + 5)/9.0definitivamente puede estar solo como una declaración. Además, si por gramaticalmente completo se refiere a un programa válido, C no permite que las declaraciones se mantengan solas como un solo programa.
Akangka

Gramaticalmente completo: constituye una oración completa.
ncmathsadist

0

Aquí está el resumen de una de las respuestas más simples que encontré.

originalmente respondida por Anders Kaseorg

Una declaración es una línea completa de código que realiza alguna acción, mientras que una expresión es cualquier sección del código que se evalúa como un valor.

Las expresiones se pueden combinar "horizontalmente" en expresiones más grandes utilizando operadores, mientras que las declaraciones solo se pueden combinar "verticalmente" escribiendo una tras otra, o con construcciones de bloques.

Cada expresión se puede usar como una declaración (cuyo efecto es evaluar la expresión e ignorar el valor resultante), pero la mayoría de las declaraciones no se pueden usar como expresiones.

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


0

La base de facto de estos conceptos es:

Expresiones : una categoría sintáctica cuya instancia se puede evaluar a un valor.

Declaración : Una categoría sintáctica cuya instancia puede estar involucrada con las evaluaciones de una expresión y el valor resultante de la evaluación (si corresponde) no está garantizado.

Además del contexto inicial de FORTRAN en las primeras décadas, ambas definiciones de expresiones y declaraciones en la respuesta aceptada son obviamente erróneas:

  • Las expresiones pueden ser operandos no evaluados. Los valores nunca se producen a partir de ellos.
    • Las subexpresiones en evaluaciones no estrictas definitivamente no se pueden evaluar.
      • La mayoría de los lenguajes tipo C tienen las llamadas reglas de evaluación de cortocircuito para omitir condicionalmente algunas evaluaciones de subexpresión sin cambiar el resultado final a pesar de los efectos secundarios.
    • C y algunos lenguajes similares a C tienen la noción de operando no evaluado que incluso puede definirse normativamente en la especificación del lenguaje. Tales construcciones se utilizan para evitar las evaluaciones definitivamente, por lo que la información de contexto restante (por ejemplo, tipos o requisitos de alineación) se puede distinguir estáticamente sin cambiar el comportamiento después de la traducción del programa.
      • Por ejemplo, una expresión utilizada como el operando del sizeofoperador nunca se evalúa.
  • Las declaraciones no tienen nada que ver con las construcciones de línea. Pueden hacer algo más que expresiones, según las especificaciones del lenguaje.
    • Fortran moderna, como el descendiente directo del antiguo FORTRAN, tiene conceptos de ejecutable declaración s y los estados no ejecutables s.
    • Del mismo modo, C ++ define las declaraciones como la subcategoría de nivel superior de una unidad de traducción. Una declaración en C ++ es una declaración. (Esto no es cierto en C.) También hay declaraciones de expresión como las declaraciones ejecutables de Fortran.
    • Para el interés de la comparación con expresiones, solo importan las declaraciones "ejecutables". Pero no puede ignorar el hecho de que las declaraciones ya están generalizadas como construcciones que forman las unidades de traducción en estos idiomas imperativos. Entonces, como puede ver, las definiciones de la categoría varían mucho. La (probablemente) única propiedad común que se conserva entre estos idiomas es que se espera que las declaraciones se interpreten en el orden léxico (para la mayoría de los usuarios, de izquierda a derecha y de arriba a abajo).

(Por cierto, quiero agregar [cita requerida] a esa respuesta con respecto a los materiales sobre C porque no puedo recordar si DMR tiene tales opiniones. Parece que no, de lo contrario no debería haber razones para preservar la duplicación de funcionalidad en el diseño de C : en particular, el operador de coma frente a las declaraciones.)

(La siguiente justificación no es la respuesta directa a la pregunta original, pero creo que es necesario aclarar algo que ya se respondió aquí).

Sin embargo, es dudoso que necesitemos una categoría específica de "declaraciones" en lenguajes de programación de propósito general:

  • No se garantiza que las declaraciones tengan más capacidades semánticas sobre las expresiones en diseños habituales.
    • Muchos idiomas ya han abandonado con éxito la noción de declaraciones para obtener diseños generales limpios, ordenados y consistentes.
      • En dichos lenguajes, las expresiones pueden hacer todo lo que pueden hacer las declaraciones de estilo antiguo: simplemente descarte los resultados no utilizados cuando se evalúan las expresiones, ya sea dejando los resultados explícitamente sin especificar (por ejemplo, en el esquema R n RS) o teniendo un valor especial (como valor de un tipo de unidad) no producible a partir de evaluaciones de expresión normal.
      • Las reglas de orden léxico de evaluación de expresiones pueden reemplazarse por un operador de control de secuencia explícito (por ejemplo, beginen el esquema) o el azúcar sintáctico de estructuras monádicas.
      • Las reglas de orden léxico de otros tipos de "declaraciones" pueden derivarse como extensiones sintácticas (usando macros higiénicas, por ejemplo) para obtener la funcionalidad sintáctica similar. (Y en realidad puede hacer más ).
    • Por el contrario, las declaraciones no pueden tener tales reglas convencionales, porque no se componen en la evaluación: simplemente no existe una noción tan común de "evaluación de la subenunciación". (Incluso si existe, dudo que pueda haber algo mucho más que copiar y pegar de las reglas existentes de evaluación de expresiones).
      • Por lo general, los enunciados de preservación de idiomas también tendrán expresiones para expresar cálculos, y existe una subcategoría de nivel superior de los enunciados conservados en las evaluaciones de expresión para esa subcategoría. Por ejemplo, C ++ tiene la llamada declaración de expresión como subcategoría, y usa las reglas de evaluación de expresión de valor descartado para especificar los casos generales de evaluaciones de expresión completa en dicho contexto. Algunos lenguajes como C # optan por refinar los contextos para simplificar los casos de uso, pero aumentan más las especificaciones.
  • Para los usuarios de lenguajes de programación, la importancia de las declaraciones puede confundirlos aún más.
    • La separación de las reglas de expresiones y declaraciones en los idiomas requiere más esfuerzo para aprender un idioma.
    • La ingenua interpretación del orden léxico oculta la noción más importante: la evaluación de la expresión. (Esto es probablemente lo más problemático sobre todo).
      • Incluso las evaluaciones de expresiones completas en las declaraciones son limitantes con el orden léxico, las subexpresiones no lo son (necesariamente). En última instancia, los usuarios deben aprender esto además de cualquier regla asociada a las declaraciones. (Considere cómo hacer que un novato obtenga el punto que no ++i + ++itiene sentido en C.)
      • Algunos lenguajes como Java y C # limitan aún más el orden de las evaluaciones de subexpresiones para permitir la ignorancia de las reglas de evaluación. Puede ser aún más problemático.
        • Esto parece demasiado especificado para los usuarios que ya han aprendido la idea de la evaluación de expresiones. También alienta a la comunidad de usuarios a seguir el modelo mental borroso del diseño del lenguaje.
        • Aumenta aún más la especificación del lenguaje.
        • Es perjudicial para la optimización al perder la expresividad del no determinismo en las evaluaciones, antes de que se introduzcan primitivas más complicadas.
      • Algunos lenguajes como C ++ (en particular, C ++ 17) especifican contextos más sutiles de las reglas de evaluación, como un compromiso de los problemas anteriores.
        • Aumenta mucho la especificación del lenguaje.
        • Esto va totalmente en contra de la simplicidad para los usuarios promedio ...

Entonces, ¿por qué las declaraciones? De todos modos, la historia ya es un desastre. Parece que la mayoría de los diseñadores de idiomas no toman su decisión con cuidado.

Peor aún, incluso les da a algunos entusiastas del sistema de tipos (que no están lo suficientemente familiarizados con la historia de PL) algunas ideas erróneas de que los sistemas de tipos deben tener cosas importantes que hacer con los diseños más esenciales de las reglas sobre la semántica operativa.

En serio, el razonamiento dependiendo de los tipos no es tan malo en muchos casos, pero particularmente no es constructivo en este caso especial. Incluso los expertos pueden arruinar las cosas.

Por ejemplo, alguien enfatiza la naturaleza de escribir bien como el argumento central contra el tratamiento tradicional de las continuaciones no delimitadas . Aunque la conclusión es algo razonable y las ideas sobre las funciones compuestas están bien ( pero aún son demasiado ingenuas para el sentido ), este argumento no es sólido porque ignora totalmente el enfoque de "canal lateral" en la práctica como _Noreturn any_of_returnable_types(en C11) para codificar Falsum. Y estrictamente hablando, una máquina abstracta con un estado impredecible no es idéntica a "una computadora averiada".


0

En un lenguaje de programación orientado a sentencias, un bloque de código se define como una lista de sentencias. En otras palabras, una declaración es una sintaxis que puede poner dentro de un bloque de código sin causar un error de sintaxis.

Wikipedia define la declaración de la palabra de manera similar

En la programación de computadoras, una declaración es una unidad sintáctica de un lenguaje de programación imperativo que expresa alguna acción a realizar. Un programa escrito en dicho lenguaje está formado por una secuencia de una o más declaraciones

Observe la última declaración. (aunque "un programa" en este caso es técnicamente incorrecto porque C y Java rechazan un programa que no consiste en nada de declaraciones).

Wikipedia define la expresión de la palabra como

Una expresión en un lenguaje de programación es una entidad sintáctica que puede evaluarse para determinar su valor.

Sin embargo, esto es falso, porque en Kotlin throw new Exception("")es una expresión, pero cuando se evalúa, simplemente arroja una excepción, sin devolver ningún valor.

En un lenguaje de programación estáticamente tipado, cada expresión tiene un tipo. Sin embargo, esta definición no funciona en un lenguaje de programación de tipo dinámico.

Personalmente, defino una expresión como una sintaxis que se puede componer con un operador o llamadas a funciones para producir una expresión más grande. Esto es realmente similar a la explicación de la expresión de Wikipedia:

Es una combinación de una o más constantes, variables, funciones y operadores que el lenguaje de programación interpreta (de acuerdo con sus reglas particulares de precedencia y asociación) y calcula para producir ("devolver", en un entorno con estado) otro valor

Pero, el problema está en el lenguaje de programación C, dada una función execute, algo como esto:

void executeSomething(void){
    return;
}

¿Es executeSomething()una expresión o es una declaración? Según mi definición, es una declaración porque, tal como se define en la gramática de referencia C de Microsoft,

No puede usar el valor (inexistente) de una expresión que tenga el tipo void de ninguna manera, ni puede convertir una expresión vacía (por conversión implícita o explícita) a cualquier tipo excepto void

Pero la misma página indica claramente que dicha sintaxis es una expresión.


-6

Para mejorar y validar mi respuesta anterior, las definiciones de los términos del lenguaje de programación deben explicarse a partir de la teoría del tipo de informática cuando corresponda.

Una expresión tiene un tipo distinto del tipo Inferior, es decir, tiene un valor. Una declaración tiene el tipo Unidad o Fondo.

De esto se deduce que una declaración solo puede tener algún efecto en un programa cuando crea un efecto secundario, porque no puede devolver un valor o solo devuelve el valor del tipo de Unidad que no es asignable (en algunos idiomas, por ejemplo, una C void) o (como en Scala) se pueden almacenar para una evaluación retrasada de la declaración.

Obviamente, a @pragmao a /*comment*/no tienen tipo y, por lo tanto, se diferencian de las declaraciones. Por lo tanto, el único tipo de declaración que no tendría efectos secundarios sería una no operación. La no operación solo es útil como marcador de posición para futuros efectos secundarios. Cualquier otra acción debido a una declaración sería un efecto secundario. Una vez más, una sugerencia del compilador, por ejemplo @pragma, no es una declaración porque no tiene tipo.


2
La distinción no tiene nada que ver con el tipo de expresiones. Las declaraciones sintácticamente definidas no tienen ningún tipo en muchos idiomas. Aunque no estoy en contra de asignar un tipo en tales términos en teoría, los diferentes tratamientos en @pragmao /*comment*/son lógicamente inconsistentes.
FrankHB

-11

Más precisamente, una declaración debe tener un "efecto secundario" (es decir, ser imperativo ) y una expresión debe tener un tipo de valor (es decir, no el tipo inferior).

El tipo de enunciado es el tipo de unidad, pero debido a que la unidad del teorema de detención es ficción, digamos el tipo de fondo .


Voidno es precisamente el tipo inferior (no es el subtipo de todos los tipos posibles). Existe en idiomas que no tienen un sistema de tipo de sonido completo . Eso puede sonar como una declaración snob, pero la integridad , como las anotaciones de variación, son críticas para escribir software extensible.

Veamos qué dice Wikipedia sobre este asunto.

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

En la programación de computadoras, una declaración es el elemento independiente más pequeño de un lenguaje de programación imperativo que expresa alguna acción a realizar.

Muchos lenguajes (por ejemplo, C) hacen una distinción entre declaraciones y definiciones, con una declaración que solo contiene código ejecutable y una definición que declara un identificador, mientras que una expresión evalúa solo un valor.


55
Una declaración no necesita tener un efecto secundario. Por ejemplo, en python passes una declaración. Es un no-op, y no evalúa nada.
Matthew Schinckel

99
-1 Esto está mal. Una declaración no tiene que tener un efecto secundario. Consulte la sección 1.5 de la Especificación del lenguaje C # . No sólo no se especifique que los estados deben tener efectos secundarios, pero también enumera varias declaraciones que pueden tener no hay efectos secundarios.
NullUserException

2
@NullUserException Leí esa sección. Las declaraciones de declaración, expresión, selección, iteración y salto pueden crear efectos secundarios. Pero si hay una expresión RT, entonces no es una declaración. Me doy cuenta de que la especificación es equiparar expresiones con declaraciones, pero esta pregunta pedía la diferencia entre ellas. Entonces, o la pregunta no tiene respuesta, o está tomando la especificación C # demasiado literalmente. La respuesta más votada es tratar de decir lo que hice. Pero "hace algo" no tiene sentido. "efecto secundario" es la forma significativa de decir "hace algo". Tenemos que pensar, no solo regurgitar.
Shelby Moore III

13
@ShelbyMooreIII Tienes razón. La documentación oficial es incorrecta . Marc Gravell y Jon Skeet, que posiblemente sean los carteles de C # más respetados activos en SO fuera de Eric Lippert, están equivocados . Yo, y todos los demás que lo rechazamos y dejamos comentarios explicando nuestra posición, estamos equivocados . Tienes razón. Claramente eres la única persona que sabe de qué están hablando, ya que eres mucho más inteligente que todo el resto de SO.
NullUserException

3
Conocer la definición precisa de conceptos como declaración, expresión, conversión, conversión, etc. tiene un impacto cero en el 99.999% de las tareas de programación cotidianas. Piensa en eso . Además: a la mayoría de las personas no les importan Haskell y Scala.
NullUserException
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.