В C# следующий метод не скомпилирует:
public bool IsItTrue()
{
}
Ошибки компилятора: 'IsItTrue ()': не все пути выполнения кода возвращают значение, которое имеет смысл. Но следующая компиляция без любой проблемы.
public bool IsItTrue()
{
while (true)
{
}
}
Который выглядит неправильным как никакой оператор возврата вообще. Почему это так? Любая справка здесь...,
Компилятор знает, что второй метод никогда не вернётся.
Если любой из методов когда-либо вернётся при любых обстоятельствах, то он должен вернуть bool
.
Первый метод не содержит бесконечных циклов, не бросает никаких безусловных исключений и т.д., поэтому он должен вернуть bool
. Код не возвращает bool
, поэтому компилятор отказывается его компилировать.
Второй метод никогда не возвращается из-за бесконечного цикла while (true)
. Если он никогда не возвращает , то не имеет значения, что (если что) никогда не возвращается никогда не возвращается , поэтому компилятор позволит ему скомпилировать его.
Еще несколько примеров, которые компилятор распознает и позволит:
public bool IsItTrue()
{
throw new Exception("Always thrown!");
}
public bool HowAboutThisOne()
{
if ((46 - 3) < (27 * 9))
{
throw new Exception("Always thrown!");
}
}
Первое хорошо объясняется сообщением об ошибке компилятора.
Второе никогда не возвращает, поэтому никогда не возвращает никаких значений.
Это не одно и то же. В первом примере метод мог вернуть без возврата какого-либо значения вызывающему абоненту -> Ошибка компилятора.
Второй никогда не вернет (компилятор достаточно умен для этого, он понимает, что вы создали бесконечный цикл). Он никогда не войдет в состояние "Хорошо, я дошел до конца метода и не знаю, что возвращать"
. В Halting Problem говорится, что в общем случае невозможно определить, будет ли программа завершаться или выполняться вечно. Учитывая, что в этом потоке есть примеры, которые, кажется, нарушают этот принцип, я подозреваю, что компилятор C# выполняет анализ условий цикла, которые можно свести к константе времени компиляции . Если константа вычислит true
, то мы знаем, что цикл никогда не завершится.
Например, рассмотрим две следующие функции.
public bool NoError()
{
while (true) { }
}
public bool Error()
{
while (NoError()) { }
}
Как было показано, первая функция не будет выдавать ошибку времени компиляции. Однако, вторая будет, так как компилятор не сможет оценить результат вызова функции NoError()
. Это также происходит, если модифицировать NoError()
, чтобы всегда возвращать true
.