Почему язык программирования позволяет присваивать целочисленные значения? - PullRequest
5 голосов
/ 17 января 2010
program TypeCategory;
{$R+}
var
    sInt : shortint;
    iInt : integer;
begin
    readln(iInt);
    sInt := iInt;
    writeln(sInt);
end.

Учитывая приведенный выше пример, язык паскаля разрешает присваивание от integer до shortint или даже от longint до shortint без явного приведения типа. То есть паскаль разрешает присваивание внутри категории типов (здесь целочисленные типы).

Pascal известен своим strongly typed, но почему он допускает такую ​​вещь weakly typed? Я думаю, что этот вид синтаксиса поощряет несовместимый код.

Какие плюсы для этого типа синтаксиса? Существуют ли другие языки, которые применяют этот тип синтаксиса, кроме знаменитых C и C ++?

спасибо.

EDIT
Я тестировал только turbo pascal и free pascal with fpc/objfpc/tp/delphi model. Кроме того, gcc/g++ и msvc дают одинаковый результат. То есть присвоение от int (что на моем компьютере составляет 4 байта) до short int (размер 2) не вызовет никаких ошибок компиляции, в то время как вы могли бы установить правильные параметры, чтобы компиляторы генерировали possible lose of data предупреждений.

Ответы [ 5 ]

8 голосов
/ 22 января 2010

Часть 1. Об определениях

Прежде всего, какой язык и реализацию вы называете "паскаль"? Если вы говорите о ISO Pascal , чем он мертв много лет назад. Если вы говорите о каком-либо другом языке или реализации, пожалуйста, предоставьте больше информации.

Во-вторых (как уже упоминалось, Теун Д) нет определения для строгой типизации . Взгляните на статью в Википедии о строгом наборе .

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

Предположим, что мы следуем определению из статьи Лука Карделли «Типовое программирование», описанной ниже на странице Википедии:

Статья Лука Карделли «Типовое программирование» описывает строгую типизацию просто как отсутствие непроверенных ошибок типов во время выполнения. Другими словами, отсутствие непроверенных ошибок времени выполнения называется безопасностью или безопасностью типов; В ранних работах Тони Хоара эта собственность называется охранной.

В любом случае описанное поведение не может быть классифицировано как статическая (или безопасная) дисциплина набора текста. Мне лично очень не нравится этот хммм ... Ну, это не особенность, это ошибка. =) * * Тысяча двадцать пять

Часть 2. Ответ

Я думаю, что проблема не в этой слабой типизации, а в большом разнообразии целочисленных типов, доступных в некоторых языках.

Существуют ли другие языки, которые применяют этот синтаксис, кроме знаменитых C и C ++?

Я думаю, что почти каждый статически типизированный язык с множеством целочисленных типов имеет такое поведение. Было хорошей идеей иметь эти SHORTINTs и весь этот джаз в первые годы для сохранения памяти. Но теперь, когда почти каждый ПК имеет около 1 ГБ и более ОЗУ ... Предположим, у нас есть 1 миллион 4-байтовых INTEGER вместо 2-байтовых SHORTINT. Это всего около 4 МБ ОЗУ вместо 2 МБ. Я думаю, что это разумная цена за то, что ты не описал все это странное поведение, которое ты описал.

Посмотрите на Wirth's Oberon-07 ( Language Report, PDF ). Существует только один целочисленный тип - 32-битный INTEGER.

Также можно упомянуть Python (или какой-то другой современный динамически типизированный язык) с типом int, который представляет числа в неограниченном диапазоне при условии наличия только доступной (виртуальной) памяти.

Итак, вы можете увидеть тенденцию - разнообразие целых чисел - это выживание 70-х годов. =) * * Тысячу сорок-пять

Какие плюсы у этого синтаксиса?

Плюсы - это (вероятно) сокращение многословия. Эти статически типизированные языки уже настолько многословны, что, если мы решим добавить некоторое явное преобразование целочисленных типов, как это сделал Вирт в Oberon-2 (взгляните на функции SHORT () и LONG ()), они станут еще более многословными. В качестве компромисса можно разрешить неявное преобразование. Также во многих языках фактический размер переменных целочисленных типов не фиксирован и отличается от одной реализации к другой. Единственная доступная информация - это размер (сокращение) <= размер (int). В случае равенства явное преобразование выглядит довольно странно. </p>

Часть 3. Дифирамб Оберон-2 =)

Кстати, не слишком настороженно относитесь к Паскалю. Он мертв, но в Оберон-2 Никлаус Вирт исправил свою ошибку.

В главе 6 Language Report вы можете найти информацию о типах. Для нашего обсуждения важное утверждение:

Типы с 3 по 5 являются целочисленными типами, типы 6 и 7 являются действительными типами, и вместе они называются числовыми типами. Они образуют иерархию; больший тип включает в себя (значения) меньший тип: LONGREAL> = REAL> = LONGINT> = INTEGER> = SHORTINT

В главе 9 мы можем прочитать о назначениях:

Выражение должно быть совместимым с присвоением с переменной

Наконец, в Приложении A:

Назначение совместимо

Выражение e типа Te совместимо по присваиванию с переменной v типа Tv, если выполняется одно из следующих условий:

Те и ТВ одного типа;

Te и Tv - числовые типы, а Tv включает Te ;

...

Итак, мы здесь. Вы не можете назначить выражение INTEGER переменной SHORTINT. Если вам интересно, вы также можете взглянуть на Component Pascal , минорный вариант и доработку Оберона-2. BlackBox Component Builder - это IDE для Windows.


В ответ на комментарий Джастина Смита.

Я удивлен, что он сказал, что больший тип включает в себя (значения) меньший тип: LONGREAL> = REAL> = LONGINT> = INTEGER> = SHORTINT, учитывая, что существуют LONGINTS, которые нельзя выразить как "REAL".

Я немного озадачен вашим заявлением

существуют ДЛИННЫЕ, которые не могут быть выражены как "РЕАЛЬНЫЕ" с

На самом деле на моей машине упомянутая выше IDE имеет

MAX (LONGINT) = 9223372036854775807

MAX (REAL) = 1,779693134862316E + 308

Таким образом, вы можете представлять каждый LONGINT как РЕАЛЬНОЕ число. Но представление может быть не точным. Я думаю, что вы на самом деле говорили об этом, но мы говорим здесь о преобразовании различных целочисленных типов. И преобразование между РЕАЛЬНЫМИ и ИНТЕГРИАМИ - другая история. История плохих и запутанных имен. РЕАЛЬНЫЕ числа на самом деле не действительные числа с математической точки зрения. Они являются приблизительным представлением. Можно использовать рациональные числа приближение (сохраняя числитель и знаменатель в виде целых чисел), но наиболее распространенным способом является использование приближения с плавающей запятой. Стандарт IEEE для арифметики с плавающей точкой (также известный как IEEE 754) является наиболее широко используемым стандартом для вычислений с плавающей точкой.

Каждый должен знать, что РЕАЛЬНЫЕ числа не являются реальными, но числа указаны в стандарте IEEE 754. И каждый должен прочитать «Что должен знать каждый учёный-компьютерщик об арифметике с плавающей точкой» , чтобы прояснить некоторые моменты.

Но это другая история ... =)

2 голосов
/ 22 января 2010

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

0 голосов
/ 21 апреля 2013

Насколько я знаю, есть несколько вещей, которые следует учитывать:

  1. Существует только ONE целочисленный тип в классическом смысле Паскаля, целое число. Другие являются просто поддиапазонами, и поэтому не являются строго отдельным типом. Назначения разрешены в зависимости от диапазона, и проверки диапазона во время выполнения являются частью стандарта для его применения.
  2. В общем, Паскаль позволяет присваивать числовые типы при условии совпадения диапазонов. Вот почему добавление целого числа к реальному разрешено. (считается, что real содержит диапазон целых чисел), но не наоборот. Это специальное исключение, хотя, (язык определенное преобразование для простоты использования), поскольку вещественное не является даже порядковым типом.

Классические Паскали часто определяют базовый целочисленный тип, отличный от размера машинного слова. (как правило, в два раза больше), для самого большого типа можно обрабатывать на машине, и использовать поддиапазоны для всех типов переменных. Это означает, что различные вычисления, как во время выполнения, так и во время компиляции (константы), будут работать, даже если размер машинного слова иногда превышается, за счет некоторой производительности. Они просто будут увеличены до большего целочисленного типа. Я получил это только из новостных групп, и не слишком много опыта с этим, хотя. Я не знаю, было ли какое-либо умножение автоматически увеличено. Вероятно, это менее применимо в наши дни, когда большая часть обработки выполняется не по частям с четко определенным вводом и персоналом инженеров для его обработки.

Размещение диапазонов для всех переменных сделало проверку диапазона более эффективной также

, например

var x : 0..10;

x:=10;
x:=x+1; // runtime range check error  here.

Однако это использование поддиапазонов для определения переменных прекратилось, поскольку эра DOS привела к появлению более случайного типа программиста. В Turbo Pascal почти все было напечатано как «целое число», и, таким образом, это должно было быть машинным (или меньшим) по соображениям эффективности.

Необходимо было ввести longint с удвоенным размером диапазона (и позже int64 в Delphi. Может быть, int128 для x86_64 во времени), но это всегда оставалось несколько своеобразным (и нормальные правила ранжирования неприменимы. Также проблемы с тип unsigned, соответствующий наибольшему типу со знаком, никогда не был полностью разрешен (так как базовый тип Pascal подписан и, следовательно, не может содержать самый большой тип без знака)

0 голосов
/ 27 января 2010

Если бы язык никогда не разрешал присваивание от int до короткого int, этот код было бы невозможно написать

var
sInt : shortint;
iInt : integer;

if (iInt < 100 && iInt > -100)
{
   sInt := iInt; // this would not compile
}

или это

var
sInt : shortint;
iInt : integer;

sInt := (iInt & 0xFFFF); // this would not compile

Вы не могли написать код, который использовал бы целые числа как временные значения при выполнении математических операций на коротких целых числах, как это.

var
sInt1 : shortint;
sInt2 : shortint;
iInt : integer;

/* I want to multiply sInt2 by sInt1 and then divide by 100 */
iInt = sInt2;
sInt2 := (iInt * sInt1) / 100; // this would not compile

Но использование большего количества битов во временном значении является обычной техникой, позволяющей избежать ошибок из-за переполнения временных значений.

0 голосов
/ 17 января 2010

Я думаю, что это поведение не является слабо типизированным в том смысле, что вы никогда не сможете получить указатель на shortint, который действительно указывает на integer. Это также никогда не приведет к сбою (хотя числовое значение во второй переменной может отличаться от ваших ожиданий).

То, что вы имеете в виду, это то, что, очевидно, Паскаль не проверяет переполнение. В например C #, вы можете установить поведение проверки из кода (http://msdn.microsoft.com/en-us/library/khy08726(VS.71).aspx),, но часто это не делается из соображений производительности. Я предполагаю, что это также относится и к паскалю.

...