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





Выражения могут быть оценены для получения значения, тогда как операторы не возвращают значение (они имеют тип пустота).
Выражения вызова функций, конечно, также можно рассматривать как операторы, но если среда выполнения не имеет специальной встроенной переменной для хранения возвращаемого значения, получить ее невозможно.
В языках, ориентированных на утверждения, все процедуры должны быть списком операторов. Языки, ориентированные на выражения, а это, вероятно, все функциональные языки, представляют собой списки выражений или, в случае LISP, одно длинное S-выражение, представляющее список выражений.
Хотя оба типа могут быть составлены, большинство выражений могут быть составлены произвольно, если типы совпадают. Каждый тип утверждений имеет свой собственный способ составления других утверждений, если они могут делать все это. Операторы Foreach и if требуют либо одного утверждения, либо того, чтобы все подчиненные операторы входили в блок операторов, один за другим, если только эти подзапросы не позволяют использовать свои собственные подзапросы.
Заявления также могут включать выражения, в которых выражение на самом деле не включает никаких инструкций. Однако одним исключением может быть лямбда-выражение, которое представляет функцию и поэтому может включать все, что может включать функция, если только язык не допускает только ограниченные лямбда-выражения, такие как лямбда-выражения с одним выражением в Python.
В языке, основанном на выражениях, все, что вам нужно, - это одно выражение для функции, поскольку все управляющие структуры возвращают значение (многие из них возвращают NIL). В операторе возврата нет необходимости, поскольку последнее вычисленное выражение в функции является возвращаемым значением.
Тип заявления - нижний тип. Void не является нижним типом. См. мой ответ.
Разве нулевой тип не является нижним типом (единственное значение null)? Разве void не был бы больше похож на тип единицы (но с недоступным его единственным значением)?
Если void является возвращаемым типом функции, которая никогда не возвращает (например, функция, которая вызывает ошибку throw), это нижний тип. В противном случае void - это тип единицы. Вы правы, что утверждение, которое не может расходиться, имеет тип единицы. Но утверждение, которое может расходиться, - это нижний тип. Из-за теоремы об остановке мы обычно не можем доказать, что функция не расходится, поэтому я считаю, что единица измерения - это фикция. Нижний тип не может иметь значения, поэтому он не может иметь единственного значения null.
Что касается того, что я сказал три года назад, я не знаю, считаю ли я до сих пор утверждения, что они имеют тип пустота или какой-либо другой на самом деле. В языках на основе операторов, с которыми я знаком, только значения и все, что либо хранит, либо возвращает значение (например, выражения, переменные, члены и функции), могут иметь типы. Я обычно думаю о нижнем типе как о пустом множестве (без значений), и поэтому все, что онтологически не существует, будет иметь этот тип. Значение null на самом деле является псевдозначение, обозначающим, что ссылка относится к чему-то, чего не существует.
Марк: Я оценил рациональность вашего ответа. Вы в основном убрали слова из моих уст. И я надеюсь, было ясно, что я признал вам, что вы были правы, когда подняли единичный балл. Думаю, мы согласны. Я не собирался упоминать об этом, но, похоже, некоторые люди здесь думают, что я веду себя отрицательно. Я просто пытаюсь быть правдой.
@ShelbyMooreIII Нет, это не так. У оператора просто нет типа. Попытка рассматривать его как значение является синтаксической ошибкой. Если выражение имеет нижний тип, оно никогда ничего не вернет. Он вызовет исключение, выполнит бесконечный цикл или изменит поток управления другими причудливыми способами.
@Akangka в теории типов все фрагменты кода (не связанные с комментариями, прагмами, макросами препроцессора и т. д.) Имеют тип, иначе система типов не будет согласованной. Если ваш PL (например, не Scala) не позволяет вам абстрагироваться от типа Unit, это не отменяет того факта (как я писал в своих ответах правильный), что операторы не являются выражениями (т.е. не возвращают значение), таким образом, имеют тип Unit. Я также объяснил в своем ответе, что Unit, возможно, является фикцией, поэтому IMO является синонимом нижнего типа. Фрагмент кода, имеющий тип дна, не является выражением ...
@Akangka проблема здесь, на S.O. как я объяснил на примере - это групповое мышление, которое хочет объединить отдельные проблемы с отдельными моделями. Например, как я объяснил правильно в своих ответах на этой странице, получивших сильные отрицательные голоса, если выражение определено так, чтобы допускать нижний тип и / или побочные эффекты, тогда термин выражение будет определенно нечеткий w.r.t. term, потому что операторы имеют побочные эффекты и расходятся (т. е. никогда не возвращаются).
@Akangka написал «У оператора просто нет типа […] Если у выражения есть нижний тип». Не удаляйте свой комментарий, если вы понимаете, что утверждения могут вызывать выражения. Ржунимагу. Я в архиве обсуждение.
@ShelbyMooreIII «в теории типов все фрагменты кода [...] имеют тип, иначе система типов не будет согласованной». Да, вы правы ... в языке из большого семейства типизированных лямбда-исчислений, которое является наиболее широко используемой математической моделью для языка программирования. Для большинства операторов (кроме определения переменных и, вероятно, некоторых других) вы также можете определить выражение let expr = ()=>{ statement; } in expr(), которое является является выражением. Причина, по которой типизированное лямбда-исчисление не имеет операторов, заключается в том, что 1. утверждения не нужны и 2. это излишне усложняет рассуждение.
@ShelbyMooreIII Фактически, тип - это просто набор значений, которые может возвращать выражение (если вообще). Во всех системах типов, которые имеют функцию (даже если это не первый класс), если у меня есть функция f типа (Unit) -> a, я смогу ввести f(<anything that have type of Unit>). Однако в Python вы не можете использовать f(raise Exception("this expression should've been legal")), а в Rust вы не можете использовать f(let a = 42). Этот синтаксис не имеет аналогов в типизированном лямбда-исчислении.
@ShelbyMooreIII Если вы думаете, что оператор имеет нижний тип, точка все равно остается в силе, потому что нижний тип является подтипом каждого типа. Также я не удалял комментарий
Позвольте нам продолжить обсуждение в чате.
Выражение - это то, что возвращает значение, а выражение - нет.
Например:
1 + 2 * 4 * foo.bar() //Expression
foo.voidFunc(1); //Statement
Главное между ними состоит в том, что вы можете связывать выражения вместе, тогда как операторы не могут быть связаны.
Уверенные утверждения могут быть связаны. {stmt1; stmt2; stmt3;} - это цепочка, а также сам (составной) оператор.
foo.voidFunc(1); - это выражение с пустым значением. while и if являются заявлениями.
Мне любопытно, что утверждения не связаны. Что-нибудь вроде "if (x> 1) return;" считаться соединением двух утверждений вместе?
@SimonTewsi Я считаю, что return считается подделкой.
@SimonTewsi Здесь оператор return неявно находится внутри блока оператора if, поэтому он является частью оператора if, а не связан с ним. Компилятор позволяет нам опускать фигурные скобки здесь, поскольку это однострочный блок.
Проще говоря: выражение дает значение, а оператор - нет.
Итак, что делает заявление? Ничего?
Он может что-то делать, но ничего не оценивает. То есть, вы не можете присвоить результат переменной, а можете - выражению.
И поэтому у утверждения должны быть побочные эффекты, как говорится в моем ответе, который сильно отклонился. Какую еще полезность может иметь утверждение? Даже если бы NO-OP считался оператором (это только «оператор» в грамматике, но не на уровне семантики, потому что он стирается после синтаксического анализа, а семантика - это то, что мы здесь обсуждаем), он не объяснил бы, что черт возьми, общая полезность утверждения есть.
Заявления @ShelbyMooreIII не требуют каких-либо действий или имеют побочные эффекты. например, {} - это заявление. Использование пугающих кавычек этого не меняет. Операторы - это синтаксические конструкции с семантикой. Не существует такой вещи, как «уровень семантики» - похоже, вы имеете в виду исполнение. Вы говорите, что пытаетесь быть точным, но вам это не удалось. Ваша жалоба на «невежество противников» - чистое ad hominem; у вас нет информации о психологическом состоянии опровергающих.
Да, все ошибаются, кроме интеллектуально нечестных. {} определяется как инструкция в спецификации языка C#.
Остерегайтесь языка с нижним шрифтом. Некоторое выражение на этом языке не дает значения.
@ShelbyMooreIII предполагает, что существует функция a с определением function a() -> Bottom{ while(true){} }, тогда тип выражения a() - Bottom. Это справедливо даже для такого языка, как Rust, который так долго оценивают. Семантика такова, что если выражение оценивается, выражение не вернет значение, а вместо этого откажется от текущего потока управления. Это может быть исключение, или вызов / cc, или, как в примере кода, бесконечный цикл.
Кроме того, некоторые элементы синтаксиса не оценивают значение, например комментарий, объявление и т. д. Но они не являются утверждениями.
@Akangka Я бы подумал, что декларация является - это утверждение.
Вы можете найти это в википедия, но выражения оцениваются до некоторого значения, а операторы не имеют оцененного значения.
Таким образом, выражения можно использовать в операторах, но не наоборот.
Обратите внимание, что некоторые языки (такие как Lisp, и я полагаю, Ruby и многие другие) не различают оператор и выражение ... в таких языках все является выражением и может быть связано с другими выражениями.
Выражение: Что-то, что оценивается как значение. Пример: 1 + 2 / х
Заявление: Строка кода, которая что-то делает. Пример: GOTO 100
В самых ранних языках программирования общего назначения, таких как FORTRAN, различие было кристально ясным. В FORTRAN оператор - это одна единица выполнения, которую вы выполняете. Единственная причина, по которой его не называли «линией», заключалась в том, что иногда он занимал несколько строк. Само по себе выражение ничего не может сделать ... вам нужно было присвоить его переменной.
1 + 2 / X
- это ошибка ФОРТРАНА, потому что он ничего не делает. Вы должны были что-то сделать с этим выражением:
X = 1 + 2 / X
У FORTRAN не было грамматики в том виде, в каком мы ее знаем сегодня - эта идея была изобретена вместе с формой Бэкуса-Наура (BNF) как часть определения Алгол-60. В этот момент различие семантический («иметь значение» против «делать что-то») было закреплено в синтаксис: один вид фраз был выражением, а другой - утверждением, и синтаксический анализатор мог различать их.
Разработчики более поздних языков стерли это различие: они позволили синтаксическим выражениям делать что-то, и они разрешили синтаксические выражения, которые имели значения. Самый ранний пример популярного языка, который до сих пор сохранился, - это C. Разработчики C поняли, что не будет никакого вреда, если вам позволят вычислить выражение и выбросить результат. В C каждое синтаксическое выражение можно превратить в оператор, просто поставив точку с запятой в конце:
1 + 2 / x;
- абсолютно законное заявление, даже если ничего не произойдет. Точно так же в C выражение может иметь побочные эффекты - оно может что-то менять.
1 + 2 / callfunc(12);
потому что callfunc может просто сделать что-нибудь полезное.
Как только вы разрешите любому выражению быть оператором, вы также можете разрешить оператор присваивания (=) внутри выражений. Вот почему C позволяет делать такие вещи, как
callfunc(x = 2);
Это вычисляет выражение x = 2 (присваивая x значение 2), а затем передает это (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 - это языки, в которых нет синтаксических операторов - у них есть только выражения. Даже циклы со структурой классов и условные формы считаются выражениями, и у них есть значения, но не очень интересные.
Если я не неправильно интерпретирую вас здесь, вы, кажется, утверждаете, что "(setf (third foo) 'goose)" является выражением, а не утверждением, потому что это Лисп, который "не имеет операторов", и потому что Lisp более чем на десять лет старше C, который был «первым популярным языком, стирающим границы [между выражениями и операторами]». Не могли бы мне объяснить подробности этого?
@ Курт Сэмпсон, вы задавали это как отдельный вопрос?
Если я не ошибаюсь, 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 Я считаю, что where на самом деле является частью объявления функции, а не выражения или утверждения.
@JimBalter Я прочитал справочную грамматику и был прав. haskell.org/onlinereport/haskell2010/haskellch10.html. Обратите внимание, что предложение where рассматривается как часть rhs (правая часть объявления), а не exp (выражение). Утверждение where как выражение подразумевает, что охранники тоже являются выражением.
@Akangka Мой комментарий не имел ничего общего с вашим ... он был об ответе Джоэла Спольски.
Обратите внимание, что в 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
Неправильная логика того, что такое утверждение. Декларативная программа также может выполняться, но декларативная программа не имеет операторов. Утверждение есть и делает "побочные эффекты", то есть обязательно. ср. мой ответ.
Некоторые вещи о языках, основанных на выражениях:
Самое главное: все возвращает значение
Нет никакой разницы между фигурными скобками и скобками для разграничения блоков кода и выражений, поскольку все является выражением. Это не мешает лексической области видимости: например, локальная переменная может быть определена для выражения, в котором содержится ее определение, и для всех содержащихся в нем операторов.
В языке, основанном на выражениях, все возвращает значение. Поначалу это может показаться немного странным - что возвращает (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 раз, каждый раз возвращая 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
)
Оператор - это частный случай выражения, имеющего тип 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? Да. Все, что ему нужно сделать, это потребовать, чтобы после return следовало выражение типа void. Результатом default(void) будет тип void, а передаваемая функция должна иметь форму Func<TValue, void> (что эквивалентно Action<TValue>).
Ряд других ответов подразумевает, что вы не можете связывать утверждения, как вы, с выражениями, но я не уверен, откуда взялась эта идея. Мы можем представить себе ;, который появляется после операторов, как бинарный инфиксный оператор, который берет два выражения типа void и объединяет их в одно выражение типа void.
Утверждение - это не особый случай выражения. В некоторых языках (например, в большинстве последователей C) все наоборот.
Для объяснения важных различий в компоновке (цепочности) выражений и утверждений, моя любимая ссылка - это статья Джона Бэкуса о премии Тьюринга, Можно ли освободить программирование от стиля фон Неймана?.
Императивные языки (Fortran, C, Java, ...) делают упор на операторы для структурирования программ и имеют выражения как своего рода размышления. Функциональные языки делают упор на выражения. Функциональные языки Чисто обладают такими мощными выражениями, что операторы могут быть полностью исключены.
Утверждения - это грамматически законченные предложения. Выражений нет. Например
x = 5
читается как «x получает 5.» Это полное предложение. Код
(x + 5)/9.0
гласит: «x плюс 5 все делится на 9,0». Это не полное предложение. Заявление
while k < 10:
print k
k += 1
это полное предложение. Обратите внимание, что заголовка цикла нет; "в то время как k
while - это выражение некоторых языков, таких как Scala. Вы смешиваете грамматику с набором текста. См. мой ответ.
Вот цикл while в scala: tutorialspoint.com/scala/scala_ while_loop.htm Цикл со своим предикатом и без тела не является грамматически законченным предложением. Это не полное выражение. Вам нужно тело, чтобы завершить его как выражение.
while с телом по-прежнему является выражением в Scala. Это также может быть утверждение, если оно создает побочные эффекты, что допускает мой ответ, получивший сильную отрицательную оценку (выражение также может быть утверждением). Мой ответ - единственно правильный. Извините всех тех читателей, которые не понимают.
Что вы имеете в виду под грамматически завершенным? В языке C (x + 5)/9.0 определенно может выступать отдельно. Кроме того, если под грамматически завершенной вы имеете в виду действительную программу, C не позволяет операторам выступать отдельно как единую программу.
Грамматически полное: составляет законченное предложение.
Точнее, оператор должен иметь "побочный эффект" (то есть быть обязательным), а выражение должно иметь тип имеютценить (т.е. не нижний тип).
тип заявления - это тип юнита, но из-за теоремы об остановке юнит является фикцией, так что скажем, нижний тип.
Void - это не совсем нижний тип (это не подтип из всех возможных типов). Он существует на языках, которые нет полностью звуковой системы типа. Это может звучать как снобистское заявление, но полнота такие как аннотации отклонений имеет решающее значение для написания расширяемого программного обеспечения.
Посмотрим, что говорит Википедия по этому поводу.
https://en.wikipedia.org/wiki/Statement_(computer_science)
In computer programming a statement is the smallest standalone element of an imperative programming language that expresses some action to be carried out.
Many languages (e.g. C) make a distinction between statements and definitions, with a statement only containing executable code and a definition declaring an identifier, while an expression evaluates to a value only.
Пожалуйста, не переопределяйте общие технические термины «выражение» и «утверждение». Мои комментарии и ответ верны для C#. Если f(); имеет тип void и не имеет побочных эффектов, то это NOOP. Хороший компилятор не допускает NOOP. Если f(); не имеет побочных эффектов и его возвращаемое значение не используется, это также NOOP. Я ответил на вопрос по поводу C#. Я ответил одним точным предложением. Это предложение верно для C#. Затем я подробно рассказал о том, что означает void в C# с точки зрения теории типов. Теория типов применима к C#.
См. Мои комментарии под ответом Марка Сидаде, которые объясняют, почему утверждение часто на самом деле является нижним типом, а не типом единицы. Сказать, что утверждение «что-то делает» невероятно неточно, поскольку выражение также «что-то делает» - оно дает значение. Я знаю, что люди пытаются сказать, просто они не выбирают точных слов и определений. Точное слово (утверждение не должно быть) ссылочно прозрачным (т. Е. Императивным). Это более точно, чем «что-то делает» или «побочный эффект».
Заявление не обязательно должно иметь побочный эффект. Например, в Python pass - это утверждение. Это запретная операция, и она ни к чему не приводит.
@MatthewSchinckel Если у него нет побочного эффекта, то это либо выражение, либо NOOP. NOOP ничего не делает, поэтому его можно удалить из программы. Это простой процесс логического исключения. Если вы не определяете оператор как требующий побочного эффекта, оператор будет таким же, как выражение. Какой еще атрибут вы бы использовали, чтобы отличить утверждение от выражения?
-1 Это неправильно. У оператора имеют нет побочного эффекта. См. Раздел 1.5 Спецификация языка C#. Он не только не указывает, что операторы должен имеют побочные эффекты, но также перечисляет несколько операторов, которые могут иметь побочные эффекты нет.
@NullUserException Я прочитал этот раздел. Операторы декларации, выражения, выбора, итерации и перехода могут создавать побочные эффекты. Но если есть выражение RT, то это не утверждение. Я понимаю, что спецификация приравнивает выражения к операторам, но в этом вопросе задавалась разница между ними. Так что либо на вопрос нет ответа, либо вы слишком буквально воспринимаете спецификацию C#. Ответ, получивший наибольшее количество голосов, пытается сказать, что я сделал. Но «что-то делает» бессмысленно. «побочный эффект» - это осмысленный способ сказать «что-то делает». Мы должны думать, а не просто срыгивать.
@ShelbyMooreIII Вы правы. Официальная документация - неправильный. Марк Грейвелл и Джон Скит, которые, возможно, являются наиболее уважаемыми авторами C#, работающими на SO, за исключением Эрика Липперта, являются неправильный. Я и все остальные, кто проголосовал против вас и оставили комментарии, объясняющие нашу позицию, - это неправильный. Ты прав. Очевидно, что вы единственный человек, который знает, о чем они говорят, поскольку вы намного умнее всех остальных в SO.
@NullUserException Они очень правы в том, как большинство пользователей C# хотят понимать концепции. Но я показываю им общую картину, возможно, они еще не видели. Я понимаю когнитивный диссонанс, тоже страдаю. В прошлом я делал аналогичные более узкие предположения. Раньше я происходил из мира C / C++ / C#, поэтому я знаю, как сложно мне было адаптироваться к Haskell, Scala и другим общим концепциям. Но я готов согласиться с тем, что мои ответы не так полезны, как другие в этом контексте. Допустим, вы правильный в каком-то смысле
Знание точного определения таких понятий, как оператор, выражение, приведение, преобразование и т. д., Не оказывает никакого влияния на 99,999% повседневных задач программирования. Подумайте о который. Также: большинству людей наплевать на Haskell и Scala.
@NullUserException Но если можно, подумайте об этом. Если выражение отличается от оператора, что это за отдельный атрибут? "Что-то делает"? Определите «что-то». Я думаю, вы обнаружите, что мой ответ совпадает с ответом, получившим наибольшее количество голосов. Я только что определил, что такое «что-то». Спецификация C# просто для удобства. Не следует ожидать, что вы думаете, что выражения неотличимы от утверждений. Или вы считаете, что выражения - это просто подмножество утверждений, но это не работает. Мне показать, как это не может работать?
@ShelbyMooreIII Я никогда не утверждал, что выражения - это просто подмножество утверждений. Но опять же, это не имеет значения.
@NullUserException Действительно, Haskell тупой и из-за ленивых вычислений имеет пространственно-временную неопределенность, что затрудняет отладку. Также у него нет виртуального наследования. Scala исправляет многие из этих вещей и на данный момент является самым быстрорастущим языком, но все еще очень незначительным. Scala довольно хорош, но у его синтаксиса слишком много вариантов, например 9 способов написать функцию и другие вопросы. Также на данный момент по большей части привязан к библиотекам Java. C# работает на Android? Хорошо, что вы не думаете, что выражения - это подмножество утверждений. Что значит «что-то»? Что такое «что-то»?
давайте продолжить обсуждение в чате
@NullUserException Я уважаю этих ребят. Я никогда не мог ответить на все их вопросы. Их знания намного шире моих. Они действительно хорошо разбираются в кодировании на этих платформах. У них, наверное, намного больше энергии, чем у меня. И они, наверное, такие же умные, если не умнее меня. Я хочу, чтобы было ясно, что это не вопрос уважения. Я просто хочу, чтобы люди были непредубежденными и давали время на все. Иногда вещи не такие, какими кажутся.
Спецификация языка C# действительно ли нет требует, чтобы операторы имели побочные эффекты. Пустые операторы допустимы (раздел 8.3) независимо от того, оставляет их компилятор или нет. Фактически, поскольку работа с операторами без операции оставлена на усмотрение реализации, даже NOOP могут потенциально повлиять на скомпилированный код и производительность программы. Так что ваш ответ неверен как с академической, так и с практической точки зрения.
Компилируются ли NOOP или нет, в любом случае не имеет значения. { return 5; } - это утверждение, которое не вызывает побочных эффектов, если только вы не переопределили «побочный эффект», включив в него возврат одного значения. Это не только неприемлемое значение (даже в Haskell), оно имеет смысл только в чисто академическом смысле. () => 5 и () => { return 5; } после вычисления дают один и тот же результат, но один является выражением, а другой - нет.
@JustinMorgan на абстрактном уровне языкового дизайна return - это либо просто выражение, которое является значением включающей функции, либо и то, и другое, а также сокращение для написания более сложной структуры if-else, чтобы все пути кода разрешались в значение . Неудивительно, что нефункциональные языки делают это неправильно. Например, в Scala return можно опустить, и вы можете просто написать 5 в конце пути кода для функции.
@MatthewSchinckel У заявление о прохождении определенно есть побочные эффекты. Это заставляет интерпретатор тратить циклы ЦП, чтобы обойти его. Он также предназначен в качестве заполнителя для функции, которая будет добавлять побочные эффекты вместо оператора pass, таким образом, это способ указания будущих побочных эффектов.
Обычные системы типов не могут хорошо справляться с побочными эффектами в метаязыке (на этапах трансляции). Тип void делает программу семантически недействительной и обычно требует диагностики от реализации, когда такой термин оценивается в контексте, требующем (не void) значения, это, по сути, действие, выполняемое транслятором. Это не имеет ничего общего с упомянутыми здесь побочными эффектами объектного языка. Верно, что концепция утверждений не так уж и полезна, но это не повод менять общеизвестное ее значение.
«Это заставляет интерпретатор тратить циклы ЦП, чтобы обойти его» [необходима цитата]. У вас есть дизассемблированный байт-код Python в качестве доказательства?
@Akangka, как обычно, это будет подвергаться цензуре, но в моем заявлении 2015 года, что не о интерпретаторе байт-кода, вместо этого я ссылаюсь на интерпретатор исходного кода. Если он полностью удален в байт-коде, это эквивалентно комментарию w.r.t. побочные эффекты по сравнению с ценностями и, следовательно, не имеют отношения к моим точкам определения. А теперь шу.
Заявления -> Инструкции для выполнения последовательно
Выражения -> Оценка, возвращающая значение
Операторы в основном похожи на шаги или инструкции в алгоритме, результатом выполнения оператора является актуализация указателя инструкции (так называемый в ассемблере)
Выражения не подразумевают и порядок выполнения на первый взгляд, их цель - оценить и вернуть значение. В императивных языках программирования оценка выражения имеет порядок, но это просто из-за императивной модели, но не в их сущности.
Примеры заявлений:
for
goto
return
if
(все они подразумевают переход строки (оператора) исполнения на другую строку)
Пример выражений:
2+2
(это подразумевает не идею исполнения, а оценку)
@AustinHenley для этого нет требований. Фактически, выражение определенно может иметь побочный эффект.
Оператор - это процедурный строительный блок, из которого строятся все программы 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;} :)
Я предпочитаю значение statement в формально-логическом смысле этого слова. Это тот, который изменяет состояние одной или нескольких переменных в вычислении, позволяя сделать истинное или ложное утверждение об их значении (ах).
Я предполагаю, что в компьютерном мире и науке в целом всегда будет путаница, когда вводится новая терминология или слова, существующие слова `` перепрофилируются '' или пользователи игнорируют существующую, устоявшуюся или `` правильную '' терминологию для того, что они описывают.
Вот краткое изложение одного из самых простых ответов, которые я нашел.
Первоначально ответил Андерс Касеорг
Оператор - это полная строка кода, которая выполняет какое-либо действие, а выражение - это любой раздел кода, который оценивается как значение.
Выражения можно комбинировать «по горизонтали» в более крупные выражения с помощью операторов, в то время как операторы можно комбинировать только «по вертикали», записывая одно за другим или с помощью блочных конструкций.
Каждое выражение может использоваться как оператор (результат которого заключается в оценке выражения и игнорировании результирующего значения), но большинство операторов нельзя использовать как выражения.
Я не совсем удовлетворен ни одним из ответов здесь. Я посмотрел грамматику для 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++.
case, например, помеченное заявлениеifif/else, casewhile, do...while, for (...)break, continue, return (может возвращать выражение), gototry/catchЭто отрывок, показывающий часть выражений:
expression:
assignment-expression
expression "," assignment-expression
assignment-expression:
conditional-expression
logical-or-expression assignment-operator initializer-clause
throw-expression
+, -, *, /, &, |, &&, ||, ...)throw также является выражениемЧтобы улучшить и подтвердить мой предыдущий ответ, определения терминов языка программирования должны быть объяснены из теории типов информатики, когда это применимо.
Выражение имеет тип, отличный от типа Bottom, то есть имеет значение. У оператора есть тип Unit или Bottom.
Из этого следует, что оператор может иметь какой-либо эффект в программе только тогда, когда он создает побочный эффект, потому что он либо не может возвращать значение, либо возвращает только значение типа Unit, которое либо не назначается (в некоторых языках, например, void языка C) или (например, в Scala) могут быть сохранены для отложенной оценки оператора.
Очевидно, что @pragma или /*comment*/ не имеют типа и, таким образом, отличаются от операторов. Таким образом, единственный тип оператора, который не будет иметь побочных эффектов, - это бездействие. Неработоспособность полезна только в качестве заполнителя для будущих побочных эффектов. Любое другое действие из-за заявления будет побочным эффектом. Снова подсказка компилятора, например @pragma не является утверждением, потому что у него нет типа.
Это различие не имеет ничего общего с типом выражений. Синтаксически определенные операторы вообще не имеют типов во многих языках. Хотя я не против назначать тип на таких условиях в теории, разные подходы к @pragma или /*comment*/ логически несовместимы.
В языке программирования, ориентированном на инструкции, блок кода определяется как список операторов. Другими словами, инструкция - это часть синтаксиса, которую вы можете поместить в блок кода, не вызывая синтаксической ошибки.
Википедия определяет слово утверждение аналогично
In computer programming, a statement is a syntactic unit of an imperative programming language that expresses some action to be carried out. A program written in such a language is formed by a sequence of one or more statements
Обратите внимание на последнее утверждение. (хотя «программа» в этом случае технически неверна, потому что и C, и Java отвергают программу, которая не состоит из операторов.)
Википедия определяет слово выражение как
An expression in a programming language is a syntactic entity that may be evaluated to determine its value
Однако это неверно, потому что в Kotlin throw new Exception("") является выражением, но при оценке оно просто генерирует исключение, никогда не возвращая никакого значения.
В статически типизированном языке программирования каждое выражение имеет тип. Однако это определение не работает в языке программирования с динамической типизацией.
Лично я определяю выражение как часть синтаксиса, которую можно составить с помощью вызова оператора или функции, чтобы получить более крупное выражение. На самом деле это похоже на объяснение выражения в Википедии:
It is a combination of one or more constants, variables, functions, and operators that the programming language interprets (according to its particular rules of precedence and of association) and computes to produce ("to return", in a stateful environment) another value
Но проблема в языке программирования C, учитывая, что функция executeSome примерно такая:
void executeSomething(void){
return;
}
executeSomething() - это выражение или утверждение? Согласно моему определению, это утверждение, потому что, как определено в справочной грамматике Microsoft C,
You cannot use the (nonexistent) value of an expression that has type void in any way, nor can you convert a void expression (by implicit or explicit conversion) to any type except void
Но на той же странице ясно указано, что такой синтаксис является выражением.
утверждение - это блок кода, который ничего не возвращает и который является просто отдельной единицей выполнения. Например-
if (a>=0)
printf("Hello Humen,I'm a statement");
выражение, с другой стороны, возвращает или оценивает новое значение. Например -
if (a>=0)
return a+10;//This is an expression because it evalutes an new value;
или же
a=10+y;//This is also an expression because it returns a new value.
A piece of syntax which can be evaluated to some value. In other words, an expression is an accumulation of expression elements like literals, names, attribute access, operators or function calls which all return a value. In contrast to many other languages, not all language constructs are expressions. There are also statements which cannot be used as expressions, such as while. Assignments are also statements, not expressions.
A statement is part of a suite (a “block” of code). A statement is either an expression or one of several constructs with a keyword, such as if, while or for.
Я считаю, что выбранный вами ответ неоднозначен. Выражение тоже что-то делает - вычисляет значение. Я дал однозначный ответ.