Почему у Java, C# и C++ нет диапазонов?
Ada, Pascal и многие другие языки поддерживают диапазоны, способ подтипить целые числа. Диапазон - это целочисленное значение со знаком, которое варьируется от значения (первое) до другого (последнее). Легко реализовать класс, который делает то же самое в ООП, но я думаю, что встроенная поддержка этой функции может позволить компилятору выполнять дополнительные статические проверки.
Я знаю, что невозможно статически проверить, что переменная, определенная в диапазоне, не будет "переполнена" во время выполнения, то есть из-за неправильного ввода, но я думаю, что что-то можно было сделать. Я думаю о подходе Design by Contract (Eiffel) и SpeC# ( C# Contracts), которые дают более общее решение.
Есть ли более простое решение, которое проверяет, по крайней мере, статическое внешнее присваивание во время компиляции в C++, C# и Java? Что-то вроде статического утверждения?
редактировать: я понимаю, что "диапазоны" могут быть использованы для разных целей:
- итераторы
- нумераторы
- целочисленный подтип
Я бы остановился на последнем, потому что формирователи легко сопоставимы на языке C*. Я имею в виду закрытый набор значений, что-то вроде громкости музыки, то есть диапазон, который варьируется от 1 до 100. Я хотел бы увеличить или уменьшить его на величину. Я хотел бы иметь ошибку компиляции в случае статического переполнения, что-то вроде:
volume=rangeInt(0,100);
volume=101; // compile error!
volume=getIntFromInput(); // possible runtime exception
Благодарю.
11 ответов
Поддиапазонные типы на самом деле не очень полезны. Мы не часто выделяем массивы фиксированной длины, и также нет причин для целых чисел фиксированного размера. Обычно там, где мы видим массивы фиксированного размера, они действуют как перечисление, и у нас есть лучшее (хотя и "более тяжелое") решение для этого.
Поддиапазонные типы также усложняют систему типов. Было бы гораздо полезнее ввести ограничения между переменными, чем фиксированными константами.
(Обязательно укажите, что целые числа должны быть произвольного размера на любом разумном языке.)
Диапазоны наиболее полезны, когда вы можете сделать что-то в этом диапазоне, кратко. Это означает закрытие. По крайней мере, для Java и C++ тип диапазона был бы раздражающим по сравнению с итератором, потому что вам нужно определить внутренний класс, чтобы определить, что вы собираетесь делать в этом диапазоне.
Для C++ в настоящее время реализуется библиотека переменных для ограниченных значений, которая будет предложена в библиотеках повышения: http://student.agh.edu.pl/~kawulak/constrained_value/index.html
У Java было ключевое слово assert начиная с версии 1.4. Если вы занимаетесь программированием по контракту, вы можете использовать его для проверки правильности назначения. И любой изменяемый атрибут внутри объекта, который должен находиться в определенном диапазоне, должен быть проверен перед установкой. Вы также можете бросить IllegalArgumentException.
Почему нет типа диапазона? Я предполагаю, что первоначальные дизайнеры не видели ни одного в C++ и не считали его столь же важным, как и другие функции, которые они пытались понять.
Это старый вопрос, но просто хотелось его обновить. В Java нет диапазонов как таковых, но если вам действительно нужна функция, вы можете использовать Commons Lang, который имеет несколько классов диапазонов, включая IntRange:
IntRange ir = new IntRange(1, 10);
Как ни странно, это не существует в Commons Math. Я частично согласен с принятым ответом, но я не считаю, что диапазоны бесполезны, особенно в тестовых случаях.
Паскаль (а также Delphi) использует тип поддиапазона, но он ограничен порядковыми типами (целое число, символ и даже логическое значение).
Это в основном целое число с дополнительной проверкой типов. Вы можете подделать это на другом языке, используя класс. Это дает преимущество в том, что вы можете применять более сложные диапазоны.
Я хотел бы добавить к ответу Тома Хотина (на что я согласен), что для C++ наличие диапазонов не подразумевает, что они будут проверяться - если вы хотите быть совместимыми с общим поведением языка - как, например, доступ к массиву в любом случае также не проверяется по дальности. Я полагаю, что для C# и Java решение было основано на производительности - проверка диапазонов наложила бы бремя и усложнила бы компилятор.
Обратите внимание, что диапазоны в основном полезны на этапе отладки - нарушение диапазона никогда не должно происходить в рабочем коде (теоретически). Таким образом, проверки диапазона лучше осуществлять не внутри самого языка, а в предварительных и постусловиях, которые могут (должны) быть удалены при создании релизной сборки.
В C# вы можете сделать это:
foreach(int i in System.Linq.Enumerable.Range(0, 10))
{
// Do something
}
C++ позволяет вам реализовывать такие типы с помощью шаблонов, и я думаю, что уже есть несколько библиотек, делающих это. Тем не менее, я думаю, что в большинстве случаев выгода слишком мала, чтобы оправдать добавленную сложность и снижение скорости компиляции.
Что касается статического утверждения, оно уже существует.
Boost имеет BOOST_STATIC_ASSERT
и в Windows, я думаю, библиотека Microsoft ATL определяет аналогичную библиотеку.
boost::type_traits
и boost::mpl, вероятно, ваши лучшие друзья в реализации чего-то подобного.
Гибкость в использовании собственного лучше, чем встроенная в язык. Что, если вы хотите использовать насыщающую арифметику, например, вместо того, чтобы генерировать исключение для значений вне диапазона? Т.е.
MyRange<0,100> volume = 99;
volume += 10; // results in volume==100
JSR-305 обеспечивает некоторую поддержку диапазонов, но я не знаю, когда это будет частью Java.