Почему C# может определить тип переменной, но не может определить тип константы?

Рейтинг: 3Ответов: 2Опубликовано: 08.04.2015

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

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

var a = 5; // int
var b = 5.0; // double

Но когда я определяю константу - компилятор заставляет меня прописать тип константы в явном виде.

const int c = 5;
const double d = 5.0;

С чем связана такая непоследовательность? Неужели тип константы определить сложнее, чем тип переменной?

Ответы

▲ 5Принят

Eric Lippert, ведущий разработчик компилятора C# отвечал на этот вопрос: https://stackoverflow.com/a/2128581/1159507

Если вкратце то var предназначена для упрощения конструкция типа Dictionary<string, List<decimal>> priceTable = new Dictionary<string, List<decimal>>();

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

▲ 3

Он может. Но, во первых, будет несколько сложнее указать, что нужна именно константа. Как это сделать?

var const b = 5.0

Выглядит коряво.

Можно, конечно, анализировать, имзеняется ли данная переменная и добавлять константность автоматом:

var b1 = 42;
// b1 нигде больше ни используется, поэтому b1 - это константа!

var b2 = 42;

// Где-то в блоке ниже! Ага, b2 - не константа! Это переменная!
b2 = 36;

Но насколько это хорошо, когда тип переменной и ее поведение зависит от места использования? Другими словами, сделать-то это дело можно, но вот будет ли в этом смысл уверенности нет!

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

UPDATE: Почему компилятор C# не может вывести тип лямбда-выраженя? (выношу ответ из комментария).

Компилятор C# не может вывести тип лямбды:

var foo = () => 42;

Не из-за ограничений параметрическим полиморфизмом:) Лямбды могут быть преобразованы к Func<T> или к Expression<Func<T>> и компилятор C# не знает, какой тип треубется пользователю.

Вот пример успешного вывода типов:

var foo = (Func<int>)(() => 42);

UPDATE 2: Почему плохо const b = 5.0? В комментариях был задан вопрос, а почему бы не использовать const b = 5.0? Ничего плохого в этом нет, но можно представить ответ команды разработчиков C# на предложение добавить эту возможность.

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

class Foo
{
  const boo = -42;
  public Foo()
  {
    const foo = 42;
  }
}

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

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

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