Выражение в сравнении с выражением

Я прошу в отношении С#, но я предполагаю, что это то же самое на большинстве других языков.

Есть ли у кого-то хорошее определение выражений и утверждений и каковы различия?

Ответ 1

Выражение: Что-то, что оценивает значение. Пример: 1 + 2/x
Утверждение: Строка кода, которая что-то делает. Пример: GOTO 100

В самых ранних языках программирования общего назначения, таких как FORTRAN, различие было кристально ясным. В FORTRAN оператор был одной единицей исполнения, то, что вы сделали. Единственная причина, по которой его не называли "линией", заключалась в том, что иногда он занимал несколько строк. Выражение само по себе ничего не может сделать... вы должны были присвоить его переменной.

1 + 2 / X

это ошибка в Фортране, потому что она ничего не делает. Вы должны были что-то сделать с этим выражением:

X = 1 + 2 / X

У Фортрана не было грамматики в том виде, в каком мы ее знаем сегодня - эта идея была изобретена вместе с формой Бэкуса-Наура (BNF), как часть определения Алгола-60. В этот момент семантическое различие ("иметь значение" и "делать что-то") было закреплено в синтаксисе: один вид фразы был выражением, а другой - выражением, и синтаксический анализатор мог их различать.

Разработчики более поздних языков размыли различие: они позволяли синтаксическим выражениям делать что-то, и они допускали синтаксические выражения, которые имели значения. Самый ранний популярный пример языка, который до сих пор сохранился, - C. Разработчики C поняли, что никакого вреда не было, если вам позволили оценить выражение и выбросить результат. В C каждое синтаксическое выражение может быть преобразовано в утверждение, просто ставя точку с запятой в конце:

1 + 2 / x;

- абсолютно законное выражение, хотя абсолютно ничего не произойдет. Точно так же в C выражение может иметь побочные эффекты - оно может что-то изменить.

1 + 2 / callfunc(12);

потому что callfunc может просто сделать что-то полезное.

Как только вы позволите любому выражению быть оператором, вы также можете разрешить оператор присваивания (=) внутри выражений. Вот почему C позволяет вам делать такие вещи, как

callfunc(x = 2);

Это вычисляет выражение x = 2 (присваивая значение от 2 до x), а затем передает его (2) в функцию callfunc.

Это размывание выражений и операторов происходит во всех C-производных (C, C++, С# и Java), которые все еще имеют некоторые операторы (например, while), но которые позволяют использовать практически любое выражение в качестве оператора ( в С# в качестве операторов могут использоваться только выражения присваивания, вызова, приращения и декремента; см. ответ скотта Вишневского).

Наличие двух "синтаксических категорий" (так называемых технических терминов для выражений и выражений) может привести к дублированию усилий. Например, C имеет две условные формы, форму заявления

if (E) S1; else S2;

и форма выражения

E ? E1 : E2

А иногда люди хотят дублирования, которого нет: в стандартном C, например, только оператор может объявить новую локальную переменную &— но эта возможность достаточно полезна, чтобы Компилятор GNU C предоставляет расширение GNU, которое позволяет выражению также объявлять локальную переменную.

Проектировщикам других языков не понравился такой тип дублирования, и они рано поняли, что если выражения могут иметь побочные эффекты, а также значения, то синтаксическое различие между утверждениями и выражениями не так уж и полезно - поэтому они избавились от него, Haskell, Icon, Lisp и ML - все языки, которые не имеют синтаксических операторов - они имеют только выражения. Даже структурированные циклы класса и условные формы считаются выражениями, и они имеют значения - но не очень интересные.

Ответ 2

Я хотел бы сделать небольшую поправку на ответ Джоэля выше.

С# не позволяет использовать все выражения в качестве операторов. В частности, в качестве операторов могут использоваться выражения присваивания, вызова, приращения и сокращения.

Например, компилятор С# будет указывать следующий код как синтаксическую ошибку:

1 + 2;

Ответ 3

  • выражение - это все, что дает значение: 2 + 2
  • оператор является одним из основных "блоков" выполнения программы.

Заметим, что в C "=" фактически является оператором, который выполняет две вещи:

  • возвращает значение подвыражения правой руки.
  • копирует значение подвыражения правой руки в переменную с левой стороны.

Здесь выдержка из грамматики ANSI C. Вы можете видеть, что C не имеет много разных видов операторов... большинство операторов в программе являются операторами выражений, то есть выражением с точкой с запятой в конце.

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

Ответ 4

Выражение - это то, что возвращает значение, в то время как оператор не делает.

Примеры:

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

Большая сделка между двумя заключается в том, что вы можете комбинировать выражения вместе, тогда как утверждения не могут быть связаны цепями.

Ответ 5

Вы можете найти это на wikipedia, но выражения оцениваются до некоторого значения, в то время как операторы не имеют оцененного значения.

Таким образом, выражения могут использоваться в операторах, но не наоборот.

Обратите внимание, что некоторые языки (такие как Lisp, и я считаю, что Ruby и многие другие) не различают оператор vs expression... на таких языках, все является выражением и может быть привязано к другим выражениям.

Ответ 6

Для объяснения важных различий в способности к компоновке (цепочки) выражений против операторов, моя любимая ссылка - статья о награде Джона Бэкуса Тьюринга, Можно ли освободить программирование от стиль фон Неймана?.

Императивные языки (Fortran, C, Java,...) подчеркивают утверждения для структурирования программ и имеют выражения как своего рода последушие. Функциональные языки подчеркивают выражения. Чисто функциональные языки имеют такие мощные выражения, которые могут быть полностью исключены.

Ответ 7

Выражения могут быть оценены для получения значения, тогда как операторы не возвращают значение (они имеют тип void).

Выражения вызова функций также могут считаться утверждениями, но если среда выполнения не имеет специальной встроенной переменной, чтобы удерживать возвращаемое значение, то нет способа получить ее.

Ориентированные на инструкцию языки требуют, чтобы все процедуры были списком операторов. Языками, ориентированными на выражения, которые, вероятно, являются все функциональные языки, являются списки выражений или в случае LISP, длинное S-выражение, которое представляет список выражений.

Хотя оба типа могут быть составлены, большинство выражений могут быть составлены произвольно до тех пор, пока типы совпадают. Каждый тип заявления имеет свой собственный способ составления других утверждений, если они могут это сделать. Операторы Foreach и if требуют либо одного статута, либо все подчиненные инструкции идут в блоке оператора один за другим, если только подпункты не разрешают его собственные подстанции.

Заявления также могут включать выражения, в которых выражение действительно не содержит каких-либо утверждений. Тем не менее, одним из исключений было бы выражение лямбда, которое представляет собой функцию, и поэтому может включать в себя все, что может быть включено в функцию, если только язык не разрешает только ограниченные lambdas, такие как lambdas с одним выражением Python.

В языке на основе выражения все, что вам нужно, - это одно выражение для функции, поскольку все структуры управления возвращают значение (многие из них возвращают NIL). Нет необходимости в операторе return, поскольку последнее выражение в функции является возвращаемым значением.

Ответ 8

Просто: выражение оценивает значение, утверждение не имеет.

Ответ 9

Некоторые вещи, касающиеся языков, основанных на выражениях:


Самое главное: все возвращает значение


Нет разницы между фигурными скобками и фигурными скобками для разграничения кодовых блоков и выражений, поскольку все является выражением. Однако это не мешает лексическому охвату: локальная переменная может быть определена для выражения, в котором содержится его определение, и всех утверждений, содержащихся внутри этого, например.


В языке на основе выражения все возвращает значение. Сначала это может быть немного странно - Что возвращает (FOR i = 1 TO 10 DO (print i))?

Несколько простых примеров:

  • (1) возвращает 1
  • (1 + 1) возвращает 2
  • (1 == 1) возвращает TRUE
  • (1 == 2) возвращает FALSE
  • (IF 1 == 1 THEN 10 ELSE 5) возвращает 10
  • (IF 1 == 2 THEN 10 ELSE 5) возвращает 5

Несколько более сложных примеров:

  • Некоторые вещи, например, некоторые вызовы функций, на самом деле не имеют значимого значения для возврата (Вещи, которые производят только побочные эффекты?). Вызов OpenADoor(), FlushTheToilet() или TwiddleYourThumbs() вернет какое-то обычное значение, например OK, Done или Success.
  • Когда несколько несвязанных выражений оцениваются в одном более крупном выражении, значение последнего объекта, оцененного в большом выражении, становится значением большого выражения. Чтобы принять пример (FOR i = 1 TO 10 DO (print i)), значение цикла for равно "10", оно вызывает выражение (print i), которое оценивается 10 раз, каждый раз возвращая я в виде строки. Последнее время через возврат 10, наш окончательный ответ

Часто требуется небольшое изменение мышления, чтобы максимально использовать язык, основанный на выражениях, поскольку тот факт, что все является выражением, позволяет "встроить" много вещей

В качестве быстрого примера:

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

является вполне допустимой заменой для

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

В некоторых случаях макет, который позволяет использовать код на основе выражений, намного более естественен для меня

Конечно, это может привести к безумию. В рамках проекта хобби на языке сценариев на языке выражений, который называется MaxScript, мне удалось создать эту линию монстров

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
)

Ответ 10

Оператор представляет собой частный случай выражения, один с типом void. Тенденция к языку рассматривать заявления по-разному часто вызывает проблемы, и было бы лучше, если бы они были должным образом обобщены.

Например, в С# у нас есть очень полезный Func<T1, T2, T3, TResult> перегруженный набор общих делегатов. Но мы также должны иметь соответствующий набор Action<T1, T2, T3>, а программирование более высокого порядка общего назначения постоянно должно дублироваться, чтобы справиться с этой неудачной бифуркацией.

Тривиальный пример - функция, которая проверяет, является ли ссылка нулевой до вызова другой функции:

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

Может ли компилятор иметь дело с возможностью TResult быть void? Да. Все, что ему нужно сделать, это потребовать, чтобы за возвратом последовало выражение типа void. Результат default(void) будет иметь тип void, и передаваемый func должен иметь вид Func<TValue, void> (который был бы эквивалентен Action<TValue>).

В ряде других ответов подразумевается, что вы не можете связать выражения, подобные выражениям, но я не уверен, откуда эта идея. Мы можем думать о ;, который появляется после операторов как двоичный инфиксный оператор, беря два выражения типа void и объединяя их в одно выражение типа void.

Ответ 11

Заявления → Инструкции следовать последовательно
Выражения → Оценка, возвращающая значение

Заявления в основном похожи на шаги или инструкции в алгоритме, результатом выполнения оператора является актуализация указателя инструкции (так называемого в ассемблере)

Выражения не подразумевают и порядок выполнения с первого взгляда, их целью является оценка и возврат значения. В императивных языках программирования оценка выражения имеет порядок, но это только из-за императивной модели, но это не их сущность.

Примеры выражений:

for
goto
return
if

(все они подразумевают продвижение строки (утверждения) выполнения в другую строку)

Пример выражений:

2+2

(это не подразумевает идею исполнения, а оценки)

Ответ 12

Заявления являются грамматически полными предложениями. Выражений нет. Например

x = 5

читается как "x получает 5." Это полное предложение. Код

(x + 5)/9.0

читает: "x плюс 5 все разделены на 9.0". Это не полное предложение. Утверждение

while k < 10: 
    print k
    k += 1

является полным предложением. Обратите внимание, что заголовок цикла не является; "в то время как k < 10" является подчиняющим условием.

Ответ 13

Statement,

Оператор - это процедурный строительный блок, из которого создаются все программы на С#. Оператор может объявлять локальную переменную или константу, вызывать метод, создавать объект или присваивать значение переменной, свойству или полю.

Ряд утверждений, окруженных фигурными фигурными скобками, образуют блок кода. Тело метода является одним из примеров кода-кода.

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

Заявления в С# часто содержат выражения. Выражение в С# является фрагментом кода, содержащим буквальное значение, простое имя или оператор и его операнды.

Выражение,

Выражение - это фрагмент кода, который может быть оценен для одного значения, объекта, метода или пространства имен. Двумя простейшими типами выражений являются литералы и простые имена. Литерал - это постоянное значение, которое не имеет имени.

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

И я и s - простые имена, идентифицирующие локальные переменные. Когда эти переменные используются в выражении, значение переменной извлекается и используется для выражения.

Ответ 14

Я предпочитаю значение statement в формальном логическом смысле слова. Это тот, который изменяет состояние одной или нескольких переменных в вычислении, позволяя сделать истинное или ложное утверждение относительно их значений.

Я предполагаю, что всегда будет путаница в вычислительном мире и науке вообще при введении новой терминологии или слов, существующие слова "перепрофилируются", или пользователи не знают существующей, установленной или "правильной" терминологии для того, описывающая

Ответ 15

Я не очень удовлетворен ни одним из ответов здесь. Я посмотрел грамматику на С++ (ISO 2008). Однако, возможно, ради дидактики и программирования ответы могут быть достаточными, чтобы отличить два элемента (реальность выглядит более сложной, хотя).

Оператор состоит из нуля или более выражений, но также может быть и другими языковыми понятиями. Это форма Extended Backus Naur для грамматики (выдержка для утверждения):

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

Мы можем видеть другие понятия, которые рассматриваются в С++.

  • выражения-выражения самоочевидны (оператор может состоять из нуля или более выражений, внимательно читать грамматику, это сложно)
  • case например, это обозначенный оператор
  • Выводные выражения if if/else, case
  • Итерационные утверждения: while, do...while, for (...)
  • jump-statements: break, continue, return (может возвращать выражение), goto
  • statement-statement - это набор объявлений
  • try-block - это оператор, представляющий try/catch blocks
  • и может быть еще несколько ниже грамматики

Это выдержка, показывающая часть выражений:

expression:
        assignment-expression
        expression "," assignment-expression
assignment-expression:
        conditional-expression
        logical-or-expression assignment-operator initializer-clause
        throw-expression
  • выражения содержат или содержат часто присваивания
  • условное выражение (звучит обманчиво) относится к использованию операторов (+, -, *, /, &, |, &&, ||...)
  • throw-expression - э-э? предложение throw также является выражением

Ответ 16

Вот итог одного из самых простых ответов, которые я нашел.

Первоначально Ответал Anders Kaseorg

Оператор представляет собой полную строку кода, которая выполняет какое-либо действие, а выражение - это любой раздел кода, который оценивает значение.

Выражения могут быть объединены "горизонтально" в более крупные выражения с использованием операторов, тогда как утверждения могут объединяться только "по вертикали", записывая один за другим или с блочными конструкциями.

Каждое выражение может использоваться как оператор (эффект которого заключается в оценке выражения и игнорировании результирующего значения), но большинство операторов не могут использоваться как выражения.

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

Ответ 17

Фактическая основа этих концепций:

Выражения: синтаксическая категория, экземпляр которой можно оценить как значение.

Утверждение: синтаксическая категория, экземпляр которой может быть связан с оценками выражения и результирующее значение оценки (если есть) не гарантировано доступно.

Помимо самого начального контекста ФОРТРАНА в первые десятилетия, оба определения выражений и утверждений в принятом ответе явно неверны:

  • Выражения могут быть неоцененными операндами. Ценности никогда не производятся от них.
    • Субэкспрессия в нестрогих оценках может быть определенно недооценена.
      • Большинство C-подобных языков имеют так называемые правила оценки короткого замыкания, чтобы условно пропускать некоторые оценки подвыражения, не изменяя конечный результат, несмотря на побочные эффекты.
    • C и некоторые C-подобные языки имеют понятие неоцененного операнда, который может быть даже нормативно определен в спецификации языка. Такие конструкции используются, чтобы определенно избегать оценок, поэтому оставшаяся контекстная информация (например, типы или требования выравнивания) может быть статически различена без изменения поведения после перевода программы.
      • Например, выражение, используемое в качестве операнда оператора sizeof, никогда не вычисляется.
  • Утверждения не имеют ничего общего с линейными конструкциями. Они могут делать что-то большее, чем выражения, в зависимости от языковых спецификаций.
    • Современный Фортран, как прямой потомок старого Фортрана, имеет концепции исполняемых операторов и неисполнимых операторов.
    • Точно так же C++ определяет объявления как подкатегорию верхнего уровня единицы перевода. Объявление в C++ является утверждением. (Это не так в C.) Существуют также операторы выражений, такие как исполняемые операторы Fortran.
    • Для сравнения выражений важны только "исполняемые" операторы. Но вы не можете игнорировать тот факт, что операторы уже обобщены, чтобы быть конструкциями, формирующими единицы перевода на таких императивных языках. Итак, как вы можете видеть, определения категории сильно различаются. (Возможно) единственное оставшееся общее свойство, сохраняемое среди этих языков, заключается в том, что операторы должны интерпретироваться в лексическом порядке (для большинства пользователей слева направо и сверху вниз).

(Кстати, я хочу добавить [цитата нужна] к этому ответу относительно материалов о C, потому что я не могу вспомнить, есть ли у DMR такие мнения. Кажется, нет, в противном случае не должно быть никаких причин сохранять дублирование функциональности в дизайне C: в частности, оператор запятой против операторов.)

(Следующее обоснование не является прямым ответом на первоначальный вопрос, но я считаю необходимым уточнить кое-что, на что здесь уже дан ответ.)

Тем не менее, сомнительно, что нам нужна особая категория "операторов" в языках программирования общего назначения:

  • Утверждения не гарантируют, чтобы иметь больше семантических возможностей по сравнению с выражениями в обычных проектах.
    • Многие языки уже успешно отказались от понятия утверждений, чтобы получить чистый, аккуратный и согласованный общий дизайн.
      • В таких языках выражения могут делать все, что могут делать операторы старого стиля: просто отбрасывать неиспользуемые результаты при оценке выражений, либо оставляя результаты явно неопределенными (например, в схеме R n RS)), либо имея специальное значение ( как значение типа единицы), не может быть получено из вычислений нормальных выражений.
      • Правила лексического порядка вычисления выражений могут быть заменены оператором явного управления последовательностями (например, begin на схеме) или синтаксическим сахаром монадных структур.
      • Правила лексического порядка для других видов "операторов" могут быть получены в виде синтаксических расширений (например, с использованием гигиенических макросов) для получения аналогичной синтаксической функциональности. (И он действительно может сделать больше.)
    • Напротив, у заявлений не может быть таких обычных правил, потому что они не составляют оценку: просто нет такого общего понятия "оценка подзаголовка". (Даже если таковые имеются, я сомневаюсь, что может быть что-то намного большее, чем копирование и вставка из существующих правил оценки выражений.)
      • Как правило, операторы, сохраняющие языки, также имеют выражения для выражения вычислений, и существует подкатегория верхнего уровня операторов, сохраняемая для вычислений выражений для этой подкатегории. Например, C++ имеет так называемый оператор выражения в качестве подкатегории и использует правила оценки выражения с отброшенными значениями для определения общих случаев оценки полного выражения в таком контексте. Некоторые языки, такие как С#, выбирают для уточнения контекстов, чтобы упростить варианты использования, но это больше раздувает спецификацию.
  • Для пользователей языков программирования значение утверждений может еще больше запутать их.
    • Разделение правил выражений и утверждений на языках требует больше усилий для изучения языка.
    • Наивная интерпретация лексического порядка скрывает более важное понятие: оценка выражения. (Это, вероятно, наиболее проблематично из всех.)
      • Даже вычисления полных выражений в выражениях ограничены лексическим порядком, а подвыражения - нет (обязательно). Пользователи должны в конечном итоге изучить это помимо любых правил, связанных с утверждениями. (Подумайте, как заставить новичка понять, что ++i + ++i не имеет смысла в C.)
      • Некоторые языки, такие как Java и С#, еще более ограничивают порядок вычислений подвыражений, чтобы разрешить игнорирование правил оценки. Это может быть еще более проблематичным.
        • Это кажется чрезмерным для пользователей, которые уже изучили идею оценки выражений. Это также побуждает сообщество пользователей следовать размытой ментальной модели языкового дизайна.
        • Это еще больше расширяет спецификацию языка.
        • Это вредно для оптимизации, так как пропускает выразительность недетерминированности в оценках, прежде чем вводятся более сложные примитивы.
      • Некоторые языки, такие как C++ (в частности, C++ 17), задают более тонкий контекст правил оценки в качестве компромисса вышеуказанных проблем.
        • Это сильно раздувает спецификацию языка.
        • Это полностью противоречит простоте для обычных пользователей...

Так почему заявления? Во всяком случае, история уже беспорядок. Кажется, что большинство языковых дизайнеров не принимают свой выбор тщательно.

Хуже того, он даже дает некоторым энтузиастам систем типов (которые недостаточно знакомы с историей PL) некоторые заблуждения о том, что системы типов должны иметь важные вещи, связанные с более существенными разработками правил операционной семантики.

Серьезно, рассуждение в зависимости от типов не так уж плохо во многих случаях, но особенно неконструктивно в этом особом. Даже эксперты могут все испортить.

Например, кто-то подчеркивает, что типизирующий характер является главным аргументом против традиционного подхода к неограниченным продолжениям. Хотя этот вывод несколько обоснован, и понимание составных функций в порядке (, но все же слишком наивно для сути), этот аргумент не является обоснованным, поскольку на практике он полностью игнорирует подход "побочного канала", такой как _Noreturn any_of_returnable_types (в C11) для кодирования Falsum. И, строго говоря, абстрактная машина с непредсказуемым состоянием не идентична "разбитому компьютеру".

Ответ 18

Чтобы улучшить и подтвердить мой предыдущий ответ, определения терминов языка программирования должны быть объяснены, если это применимо, в теории типов компьютерных наук.

Выражение имеет тип, отличный от типа Bottom, т.е. имеет значение. Оператор имеет тип Unit или Bottom.

Из этого следует, что оператор может иметь какой-либо эффект только в программе, когда он создает побочный эффект, поскольку он либо не может вернуть значение, либо возвращает только значение типа Unit, которое либо не назначается (в некоторые языки, такие как C void) или (например, в Scala), могут храниться для отложенной оценки оператора.

Очевидно, что a @pragma или /*comment*/ не имеют типа и, следовательно, отличаются от операторов. Таким образом, единственным типом утверждения, которое не было бы побочных эффектов, было бы нерабочее. Неиспользование полезно только в качестве заполнителя для будущих побочных эффектов. Любые другие действия, связанные с выражением, будут побочным эффектом. Снова подсказка компилятора, например. @pragma, не является утверждением, потому что он не имеет типа.

Ответ 19

В точности, оператор должен иметь "побочный эффект" (т.е. обязательно), а выражение должно иметь значение (т.е. не нижний тип).

тип оператора - это тип единицы измерения, но из-за модуля теоремы Halting это вымысел, поэтому скажем нижний тип.


Void не является точно нижним типом (это не подтип всех возможных типов). Он существует на языках, которые не имеют полностью звуковой системы типа. Это может показаться снобистским выражением, но полнота такая как аннотации вариаций, имеет решающее значение для написания расширяемого программного обеспечения.

Посмотрите, что Wikipedia может сказать по этому вопросу.

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

В компьютерном программировании оператор является наименьшим автономным элементом языка императивного, который выражает какое-либо действие.

Многие языки (например, C) делают различие между операторами и определениями, причем оператор содержит только исполняемый код и определение, объявляющее идентификатор, в то время как выражение оценивает только значение.