Да, и коль уж заговорили о переполнениях, выскажу старую свою мысль: система типов и у Оберона и у прочих современных ЯП (типа той же java например, да и плюсов и haskell'я) - дырявая.
Переполнения никак не связаны с типизацией, они связаны с реализацией математических операций и функций в ЯП. Переполнение, с высокоуровневой точки зрения, это
изменение результата ЯП-операции или функции с математически правильного значения, если это значение выходит за пределы диапазона типа результата, на математически неправильное значение, но взятого в пределах указанного диапазона. Обычно это усечение старших битов.
В отличие от своих математических оригиналов,
правильные ЯП-операции и функции, помимо типизации аргументов и результата, определены не для всех (математически допустимых) значений аргументов нужного типа. Например, правильно реализованные в ЯП математические операции сложения, вычитания и умножения int-типа определены не для всех пар int-значений.
Если же вместо сокращения области определения (вместо неопределенности результата) использовать выдачу неправильных значений но взятых в пределах диапазона, т.е. использовать переполнение, то это будет
ошибочная реализация математики в ЯП.
Впрочем, никто не обязывает следовать правилу "тип результата = максимальный тип аргумента", тип результата можно взять достаточно большим, чтобы вместить значение результата от любых значений аргументов в пределах их типа.
Но, ни тот, ни другой, ни третий вариант не является нарушением строгой типизации.
У строго типизированных она почему-то запрещает например преобразование real->int, но при этом разрешает int+int.
Так int+int это не преобразование, а операция.
А ведь и то и другое может привести к одному и тому же - к переполнению/порче значения.
Порча значений относится не к ЯП, а к ошибочной реализации ЯП в компиляторе.
Если ЯП декларирует свои операции и функции без переполнения, а компилятор сует в них переполнение (место выдачи ошибки), то такой компилятор тоже является ошибочной реализацией языка.
Пусть у нас есть тип Int(N), где N - битность этого целочисленного типа.
Разные значения одного типа (одного объекта) не обязаны иметь одинаковую битность в машинном представлении. Значения одного типа это высокоуровневая категория и не привязаны к месту в памяти и ее размеру.
Тогда, очевидно в случае сложения двух чисел этого типа результат не будет иметь тип Int(N), он будет иметь тип Int(N+1).
При том условии, что не накладывается других ограничений кроме типа на значения аргументов, т.е. операция является всюду определенной. И если имеется подобная иерархия типов со вложенными диапазонами, не обязательно основанная на числе бит в представлении.
Тогда можно ввести правило "тип результата = минимальный тип, содержащий значение результата операции при любых допустимых значениях аргументов из диапазонов их типа", который вы назвали логическим типом.
Вообще же говоря (без такого правила), множество значений не привязано к определенному диапазонному типу. Потому невозможно определить тип результата по множеству принимаемых им значений, тип результата
назначается. Произвольно. Операции INTEGER + INTEGER можно назначить тип результата хоть BYTE. Правда, операция не обязательно будет всюду определена.
Если в языке одно от другого отделено, то это позволяет в ряде случаев выполнять рантайм проверку только когда логический вычисленный (по правилам приведенным выше) тип становится больше машинного (производится автоматическое приведение к логическому типу с проверкой).
Машинный, в смысле, назначенный языком или программой тип результата операции.
Непонятно только, почему обязательно надо сначала полностью вычислять значение результата по логическому типу, а уже потом проверять его на выход за диапазон и (если его нет) приводить значение к машинному типу. Можно сразу вычислять результат по машинному типу и обрывать вычисления как только обнаружиться выход значения за диапазон. Это уже детали машинной реализации вычислений.
Либо требовать рукотворного явного приведения типов. Типа a,b,c,d : int_4; a:=int_4(a+b+c+d); Только программировать в таком стиле будет не слишком удобно.
Что здесь имеется ввиду?
1. Тип результата операций опредялется по правилу "минимального типа", а затем функция int_4 проецирует (с проверкой) значение выражения к типу int_4.
2. int_4( + + + ) - единая конструкция (вызов функции), где роль разделителя аргуметов играет знак '+' (вместо запятой).
3. int_4 - опция компилятора, которая задает тип результата всех арифметических операций в подставленном выражении.
Отличаются тем, где генерируется ошибка.