Выражение против утверждения


432

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

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


4
Я нахожу ответ, который вы выбрали, неоднозначным. Выражение также что-то делает - оно оценивает значение. Я дал однозначный ответ.
Шелби Мур III

4
@ShelbyMooreIII - не однозначно, а также неправильно. Принятый ответ сформулирован неформально, но эта формулировка облегчает понимание - и, самое главное, значение, которое он передает, является точным.
Джастин Морган

@JustinMorgan К сожалению, определения в принятом ответе также явно неверны («оценивает значение» / «строка кода») для большинства современных языков, включая C-подобные: выражения могут использоваться в неоцененных контекстах, а операторы ничего не имеют делать с линиями. Даже если есть некоторые объяснения, короткий ответ сбивает с толку и вводит в заблуждение.
FrankHB

Ответы:


521

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

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

1 + 2 / X

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

X = 1 + 2 / X

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

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

1 + 2 / x;

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

1 + 2 / callfunc(12);

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

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

callfunc(x = 2);

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

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

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

if (E) S1; else S2;

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

E ? E1 : E2

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

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


9
Если я не ошибаюсь в вашей интерпретации здесь, вы, похоже, утверждаете, что "(setf (third foo) 'goose)" является выражением, а не утверждением, поскольку это Лисп, который "не имеет выражений", и потому что Lisp более чем на десять лет старше C, который был «самым ранним популярным языком, который стирает границы [между выражениями и утверждениями]». Не могли бы вы объяснить детали этого для меня?
cjs

2
@ Курт Сэмпсон, ты задавал это как отдельный вопрос?
Келли С. Френч

5
Если я не ошибаюсь, callfunc(x = 2);переходит xна callfuncнет 2. Если xэто поплавок, callfunc(float)будет называться, а не callfunc(int). И в C ++, если вы передаете x=yк funcи funcпринимает ссылку и изменяет его, она меняется x, не y.
Габриэль

В ответе выше написано, что "Haskell, ... все языки, которые не имеют синтаксических операторов - они имеют только выражения". Мне любопытно, почему whereпредложение в haskell считается выражением, а не утверждением. learnyouahaskell.com/syntax-in-functions#where
skgbanga

@skgbanga Я считаю, whereчто на самом деле это часть объявления функции, а не выражение или утверждение.
Akangka

22
  • выражение - это все, что дает значение: 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


2
Неверная логика в том, что такое утверждение. Декларативная программа также может выполняться, но декларативная программа не имеет операторов. Заявление является и делает "побочные эффекты" , то есть является обязательным. ср мой ответ .
Шелби Мур III

15

Выражение - это то, что возвращает значение, а выражение - нет.

Например:

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

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


6
Конечно, заявления могут быть прикованы цепью. {stmt1; stmt2; stmt3;} является цепочкой, а также является (составным) оператором.
Хью Аллен

5
foo.voidFunc(1);является выражением со значением void. whileи ifявляются заявлениями.
tzot

Мне любопытно, чтобы не было цепочек утверждений. Было бы что-то вроде "if (x> 1) return;" считаться цепочкой двух утверждений вместе?
Саймон Тьюси

1
@SimonTewsi Я считаю, что returnсчитается подзаголовком.
RastaJedi

1
@SimonTewsi Здесь оператор return неявно находится внутри блока оператора if, поэтому он является частью оператора if, а не связан с ним. Компилятор позволяет нам опустить здесь фигурные скобки, так как это однострочный блок.
user2597608

9

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

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

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


8

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

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


5

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

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

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

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

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

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


Тип заявления является нижним типом. Voidэто не нижний тип. Смотри мой ответ .
Шелби Мур III

1
Разве это не нулевой типа нижнего типа (одно значения null)? Не будет voidли больше похож на тип устройства (но с единственным недоступным значением)?
Марк Сидаде

Если voidэто тип возврата функции, которая никогда не возвращается (например, функция, которая throwявляется ошибкой), это тип снизу . В противном случае voidэто тип устройства . Вы правы, что утверждение, которое не может расходиться, имеет тип единицы измерения. Но утверждение, которое может расходиться, является типом дна. Из-за теоремы Остановки мы обычно не можем доказать, что функция не расходится, поэтому я думаю, что единица - это выдумка. Нижний тип не может иметь значения, поэтому он не может иметь единственного значения null.
Шелби Мур III

1
Что касается того, что я сказал три года назад, я не знаю, считаю ли я все еще заявления о том, что они имеют тип void или какой-либо другой тип. В языках заявление на основе , с которыми я знаком, только значения и все , что либо хранит или возвращает значение (например, выражения, переменные, члены и функции) могут иметь типы. Я обычно думаю о нижнем типе как о пустом множестве (без значений), и поэтому все, что не существует онтологически, будет иметь этот тип. nullЗначение действительно pseudovalue обозначая , что ссылка указывает на то , что не существует.
Марк Сидаде

1
Марк, я оценил рациональность вашего ответа. Вы в основном вынули слова из моих уст, и я надеюсь, что было ясно, что я признался вам, что вы были правы, чтобы поднять единицу. Я думаю, что мы согласны. Я не собирался упоминать об этом, но некоторые люди здесь думают, что я настроен негативно. Я просто пытаюсь быть фактическим.
Шелби Мур III

4

Просто: выражение оценивается как значение, а выражение - нет.


Так что же делает заявление? Ничего?
Шелби Мур III

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

И поэтому у заявления должны быть побочные эффекты, о чем говорит мой сильно отрицательный ответ. Какую еще полезность может иметь заявление? Даже если бы NO-OP считался оператором (это только «оператор» в грамматике, но не на уровне семантики, потому что он стирается после синтаксического анализа, а семантика - это то, что мы обсуждаем здесь), он не объяснил бы, что черт возьми, общая полезность утверждения есть.
Шелби Мур III

1
@ShelbyMooreIII Заявления не должны ничего делать или иметь побочные эффекты. Например, {}это утверждение. Помещение слова в кавычки не меняет этого. Заявления являются синтаксическими конструкциями с семантикой. Нет такого понятия, как «уровень семантики» - вы, похоже, имеете в виду выполнение . Вы говорите, что пытаетесь быть точным, но у вас ничего не получилось. Ваша жалоба о "невежестве недовольных избирателей" - это чистый ad hominem; у вас нет информации о психических состояниях downvoters.
Джим Балтер

Да, все не правы, кроме интеллектуально нечестных. {}определяется как оператор в спецификации языка C #.
Джим Балтер

4

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


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


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


На языке выражений все возвращает значение. Поначалу это может показаться немного странным - что (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, Готово или Успех.
  • Когда несколько несвязанных выражений оцениваются в одном большем выражении, значение последней вещи, вычисленной в большом выражении, становится значением большого выражения. Чтобы взять пример (FOR i = 1 TO 10 DO (print i)), значение цикла for равно 10, это заставляет (print i)выражение вычисляться 10 раз, каждый раз возвращая i в виде строки. Последний раз через возвращение 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
)

2

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

Например, в C # у нас есть очень полезный 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<TValue, void>(которая будет эквивалентна Action<TValue>).

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


Утверждение не является частным случаем выражения. В некоторых языках (т. Е. В большинстве преемников C) все наоборот.
Akangka

2

Заявления -> Инструкции для последовательного следования
выражений -> Оценка, которая возвращает значение

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

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

Примеры заявлений:

for
goto
return
if

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

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

2+2

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


Как насчет побочных эффектов?
Остин Хенли,

@ AustinHenley нет никаких требований для этого. На самом деле выражение может определенно иметь побочный эффект.
Akangka

1

Заявление ,

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

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

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

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

Выражение ,

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

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

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


Я бы лучше написал if(number >= 0) return true; else return false;или даже лучше bool? IsPositive(int number) { if(number > 0) return true; else if(number < 0) return false; else return null;}:)
Махди Тахсильдари

1

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

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


1

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

Оператор состоит из нуля или более выражений, но также может представлять собой другие языковые концепции. Это расширенная форма 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

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

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

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

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

0

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

x = 5

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

(x + 5)/9.0

гласит: «х плюс 5 все делится на 9,0». Это не полное предложение. Заявление

while k < 10: 
    print k
    k += 1

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


whileЭто выражение некоторых языков, таких как Scala. Вы смешиваете грамматику с набором текста. Смотри мой ответ .
Шелби Мур III

Вот цикл while в scala: tutorialspoint.com/scala/scala_ while_loop.htm Цикл с его предикатом и без тела не является грамматически завершенным предложением. Это не полное выражение. Вам нужно тело, чтобы завершить его как выражение.
ncmathsadist

А whileс телом это еще выражение в Скале. Это также может быть утверждение, если оно создает побочные эффекты, что допускает мой сильно опущенный ответ (выражение также может быть утверждением). Мой ответ - единственный правильный. Извините всех тех читателей, которые не могут понять.
Шелби Мур III

Что вы подразумеваете под грамматически завершенным? В C, (x + 5)/9.0безусловно , может стоять в одиночестве как утверждение. Кроме того, если под грамматическим завершением вы подразумеваете допустимую программу, C не позволяет операторам выделяться как отдельная программа.
Akangka

Грамматически завершено: представляет собой законченное предложение.
ncmathsadist

0

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

Первоначально ответил Андерс Kaseorg

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

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

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

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


0

Де-факто основой этих понятий является:

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

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

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

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

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

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

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

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

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

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

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

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


0

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

Википедия определяет словосочетание аналогично

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

Обратите внимание на последнее утверждение. (хотя «программа» в этом случае технически неверна, потому что и C, и Java отклоняют программу, которая не содержит ничего из утверждений.)

Википедия определяет выражение слова как

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

Это, однако, ложно, потому что в Kotlin throw new Exception("")это выражение, но при оценке оно просто выдает исключение, никогда не возвращая никакого значения.

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

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

Это комбинация из одной или нескольких констант, переменных, функций и операторов, которую язык программирования интерпретирует (в соответствии со своими конкретными правилами приоритета и ассоциации) и вычисляет для получения («вернуть» в среде с состоянием) другого значения

Но проблема в языке программирования C, учитывая функцию executeSomething следующим образом:

void executeSomething(void){
    return;
}

Это executeSomething()выражение или это утверждение? Согласно моему определению, это утверждение, потому что, как определено в справочной грамматике Microsoft C,

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

Но эта же страница ясно указывает на то, что такой синтаксис является выражением.


-6

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

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

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

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


2
Различие не имеет ничего общего с типом выражений. Синтаксически определенные операторы вообще не имеют типов во многих языках. Хотя я не против, чтобы назначать тип на таких терминах в теории, различные трактовки @pragmaили /*comment*/логически несовместимы.
FrankHB

-11

Наиболее точно, оператор должен иметь «побочный эффект» (т.е. будет императивным ) и выражение должно иметь в значении типа (т.е. не нижний тип).

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


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

Давайте посмотрим, что Википедия должна сказать по этому вопросу.

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

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

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


5
Заявление не должно иметь побочного эффекта. Например, в python passесть утверждение. Это неоперация, и это ни к чему не приводит.
Мэтью Шинкель

9
-1 Это неправильно. Заявление не должно иметь побочный эффект. См. Раздел 1.5 спецификации языка C # . Мало того, что не указано , что заявления должны иметь побочные эффекты, но он также перечисляет несколько заявлений , которые не могут иметь не побочные эффекты.
NullUserException

2
@NullUserException Я прочитал этот раздел. Операторы объявлений, выражений, выбора, итерации и перехода могут создавать побочные эффекты. Но если есть выражение RT, то это не утверждение. Я понимаю, что спецификация приравнивает выражения к операторам, но этот вопрос задал разницу между ними. Так что либо вопрос не имеет ответа, либо вы слишком буквально воспринимаете спецификацию C #. Топ проголосовавший ответ пытается сказать, что я сделал. Но «что-то делать» не имеет смысла. «побочный эффект» - это осмысленный способ сказать «делает что-то». Мы должны думать, а не просто извергать.
Шелби Мур III

13
@ShelbyMooreIII Вы правы. Официальная документация неверна . Марк Грэвелл и Джон Скит, которые, возможно, наиболее уважают постеры C #, работающие на SO вне Эрика Липперта, ошибаются . Я и все остальные, которые отрицали вашу позицию и оставили комментарии, объясняющие нашу позицию, не правы . Вы правы. Вы, очевидно, единственный человек, который знает, о чем они говорят, так как вы намного умнее, чем все остальные SO.
NullUserException

3
Знание точного определения таких понятий, как оператор, выражение, приведение, преобразование и т. Д., Не оказывает влияния на 99,999% повседневных задач программирования. Подумай об этом . Также: большинство людей не заботятся о Haskell и Scala.
NullUserException
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.