[ 11 ] :: Константы в программеВ связи с наличием более-менее строгой типизации, возникает вопрос с тем, как транслятор должен интерпретировать неименованные константы в программе. Допустим, написано выражение
Код:
Int32 a = 1024;
Здесь всё ясно, компилятор видит, что происходит инициализация целого типа размером 32 бита и вопроса о типе числа 1024 не возникает. А теперь мы делаем иначе:
Код:
Int32 a = 10 + (65536*65536);
Каким должен быть типа произведения в скобках? Должен ли компилятор догадаться по размеру результата, что тут нужен тип более высокий, чем int32? Если да, то получаем ошибку неявного приведения типов. Если нет, то будет переполнение и это вряд ли то, чего хотел бы программист (возможно, он допустил опечатку - и компилятор должен что-то ему сказать).
Более сложный вопрос
Код:
Int32 a = 10 + (65536*65536)/65536;
Это выражение будет ли вычислено правильно? Формально, тип ответа сходится по размерности, но промежуточные результаты выходят за его рамки. Что должен делать компилятор? Чем по-умолчанию должно быть число 65536?
Чтобы не было подобных проблем, можно попытаться сделать следующее.
1 Запретить в программе все числовые неименованные константы, кроме 0 и 1. Правила хорошего тона (хотя у каждого они бывают свои) требуют наделять все константы, отличные от 0 и 1 именами, а когда мы даём константе имя, мы даём ей и тип, а значит сразу избавляем компилятор от лишних размышлений и на страже безопасности будет строгая типизация, а неизбежность переполнения компилятор может определить сам и выдать предупреждение.
2 Не запрещать неименованные константы в программе, но создать суффиксы, позволяющие однозначно определить тип (как в C++, только не через ж... ). Например (это лишь пример!)
Код:
65536i32 // целое 32 бита со знаком
65536i32u // целое 32 бита без знака
65536i16 // ошибка
1r // рациональное число 1/1
2+3i // комплексное
Идея с суффиксами шла к успеху, однако напоролась на непонятный момент: как обозначить комплексное число из рациональных чисел и как сделать его же из вещественны чисел? Если rational и real имеют одну и ту же первую букву, то ... использовать q? Тогда почему целое – это i, а не z? Можно сделать z, но тогда целое без знака логично было бы назвать n (натуральное), но среди натуральных чисел нет нуля! Тогда обозначим их через N0? : ) В общем, начинается головная боль. Такие числа труднее читать и понять логику суффиксов будет не всегда просто.
Таким образом, мне суффиксы не нравятся – это как костыли, которые придумывают за неимением более хорошего решения. В графическом редакторе можно было бы хотя бы создать выделение цветом или придумать нижний индекс, всплывающие подсказки и т. д. А в текстовом редакторе очевидных хороших решений я не вижу.
3 Выполнять явное указание типа при использовании неименованной константы, например, int32u ( 65536 ) – всё ясно, целое без знака 32 бита, определяется во время компиляции. Но это громоздко.
А что делать, когда пишется a [ 10 ]? Какой тип имеет число 10?
Здесь проблем нет, оператор [] получает на вход совершенно чёткий тип данных (или несколько, если у нас полиморфизм), определённый заранее. По умолчанию при обращении к элементам массива параметр номера элемента следует сделать такой же разрядности, какой разрядности у нас доступно адресное пространство. Если 4 Гб, то 32 бита без знака. Если больше, то 64 (понятно, что реально памяти меньше, но она же виртуальная). Поэтому обращение к элементам массива типа a [ i + 10 ] не вызовет проблем, если 10 будет приведено к типу i и может быть выполнено сложение, возвращающее результат, соответствующий ожидаемому для оператора [].
Среди трёх описанных решений мне больше нравится запрет на использование неименованных констант с возможностью явного указания типа, если такая константа всё-таки требуется. Но если она всё-таки требуется, значит (имхо!) код плохо продуман, то есть раз делаем костыль, значит и выглядеть он должен как костыль, то есть плохо. У этого костыля тип должен быть прописан явно. А то что за костыль без типа?
--- Лирическое отступление ---Вообще, я сторонник того, чтобы хорошо продуманная программа могла быть написана хорошо, а плохо продуманная всегда писалась бы плохо и выглядела бы неопрятно. Такая философия. Я часто замечал за собой, что когда код программы начинает превращаться во что-то некрасивое (субъективно), значит решение (даже если будет правильным) по сути плохое, значит есть гораздо более хорошее. Данная философия нередко позволяла мне создавать очень хорошие программы. Я просто переписывал код так, чтобы он был красивым, и на удивление почти всегда программа получалась быстрее
и проще (именно «
и», а не «
или»). Мистика.
--- Конец лирического отступления ---Ещё один важный момент, в языке должна быть предусмотрена возможность визуального разделения разрядов (по желанию программиста). Хотя бы как в новом стандарте C++:
Код:
int a = 65'536+1'024
double b = 123'456.789'101'11.
Замечание! Записи типа
Код:
double a = .5
double a=5.
запретить и выжечь калёным железом. Меня лично они чем-то сильно задевают (это полностью субъективная оценка, но разумных обоснований я не слышал и не придумал).
Теперь что делать с константами в других системах счисления? Вот здесь как раз суффиксы и будут наиболее удобным решением: b, o, h. Например,
Цитата:
int16u a = AB'CD'h // шестнадцатеричное
int16u a = 1010'1011'1100'1101'b // двоичное, не может быть конфликта с шестнадцатеричным из-за суффикса b, так как тут нет суффикса h
Есть одна проблема, как не перепутать имя переменной ABCDh с шестнадцатеричной константой? Я думаю, что апостроф нужен перед суффиксом всегда, то есть константа должна иметь вид ABCD'h, без апострофа это будет литерал. Разумеется, апостроф - это лишь пример, выдумать способ разделения можно совершенно любой, лишь бы было удобно. В языке TeX, например, это команда «\,» которая раскрывается в маленький пробел, заметный глазу.
Теоретически, можно использовать даже произвольное основание int32 a = 123_5, что будет означать 123 в пятеричной системе, а int32 a = 123_3 будет уже ошибкой компиляции. Но, мне кажется, поддержка произвольной системы счисления на уровне языка не нужна, отдельной библиотекой с использованием строковых типов данных это сделать куда проще и понятнее. Во-первых, не нужно перегружать язык, во-вторых, букв всего 26, а систем счисления бесконечно, не говоря уже о нестандартных вроде i*sqrt(5).
[ Продолжение следует ]