Арифметическое переполнение
От: AlexRK  
Дата: 22.02.14 08:20
Оценка: -1
Приветствую, уважаемые коллеги.

Думаю над сабжевым вопросом. Существующие языки программирования разбираются с переполнением по-разному:

С++. Стратегия типа "суем голову в песок" — объявляем переполнение UB и не паримся. Кому надо — пусть руками ифы ставит. Плюсы — скорость, думать над кодом не надо. Минусы — полное отсутствие надежности.

C#. Каждая операция с проверкой. Плюсы — при переполнении поведение вполне определенное, опять же не надо специально думать при написании кода. Минусы — скорость, да и потенциальный вылет эксепшена хоть и не UB, но тоже скорее всего оставит программу в некорректном состоянии.

SPARK. Переполнения запрещаются статически. Плюсы — скорость, полная надежность. Минусы — очень геморройно писать/изменять код и согласовывать все контракты. Только для ракет и АЭС.

Python. Используем arbitrary precision arithmetic. Плюсы — надежно, код писать просто. Минусы — тормозно, тащим с собой огромную кучу кода (на фоне использования виртуальной машины может быть не важно, но если смотреть абстрактно — это большой минус).


Может быть есть иные подходы обработки переполнений? Хочется вариант с полной скоростью и полной надежностью, но не такой сложный в использовании, как контракты из SPARK. Можно немного поступиться удобством. Немного! Примерно так, как поступаются удобством статически типизированные языки, заставляя писать типы (по сравнению с динамическими). Возможно ли такое в мейнстим программировании в принципе?

И это я еще не говорю про числа с плавающей точкой...
Re: Арифметическое переполнение
От: andy1618 Россия  
Дата: 22.02.14 10:50
Оценка: +1
Здравствуйте, AlexRK, Вы писали:

ARK>C#. Каждая операция с проверкой. Плюсы — при переполнении поведение вполне определенное, опять же не надо специально думать при написании кода. Минусы — скорость, да и потенциальный вылет эксепшена хоть и не UB, но тоже скорее всего оставит программу в некорректном состоянии.


В C# поведение можно изменять опциями checked-unchecked:
http://msdn.microsoft.com/en-us//library/a569z7k8.aspx
Довольно удобно и наглядно, кстати.
Re: Арифметическое переполнение
От: koodeer  
Дата: 22.02.14 11:03
Оценка: +1
Здравствуйте, AlexRK, Вы писали:

ARK>C#. Каждая операция с проверкой. Плюсы — при переполнении поведение вполне определенное, опять же не надо специально думать при написании кода. Минусы — скорость, да и потенциальный вылет эксепшена хоть и не UB, но тоже скорее всего оставит программу в некорректном состоянии.


Не совсем так. andy1618 уже написал выше, что только при включенной опции checked будут проверки, при unchecked их нет.

А вообще, реакция на переполнение зависит от архитектуры процессора. В старом добром x86 просто устанавливается бит переполнения в регистре. И программный код должен содержать дополнительные инструкции, чтобы как-то обработать эту ситуацию. Опция checked в дотнете как раз добавляет такой код.

Я начинал с компьютера БК-0010-01, по системе команд он совместим с PDP-11. Так вот там поведение было другое: при арифметическом переполнении не только устанавливался соответствующий бит в регистре, но и происходило аппаратное прерывание: переход на определённый адрес. Если нам не нужно обрабатывать эту ситуацию, то просто помещаем в векторе перехода адрес на команду возврата. Если переполнение нужно обработать, то в векторе перехода должен быть адрес на код обработки.

Таким образом, в разных архитектурах разная цена игнорирования/обработки переполнения.
Re[2]: Арифметическое переполнение
От: AlexRK  
Дата: 22.02.14 11:18
Оценка:
Здравствуйте, andy1618, Вы писали:

A>В C# поведение можно изменять опциями checked-unchecked:

A>http://msdn.microsoft.com/en-us//library/a569z7k8.aspx
A>Довольно удобно и наглядно, кстати.

Ну окей, будет либо как в С++, либо с проверками. C# я привел просто в качестве примера подхода к "решению" проблемы переполнения (на самом деле, никакое это не решение).
Re[2]: Арифметическое переполнение
От: AlexRK  
Дата: 22.02.14 11:23
Оценка:
Здравствуйте, koodeer, Вы писали:

K>А вообще, реакция на переполнение зависит от архитектуры процессора. В старом добром x86 просто устанавливается бит переполнения в регистре. И программный код должен содержать дополнительные инструкции, чтобы как-то обработать эту ситуацию. Опция checked в дотнете как раз добавляет такой код.


K>Я начинал с компьютера БК-0010-01, по системе команд он совместим с PDP-11. Так вот там поведение было другое: при арифметическом переполнении не только устанавливался соответствующий бит в регистре, но и происходило аппаратное прерывание: переход на определённый адрес. Если нам не нужно обрабатывать эту ситуацию, то просто помещаем в векторе перехода адрес на команду возврата. Если переполнение нужно обработать, то в векторе перехода должен быть адрес на код обработки.


Спасибо, понятно. Но это все же не то, чего мне хочется. Хочется доказанного отсутствия переполнения (как в SPARK), но не такой дорогой ценой — чтобы получившееся решение было пригодно для массового использования. Если переполнение в аппаратуре произошло, то это значит, что _уже_ что-то пошло не так — программа написана некорректно.
Re: Арифметическое переполнение
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 22.02.14 11:32
Оценка: 3 (1) +2
Здравствуйте, AlexRK, Вы писали:


ARK>Может быть есть иные подходы обработки переполнений? Хочется вариант с полной скоростью и полной надежностью, но не такой сложный в использовании, как контракты из SPARK.


Гипотетический вариант: брать подход С++, но использовать специальный анализатор кода, который сделает range inference. В некоторых местах добавить в исходники пометки для анализатора. Будет как типы, но менее интрузивно.
Re[2]: Арифметическое переполнение
От: AlexRK  
Дата: 22.02.14 11:37
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Гипотетический вариант: брать подход С++, но использовать специальный анализатор кода, который сделает range inference. В некоторых местах добавить в исходники пометки для анализатора. Будет как типы, но менее интрузивно.


Спасибо. Да, это приходило в голову. Но при таком раскладе мы неизбежно вытаскиваем в контракты метода сильную зависимость от его реализации. Поменяли реализацию в библиотеке — и все клиенты сломались. Тут нужен некий промежуточный вариант, причем простой, но вот какой? Зависимость от имплементации, безусловно, должна быть, но в каких-то довольно широких рамках, которые соблюдают и создатель метода, и его клиенты.
Re[3]: Арифметическое переполнение
От: koodeer  
Дата: 22.02.14 11:42
Оценка: +1
Здравствуйте, AlexRK, Вы писали:

ARK> Но это все же не то, чего мне хочется. Хочется доказанного отсутствия переполнения (как в SPARK), но не такой дорогой ценой — чтобы получившееся решение было пригодно для массового использования. Если переполнение в аппаратуре произошло, то это значит, что _уже_ что-то пошло не так — программа написана некорректно.


Ага, я понял. У меня на самом деле тоже такая хотелка очень давно. После знакомства с ассемблером, я всегда хотел такого же подхода к получению результата, как в нём. Например, если перемножаем два байта, то результат всегда получаем в двух байтах.
Полагаю, этот же подход можно перенести в языки высокого уровня: по умолчанию результат арифметических операций, которые могут привести к переполнению, должен возвращаться в виде значения большего разряда. То есть складываем два числа int32, результат получаем в int64.
При этом придётся убрать из языка неявные приведения типа в арифметических операциях (вариант: сделать включение/отключение неявных преобразований опциональным, как checked в C#).
Re: Арифметическое переполнение
От: LaptevVV Россия  
Дата: 22.02.14 11:46
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Приветствую, уважаемые коллеги.

ARK>Думаю над сабжевым вопросом. Существующие языки программирования разбираются с переполнением по-разному:

ARK>И это я еще не говорю про числа с плавающей точкой...

А вот надо бы. Ибо для целых и для дробных, как говорится, две БОЛЬШИЕ разницы.
Если речь идет об Интел, то там в регистре управления сопроцессора можно установить прерывание по переполнению.
Для целых я такого не припомню, хотя флаг переполнения в регистре флагов, естественно, есть.
Его можно проверить и генерировать исключение.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[4]: Арифметическое переполнение
От: AlexRK  
Дата: 22.02.14 11:47
Оценка:
Здравствуйте, koodeer, Вы писали:

K>Ага, я понял. У меня на самом деле тоже такая хотелка очень давно. После знакомства с ассемблером, я всегда хотел такого же подхода к получению результата, как в нём. Например, если перемножаем два байта, то результат всегда получаем в двух байтах.

K>Полагаю, этот же подход можно перенести в языки высокого уровня: по умолчанию результат арифметических операций, которые могут привести к переполнению, должен возвращаться в виде значения большего разряда. То есть складываем два числа int32, результат получаем в int64.
K>При этом придётся убрать из языка неявные приведения типа в арифметических операциях (вариант: сделать включение/отключение неявных преобразований опциональным, как checked в C#).

Да, абсолютно верно, речь именно об этом. В принципе при сложении двух Int32 для результата достаточно одного лишнего разряда, чтобы ошибки не возникло (Int33 ). Но возникает масса проблем с циклами, да и просто с вызовом методов — все будут требовать специфические условия для себя. Вот я и интересуюсь, может есть какие-то интересные подходы...
Re: Арифметическое переполнение
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 22.02.14 11:48
Оценка: +1
Здравствуйте, AlexRK, Вы писали:

ARK>Может быть есть иные подходы обработки переполнений?


В Ada еще есть отдельные модульные типы, как вариант решения проблемы.
Re[2]: Арифметическое переполнение
От: AlexRK  
Дата: 22.02.14 11:49
Оценка:
Здравствуйте, LaptevVV, Вы писали:

ARK>>И это я еще не говорю про числа с плавающей точкой...

LVV>А вот надо бы. Ибо для целых и для дробных, как говорится, две БОЛЬШИЕ разницы.

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

LVV>Если речь идет об Интел, то там в регистре управления сопроцессора можно установить прерывание по переполнению.

LVV>Для целых я такого не припомню, хотя флаг переполнения в регистре флагов, естественно, есть.
LVV>Его можно проверить и генерировать исключение.

Это понятно, но исключение мне не нужно. Если произошло исключение (хоть программное, хоть аппаратное), то это уже некорректное поведение программы.
Re[2]: Арифметическое переполнение
От: AlexRK  
Дата: 22.02.14 11:51
Оценка:
Здравствуйте, Mystic, Вы писали:

ARK>>Может быть есть иные подходы обработки переполнений?


M>В Ada еще есть отдельные модульные типы, как вариант решения проблемы.


Да, верно, забыл про них. Но это, ИМХО, некорректное поведение в общем случае. То есть неправильное с математической точки зрения решение. Можно и просто отбрасывать лишние разряды — это тоже не решение.
Re[3]: Арифметическое переполнение
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 22.02.14 12:01
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Здравствуйте, Mystic, Вы писали:


ARK>>>Может быть есть иные подходы обработки переполнений?


M>>В Ada еще есть отдельные модульные типы, как вариант решения проблемы.


ARK>Да, верно, забыл про них. Но это, ИМХО, некорректное поведение в общем случае. То есть неправильное с математической точки зрения решение. Можно и просто отбрасывать лишние разряды — это тоже не решение.


С переполнением есть другой аспект — оно может быть полезно с точки зрения алгоритма. Например, при подсчете CRC. Или циклический буфер. В этом случае проще использовать модульные типы.

А так SPARK и последняя версия Ada с контрактами представляет собой, имхо, наилучшее решение. Там где компилятор может доказать, что переполнения не будет, там и дополнительных проверок никаких не будет. А если мы хотим гарантировать отсутствие переполнений в некотором критическом коде, то ставим соответствующий контракт и далее ручками помогаем компилятору построить доказательство этого факта используя диапазоны и т. п.
Re[3]: Арифметическое переполнение
От: LaptevVV Россия  
Дата: 22.02.14 12:04
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Это понятно, но исключение мне не нужно. Если произошло исключение (хоть программное, хоть аппаратное), то это уже некорректное поведение программы.

Как я понял, надо заранее предупреждать переполнение?
Тогда надо проверять диапазон слагаемых, и опять же что-то делать, если значения не удовлетворяют.
Но вообще признак переполнение при сложении — знак результата отличается от истинного.
Переполнение же случается только при сложении слагаемых одинакового знака.
Если вам нужно для любой операции — надо немного поисследовать.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[4]: Арифметическое переполнение
От: AlexRK  
Дата: 22.02.14 12:08
Оценка:
Здравствуйте, Mystic, Вы писали:

M>С переполнением есть другой аспект — оно может быть полезно с точки зрения алгоритма. Например, при подсчете CRC. Или циклический буфер. В этом случае проще использовать модульные типы.


Да. Но это частные случаи, которые к тому же легко реализовать на "корректных числах", не модульных.

M>А так SPARK и последняя версия Ada с контрактами представляет собой, имхо, наилучшее решение. Там где компилятор может доказать, что переполнения не будет, там и дополнительных проверок никаких не будет. А если мы хотим гарантировать отсутствие переполнений в некотором критическом коде, то ставим соответствующий контракт и далее ручками помогаем компилятору построить доказательство этого факта используя диапазоны и т. п.


Ну да. Вопрос заключается в том, чтобы сделать код глобально корректным, без рантайм-проверок вообще. И при этом с достаточной степенью свободы для изменения реализации методов. Условно говоря, чтобы контракт метода не изменялся, когда мы внутри метода меняем строку "i := i + 1" на "i := i + 2".
Re[4]: Арифметическое переполнение
От: AlexRK  
Дата: 22.02.14 12:11
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Как я понял, надо заранее предупреждать переполнение?


Именно.

LVV>Тогда надо проверять диапазон слагаемых, и опять же что-то делать, если значения не удовлетворяют.


Что делать, как раз понятно — не компилировать программу. Вопрос — как правильно построить программу, чтобы такого не возникало.
Re[5]: Арифметическое переполнение
От: LaptevVV Россия  
Дата: 22.02.14 12:17
Оценка:
Здравствуйте, AlexRK, Вы писали:

LVV>>Тогда надо проверять диапазон слагаемых, и опять же что-то делать, если значения не удовлетворяют.

ARK>Что делать, как раз понятно — не компилировать программу. Вопрос — как правильно построить программу, чтобы такого не возникало.
Не компилировать не получится. Переполнение — это жеж во время выполнения.
Или вам нужно на этапе компилЯции определять ?!
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[5]: Арифметическое переполнение
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 22.02.14 12:20
Оценка: +1
Здравствуйте, AlexRK, Вы писали:

ARK>Ну да. Вопрос заключается в том, чтобы сделать код глобально корректным, без рантайм-проверок вообще. И при этом с достаточной степенью свободы для изменения реализации методов. Условно говоря, чтобы контракт метода не изменялся, когда мы внутри метода меняем строку "i := i + 1" на "i := i + 2".


Заранее выбирать тип range для i такой, чтобы он вмещал все разумные значения. Например, выделение памяти. Если мы заранее знаем, что не будут выделяться фрагменты более 100M, мы можем указать диапазон с некоторым запасом, скажем 1G, чтобы (A) иметь свободу маневра и (B) исключить переполнение при элементарных операциях.
Re[6]: Арифметическое переполнение
От: AlexRK  
Дата: 22.02.14 12:23
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Не компилировать не получится. Переполнение — это жеж во время выполнения.

LVV>Или вам нужно на этапе компилЯции определять ?!

ИМЕННО ТАК.

Более того — уже есть системы, позволяющие это (см. первый пост темы — SPARK). Но писать для них программы сильно сложно. Для мейнстрима не годится.
Re[6]: Арифметическое переполнение
От: AlexRK  
Дата: 22.02.14 12:25
Оценка:
Здравствуйте, Mystic, Вы писали:

M>Заранее выбирать тип range для i такой, чтобы он вмещал все разумные значения. Например, выделение памяти. Если мы заранее знаем, что не будут выделяться фрагменты более 100M, мы можем указать диапазон с некоторым запасом, скажем 1G, чтобы (A) иметь свободу маневра и (B) исключить переполнение при элементарных операциях.


Да, что-то в этом направлении. Но все равно руками контракты писать придется? А если там формула Result:=((A+B)/(B*C-D))^E ? Как программист сможет выбрать "нормальный вариант с запасом" без того, чтобы сесть и выводить математические диапазоны?
Re[7]: Арифметическое переполнение
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 22.02.14 12:33
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Здравствуйте, Mystic, Вы писали:


M>>Заранее выбирать тип range для i такой, чтобы он вмещал все разумные значения. Например, выделение памяти. Если мы заранее знаем, что не будут выделяться фрагменты более 100M, мы можем указать диапазон с некоторым запасом, скажем 1G, чтобы (A) иметь свободу маневра и (B) исключить переполнение при элементарных операциях.


ARK>Да, что-то в этом направлении. Но все равно руками контракты писать придется? А если там формула Result:=((A+B)/(B*C-D))^E ? Как программист сможет выбрать "нормальный вариант с запасом" без того, чтобы сесть и выводить математические диапазоны?


Если брать исходники Ada, то там стараются использовать диапазоны. Соответственно, при объявлении переменных A, B, C, D, E я должен задаться вопросом, а что хранится в этих переменных? Если A это численность студентов в группе, то мне надо писать range 0 .. 99. Если B это голубой цвет, то range 0..255. С одной стороны лишняя работа. С другой стороны, статический анализ поможет раньше выловить разные баги и опечатки.
Re[5]: Арифметическое переполнение
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 22.02.14 12:41
Оценка:
Здравствуйте, AlexRK, Вы писали:

K>>Полагаю, этот же подход можно перенести в языки высокого уровня: по умолчанию результат арифметических операций, которые могут привести к переполнению, должен возвращаться в виде значения большего разряда. То есть складываем два числа int32, результат получаем в int64.

K>>При этом придётся убрать из языка неявные приведения типа в арифметических операциях (вариант: сделать включение/отключение неявных преобразований опциональным, как checked в C#).

ARK>Да, абсолютно верно, речь именно об этом. В принципе при сложении двух Int32 для результата достаточно одного лишнего разряда, чтобы ошибки не возникло (Int33 ). Но возникает масса проблем с циклами, да и просто с вызовом методов — все будут требовать специфические условия для себя. Вот я и интересуюсь, может есть какие-то интересные подходы...


И такой бит есть. Он правда отдельно расположен, обычно в флаговом регистре. На тех нескольких платформах, на которых я поработал, он везде есть. Единственное, что меня всегда удивляло, так это то, что в языке C/C++ нет какой-то инструкции/конструкции, которая бы помогала определять факт переполнения, вроде же "высокоуровневый ассемблер". Наверно на PDP, или на чем там первый C делали, не было такого флага.

При наличии такой конструкции можно было бы либо игнорировать переполнение/заём, если алгоритму безразличен; обработать его, как надо, если это важно; или бросить исключение (C++), если не знаешь, что делать.
Маньяк Робокряк колесит по городу
Re[8]: Арифметическое переполнение
От: AlexRK  
Дата: 22.02.14 12:44
Оценка:
Здравствуйте, Mystic, Вы писали:

ARK>>Да, что-то в этом направлении. Но все равно руками контракты писать придется? А если там формула Result:=((A+B)/(B*C-D))^E ? Как программист сможет выбрать "нормальный вариант с запасом" без того, чтобы сесть и выводить математические диапазоны?


M>Если брать исходники Ada, то там стараются использовать диапазоны. Соответственно, при объявлении переменных A, B, C, D, E я должен задаться вопросом, а что хранится в этих переменных? Если A это численность студентов в группе, то мне надо писать range 0 .. 99. Если B это голубой цвет, то range 0..255. С одной стороны лишняя работа. С другой стороны, статический анализ поможет раньше выловить разные баги и опечатки.


Диапазоны входных параметров — это еще полбеды. А вот с возвращаемыми значениями все куда веселее. Для формулы, которую я привел выше, диапазон уже совсем не очевиден. Можно его вывести автоматически, но тогда мы выставляем наружу сильную зависимость от реализации. Чуть изменили формулу — и все.

Да еще и с циклами большой вопрос... С ними проблемы предупреждения переполнения многократно хуже.

Видимо, я хочу невозможного и только искусственный интеллект может помочь.
Re[6]: Арифметическое переполнение
От: AlexRK  
Дата: 22.02.14 12:47
Оценка:
Здравствуйте, Marty, Вы писали:

M>И такой бит есть. Он правда отдельно расположен, обычно в флаговом регистре. На тех нескольких платформах, на которых я поработал, он везде есть. Единственное, что меня всегда удивляло, так это то, что в языке C/C++ нет какой-то инструкции/конструкции, которая бы помогала определять факт переполнения, вроде же "высокоуровневый ассемблер". Наверно на PDP, или на чем там первый C делали, не было такого флага.


Это только для сложения достаточно лишнего бита. А для умножения двух N-разрядных чисел для результата нужно уже 2N разрядов.

M>При наличии такой конструкции можно было бы либо игнорировать переполнение/заём, если алгоритму безразличен; обработать его, как надо, если это важно; или бросить исключение (C++), если не знаешь, что делать.


Ну, вообще говоря, тема посвящена не обработке переполнения постфактум, а вопросу предупреждения переполнения на этапе компиляции.
Re[9]: Арифметическое переполнение
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 22.02.14 13:10
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Диапазоны входных параметров — это еще полбеды. А вот с возвращаемыми значениями все куда веселее. Для формулы, которую я привел выше, диапазон уже совсем не очевиден. Можно его вывести автоматически, но тогда мы выставляем наружу сильную зависимость от реализации. Чуть изменили формулу — и все.


ARK>Да еще и с циклами большой вопрос... С ними проблемы предупреждения переполнения многократно хуже.


ARK>Видимо, я хочу невозможного и только искусственный интеллект может помочь.


Возвращаемые значения они же тоже что-то значат. Если функция возвращает количество фигур на шахматной доске, то ее результат вполне можно описать как range 2..32. Конечно, нужны достаточно выразительные средства для контрактов. Особенно если позиция хранится в битовых масках.

А с другой стороны, а это так надо? Все таки критического кода не так уж и много, и если это действительно надо, то надо заморочиться.
Re[7]: Арифметическое переполнение
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 22.02.14 13:31
Оценка:
Здравствуйте, AlexRK, Вы писали:

M>>При наличии такой конструкции можно было бы либо игнорировать переполнение/заём, если алгоритму безразличен; обработать его, как надо, если это важно; или бросить исключение (C++), если не знаешь, что делать.


ARK>Ну, вообще говоря, тема посвящена не обработке переполнения постфактум, а вопросу предупреждения переполнения на этапе компиляции.


По поводу того, что тема посвящена исключительно отлову на этапе компиляции — это как-то не очевидно из исходного сообщения.

Интересно было бы почитать, как там в SPARK устроено, но в любом случае имхо придется в рантайме вопрос решать — можно конечно требовать от любой арифметической операции возвращать тип, который гарантированно вмещает любой ее результат, но все равно в рантайме предется усекать разрядность и проверять, не обрезали ли лишнее, иначе размеры типов для программы более сложной, чем два-три сложения, перестанут вмещаться в память, а о циклах с переменным числом итераций вообще можно забыть.

Или я что-то не понимаю?
Маньяк Робокряк колесит по городу
Re[10]: Арифметическое переполнение
От: AlexRK  
Дата: 22.02.14 13:39
Оценка:
Здравствуйте, Mystic, Вы писали:

M>Возвращаемые значения они же тоже что-то значат. Если функция возвращает количество фигур на шахматной доске, то ее результат вполне можно описать как range 2..32. Конечно, нужны достаточно выразительные средства для контрактов. Особенно если позиция хранится в битовых масках.


Да, действительно. Хотел сейчас привести спорные примеры из дотнета, но что-то с налету не нашел. Width/Height из контролов — диапазоны определяются размерами экрана. Controls.Count, TabIndex — максимальное количество контролов на форме. Правда, сейчас этим не заморачиваются, везде просто int.

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

M>А с другой стороны, а это так надо? Все таки критического кода не так уж и много, и если это действительно надо, то надо заморочиться.


Надо ли — философский вопрос. В принципе, много чего не надо. Вон на Ц пишут операционные системы, а в нем ничего нет.
Re[8]: Арифметическое переполнение
От: AlexRK  
Дата: 22.02.14 13:43
Оценка:
Здравствуйте, Marty, Вы писали:

M>По поводу того, что тема посвящена исключительно отлову на этапе компиляции — это как-то не очевидно из исходного сообщения.


Согласен, первый пост не вполне очевиден в этом плане.

M>Интересно было бы почитать, как там в SPARK устроено, но в любом случае имхо придется в рантайме вопрос решать — можно конечно требовать от любой арифметической операции возвращать тип, который гарантированно вмещает любой ее результат, но все равно в рантайме предется усекать разрядность и проверять, не обрезали ли лишнее, иначе размеры типов для программы более сложной, чем два-три сложения, перестанут вмещаться в память, а о циклах с переменным числом итераций вообще можно забыть.


M>Или я что-то не понимаю?


Да нет, фишка как раз в том, что в рантайме ничего не решается. Отсутствие ошибок гарантируется на этапе компиляции. Но, конечно, все функции в качестве входных и выходных параметров используют не простые типы вроде int, а ограниченные диапазоны (0..10, -1000..10000 и т.п.). Таким образом, например, если мы складываем не больше 10 чисел, каждое из которых не больше 100 и не меньше 0, то результат гарантировано будет лежать в диапазоне 0..1000.
Re: Арифметическое переполнение
От: Pavel Dvorkin Россия  
Дата: 23.02.14 06:26
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Может быть есть иные подходы обработки переполнений?


Для целых чисел — не допускать их вообще. Используйте арифметику с соответствующей длиной операндов.

>Хочется вариант с полной скоростью и полной надежностью


И будет он.
With best regards
Pavel Dvorkin
Re[2]: Арифметическое переполнение
От: AlexRK  
Дата: 23.02.14 06:52
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

ARK>>Может быть есть иные подходы обработки переполнений?

PD>Для целых чисел — не допускать их вообще. Используйте арифметику с соответствующей длиной операндов.

А можно немного подробнее? Что вы имеете в виду под "арифметикой с соответствующей длиной операндов"?
Re: Арифметическое переполнение
От: NeoCode  
Дата: 23.02.14 09:35
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Думаю над сабжевым вопросом. Существующие языки программирования разбираются с переполнением по-разному:


Я в своем разрабатываемом языке программирования принял стратегию С/С++ с возможностью использовать альтернативные режимы явно:
Из C#: checked/unchecked
И режим насыщения sated/unsated (т.е. для байта например sated { 255+1 } == 255 )
разумеется, в такие блоки можно заключать фрагменты кода любого размера, хоть целые модули.
Re[2]: Арифметическое переполнение
От: AlexRK  
Дата: 23.02.14 09:46
Оценка:
Здравствуйте, NeoCode, Вы писали:

NC>Я в своем разрабатываемом языке программирования принял стратегию С/С++ с возможностью использовать альтернативные режимы явно:


Покажете язык-то? Я интересуюсь языками программирования.

NC>Из C#: checked/unchecked

NC>И режим насыщения sated/unsated (т.е. для байта например sated { 255+1 } == 255 )
NC>разумеется, в такие блоки можно заключать фрагменты кода любого размера, хоть целые модули.

Понятно. В принципе, выбранные решения просты в реализации.
А я тяготею к математической корректности в условиях ограничений реальной аппаратуры.
Re: Арифметическое переполнение
От: minorlogic Украина  
Дата: 23.02.14 09:49
Оценка:
еще есть вариант не выполнять все операции по месту а только накапливать буффер операций, и выводить результат когда он нужен по факту.

Также есть комбинированные подходы , хранить дроби неограниченной длниы для простых операций и т.д
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[3]: Арифметическое переполнение
От: Pavel Dvorkin Россия  
Дата: 23.02.14 09:49
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>А можно немного подробнее? Что вы имеете в виду под "арифметикой с соответствующей длиной операндов"?


Если ожидается, что значения не выйдут за пределы (беру знаковый случай) -2^15..2^15-1 — хватит и short, хотя, возможно, стоит все же использовать int, так как short для 32/64-битного процессора не родной
Если в этом нет уверенности, но ожидается, что значения не выйдут за пределы -2^31..2^31 -1 — хватит int
Если и это под вопросом, но ожидается, что значения не выйдут за пределы -2^63..2^63 -1 — брать long

Если же целые числа могут выйти за пределы -2^63..2^63 -1 — задать себе вопрос, что это за такие целые (точные!) числа и почему они должны быть целыми.

А для вещественных чисел в случае Windows есть __try — _except. Не знаю насчет платформонезависимого варианта.
With best regards
Pavel Dvorkin
Re[2]: Арифметическое переполнение
От: AlexRK  
Дата: 23.02.14 10:05
Оценка:
Здравствуйте, minorlogic, Вы писали:

M>еще есть вариант не выполнять все операции по месту а только накапливать буффер операций, и выводить результат когда он нужен по факту.


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

M>Также есть комбинированные подходы , хранить дроби неограниченной длниы для простых операций и т.д


Хранение рациональных чисел в виде простых дробей? ИМХО, это из той же оперы. Да и к переполнению вряд ли имеет отношение.
Re[4]: Арифметическое переполнение
От: AlexRK  
Дата: 23.02.14 10:08
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Если ожидается, что значения не выйдут за пределы (беру знаковый случай) -2^15..2^15-1 — хватит и short, хотя, возможно, стоит все же использовать int, так как short для 32/64-битного процессора не родной

PD>Если в этом нет уверенности, но ожидается, что значения не выйдут за пределы -2^31..2^31 -1 — хватит int
PD>Если и это под вопросом, но ожидается, что значения не выйдут за пределы -2^63..2^63 -1 — брать long

А, вы об этом.
Меня интересует немного другое — корректность программ более сильного вида, а именно формальная. Т.е. отсутствие переполнений, гарантированное компилятором.
Re[5]: Арифметическое переполнение
От: Pavel Dvorkin Россия  
Дата: 23.02.14 10:16
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Меня интересует немного другое — корректность программ более сильного вида, а именно формальная. Т.е. отсутствие переполнений, гарантированное компилятором.


А зачем решать проблему, если можно ее легко обойти ?
With best regards
Pavel Dvorkin
Re[6]: Арифметическое переполнение
От: AlexRK  
Дата: 23.02.14 10:26
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>А зачем решать проблему, если можно ее легко обойти ?


Ну, это вопрос философский.

Лично мне нравится такая цель — создание корректного ПО. Гарантированно корректного, а не с некоторой вероятностью. Под корректностью в данном контексте я понимаю отсутствие ошибок времени исполнения.
Если можно достичь этого, то почему бы и нет?
Re[7]: Арифметическое переполнение
От: Pavel Dvorkin Россия  
Дата: 23.02.14 10:57
Оценка:
Здравствуйте, AlexRK, Вы писали:

PD>>А зачем решать проблему, если можно ее легко обойти ?


ARK>Ну, это вопрос философский.


Не согласен. Если есть способ избавиться от проблемы, то ИМХО решать ее не надо, а надо именно избавиться. Других проблем хватит, от которых избавиться так просто не удастся.

ARK>Лично мне нравится такая цель — создание корректного ПО. Гарантированно корректного, а не с некоторой вероятностью. Под корректностью в данном контексте я понимаю отсутствие ошибок времени исполнения.


А в том, что я предложил, именно эта цель и достигается. Дело в том, что абстрактная задача избавиться от переполнений вообще не решается, так как размер памяти, отводимой для чисел, ограничен всегда, а значит можно придумать абстрактную ситуацию, когда переполнение все равно возникнет. Однако из этого вовсе не следует, что если в реальной ситуации можно сделать так, чтобы оно не возникало, то реально работающему программисту нужно обязательно поразмышлять над этой абстрактной и в практике не существующей ситуацией.

Мало ли какие абстрактные ситуации могут быть... Например, можно пообсуждать, как обеспечить работу программы при адресном пространстве в 64 Кбайта, каким оно и было во времена первых микропроцессоров. Тогда для того, чтобы программы уложить в эту память, придуманы были различные методики, о которых сейчас никто уже и не помнит, так как проблема самоликвидировалась. Нет ее, и решать незачем.
With best regards
Pavel Dvorkin
Re[8]: Арифметическое переполнение
От: AlexRK  
Дата: 23.02.14 11:15
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Не согласен. Если есть способ избавиться от проблемы, то ИМХО решать ее не надо, а надо именно избавиться. Других проблем хватит, от которых избавиться так просто не удастся.


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

ARK>>Лично мне нравится такая цель — создание корректного ПО. Гарантированно корректного, а не с некоторой вероятностью. Под корректностью в данном контексте я понимаю отсутствие ошибок времени исполнения.

PD>А в том, что я предложил, именно эта цель и достигается.

Боюсь, что нет. Формальных гарантий ваш способ не дает.

PD>Дело в том, что абстрактная задача избавиться от переполнений вообще не решается, так как размер памяти, отводимой для чисел, ограничен всегда, а значит можно придумать абстрактную ситуацию, когда переполнение все равно возникнет.


Задача эта решается, и в первом посте темы приведен пример программного пакета, решающего ее (SPARK). Есть и другие разработки.

PD>Однако из этого вовсе не следует, что если в реальной ситуации можно сделать так, чтобы оно не возникало, то реально работающему программисту нужно обязательно поразмышлять над этой абстрактной и в практике не существующей ситуацией.


Вот мне и хочется корректности, но чтобы без очень больших усилий. С большими усилиями это уже сейчас реально.

PD>Мало ли какие абстрактные ситуации могут быть... Например, можно пообсуждать, как обеспечить работу программы при адресном пространстве в 64 Кбайта, каким оно и было во времена первых микропроцессоров. Тогда для того, чтобы программы уложить в эту память, придуманы были различные методики, о которых сейчас никто уже и не помнит, так как проблема самоликвидировалась. Нет ее, и решать незачем.


Проблема есть, просто она на практике не часто возникает.
Re[9]: Арифметическое переполнение
От: Pavel Dvorkin Россия  
Дата: 23.02.14 12:28
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Боюсь, что нет. Формальных гарантий ваш способ не дает.


То есть ? Если результат заведомо укладывается в сетку — какие еще гарантии ?

ARK>Вот мне и хочется корректности, но чтобы без очень больших усилий. С большими усилиями это уже сейчас реально.


А можно поинтересоваться, что за реальная такая задача, что нужно эту проблему решать , и иначе ее решить нельзя ? Что из себя представляют эти целые числа, о чем речь ?
With best regards
Pavel Dvorkin
Re[10]: Арифметическое переполнение
От: AlexRK  
Дата: 23.02.14 12:48
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

ARK>>Боюсь, что нет. Формальных гарантий ваш способ не дает.

PD>То есть ? Если результат заведомо укладывается в сетку — какие еще гарантии ?

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

PD>А можно поинтересоваться, что за реальная такая задача, что нужно эту проблему решать , и иначе ее решить нельзя ? Что из себя представляют эти целые числа, о чем речь ?


Реальная задача — создание языка программирования, не допускающего создания программ, содержащих потенциальные арифметические переполнения.
Re[3]: Арифметическое переполнение
От: andy1618 Россия  
Дата: 23.02.14 20:51
Оценка:
A>>В C# поведение можно изменять опциями checked-unchecked:
A>>http://msdn.microsoft.com/en-us//library/a569z7k8.aspx
A>>Довольно удобно и наглядно, кстати.

ARK>Ну окей, будет либо как в С++, либо с проверками. C# я привел

ARK>просто в качестве примера подхода к "решению" проблемы переполнения
ARK>(на самом деле, никакое это не решение).

Тогда надо "проблему" более чётко сформулировать

Кстати, для C# есть ещё и контракты:
http://research.microsoft.com/en-us/projects/contracts/
Re[4]: Арифметическое переполнение
От: AlexRK  
Дата: 24.02.14 05:40
Оценка:
Здравствуйте, andy1618, Вы писали:

A>Тогда надо "проблему" более чётко сформулировать


В принципе, я интересуюсь любой информацией на тему. Конкретные языки рояля не играют, главное — принятые там решения.

А еще лучше обсудить не существующие языки, а теоретические подходы к решению проблемы.
Например, очевидно, что для контроля переполнений надо выносить в сигнатуру функции дополнительную информацию о входных-выходных параметрах. Вопрос — какую именно и в каком виде. Чтобы это было не очень обременительно для программиста.

A>Кстати, для C# есть ещё и контракты:

A>http://research.microsoft.com/en-us/projects/contracts/

Да, я в курсе. Смесь compile-time (только примитивные случаи) и run-time проверок.
Re[9]: Арифметическое переполнение
От: Erop Россия  
Дата: 24.02.14 06:16
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Видимо, я хочу невозможного и только искусственный интеллект может помочь.


Я думаю, что возможен компромиссный подход. Типа пишем по коду что-то типа assert'ов, которые проверяют диапазоны исходных данных и результатов в тех местах, где мы хотим что-то гарантировать, а при сборке системы какой-то статический анализатор проверяет какие assert'ы могут провалиться динамически. Ну и типа, в случае провала такого assert имеем возможность какой-то обработки ситуации...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[10]: Арифметическое переполнение
От: AlexRK  
Дата: 24.02.14 07:00
Оценка:
Здравствуйте, Erop, Вы писали:

E>Я думаю, что возможен компромиссный подход. Типа пишем по коду что-то типа assert'ов, которые проверяют диапазоны исходных данных и результатов в тех местах, где мы хотим что-то гарантировать, а при сборке системы какой-то статический анализатор проверяет какие assert'ы могут провалиться динамически. Ну и типа, в случае провала такого assert имеем возможность какой-то обработки ситуации...


Да, именно такой вариант применяется в статических анализаторах типа Frama-C или Perfect Developer — причем они сами расставляют эти assert'ы, а потом решатель теорем выводит, какие из них безопасны в рантайме, а какие нет.

В принципе, этот вариант неплох, но у него есть два серьезных недостатка.
Во-первых, это очень тяжелый процесс, конпеляция больших проектов С++ на фоне этого — сущая мелочь .
Во-вторых (и это даже главнее) — опять же выходит сильная зависимость от конкретной реализации метода.

Было так:
int foo()
{
  return 2000000000;
}

...

int i = foo();
int j = Int32.Parse(Console.ReadLine());

// i = i + j;  // тут анализатор предупреждает об опасности
// поэтому ставим иф
if (j < 100000)
  i = i + j;
else
  ...


Потом поменяли библиотечную функцию foo:
int foo()
{
  return Int32.MaxValue - 1;
}

...

int i = foo();
int j = Int32.Parse(Console.ReadLine());

if (j < 100000)
  i = i + j;  // опять наш код сломался, нужен уже более сильный иф
else
  ...
Re[11]: Арифметическое переполнение
От: Erop Россия  
Дата: 24.02.14 07:22
Оценка: +1
Здравствуйте, AlexRK, Вы писали:


ARK>А вот для абстрактных функций типа "сумма всех элементов массива целых чисел" — тут уже ни входные параметры, ни выходные ничего не значат. Но таких функций, думаю, не очень много.


Они могут быть шаблонными какими-то, и компилятор сможет подставить на вход и на выход какие-то внешние условия и как-то распространить их.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[11]: Арифметическое переполнение
От: Erop Россия  
Дата: 24.02.14 07:57
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Во-первых, это очень тяжелый процесс, конпеляция больших проектов С++ на фоне этого — сущая мелочь .

ARK>Во-вторых (и это даже главнее) — опять же выходит сильная зависимость от конкретной реализации метода.

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

assert'ы тоже можно маркировать в коде какие мы подразумеваем, как вводные (аксиомы), какие, как теоремы, которые хорошо бы доказать, а какие как теоремы, которые доказать обязательно, типа критический участок ну и обработка провала в RT тоже может настраиваться...

Я думаю, что примерно такую систему обработки и предупреждения переполнений, можно интегрировать во многие языки и она окажется достаточно мощной для многих практических целей и не слишком накладной при этом.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[12]: Арифметическое переполнение
От: dilmah США  
Дата: 24.02.14 08:20
Оценка:
E>Я думаю, что примерно такую систему обработки и предупреждения переполнений, можно интегрировать во многие языки и она окажется достаточно мощной для многих практических целей и не слишком накладной при этом.

на практике нужно обрабатывать довольно дикий и слабо ограниченный поток данных и/или событий.
Эти данные/события в процессе вычислений над ними будут с близкими к 100% шансами порождать (теоретически и иногда практически) возможные переполнения.
Re[12]: Арифметическое переполнение
От: AlexRK  
Дата: 24.02.14 10:06
Оценка:
Здравствуйте, Erop, Вы писали:

E>Главное отказаться от автоматической расстановки assert'ов. Пусть программист пишет из соображений своего понимания программы, а автомат показывает, где он может доказать assert статически, при предположении верности остальных, где не может, типа это нужно использовать, как аксиомы, а где теорема слишком сложна для автоматического вывода...

E>assert'ы тоже можно маркировать в коде какие мы подразумеваем, как вводные (аксиомы), какие, как теоремы, которые хорошо бы доказать, а какие как теоремы, которые доказать обязательно, типа критический участок ну и обработка провала в RT тоже может настраиваться...

Такой вариант, конечно, возможен...

Но щас я думаю о чем-то "бескомпромиссном".

Крутится мысль о выносе в сигнатуру функции некоторой дополнительной информации о числовых параметрах. Этакие "типы для числовых типов", но не просто диапазоны.

Может быть что-то вроде
T foo(U parameter) where T : Integer, U : Integer, T > U


где "T > U" это выражение некоторого порядка над типами. Ну и какая-то простая алгебра над всем этим. Типа того, что одна функция "повышает порядок" значения, другая — понижает его, третья не меняет... И на основе этого какой-то простой value analysis для всех путей каждого значения... Хз, может это все утопия, конечно.
Re[13]: Арифметическое переполнение
От: Erop Россия  
Дата: 24.02.14 10:48
Оценка:
Здравствуйте, AlexRK, Вы писали:


ARK>где "T > U" это выражение некоторого порядка над типами. Ну и какая-то простая алгебра над всем этим. Типа того, что одна функция "повышает порядок" значения, другая — понижает его, третья не меняет... И на основе этого какой-то простой value analysis для всех путей каждого значения... Хз, может это все утопия, конечно.


Просто попробуй какие-нибудь реальные программы так разметить -- поймёшь насколько это жизненно или нет...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[13]: Арифметическое переполнение
От: Erop Россия  
Дата: 24.02.14 14:40
Оценка:
Здравствуйте, dilmah, Вы писали:

D>на практике нужно обрабатывать довольно дикий и слабо ограниченный поток данных и/или событий.

Не всегда.

D>Эти данные/события в процессе вычислений над ними будут с близкими к 100% шансами порождать (теоретически и иногда практически) возможные переполнения.

Это в ненадёжных программах так. В надёжных неудачные данные можно обрабатывать как-то особо. В любом случае запланированно обрабатывать особую ситуацию, намного надёжнее, чем в режиме "как получится, так и хорошо"
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Арифметическое переполнение
От: C.A.B LinkedIn
Дата: 24.02.14 15:09
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Может быть есть иные подходы обработки переполнений? Хочется вариант с полной скоростью и полной надежностью, но не такой сложный в использовании, как контракты из SPARK.

Можно оставить как Python'е но сделать компилятор(jit) достаточно "умным" чтобы он, анализируя код, мог рассчитать сколько потребуется памяти для результата. Но это, мягко говоря, сложная задача
Ну а для идеального случая(просто, с полной скоростью и полной надежностью) думаю эта задача не разрешима, т.к. числа бесконечны, а память компьютера нет.
Между тем,что я думаю,тем,что я хочу сказать,тем,что я,как мне кажется,говорю,и тем,что вы хотите услышать,тем,что как вам кажется,вы слышите,тем,что вы понимаете,стоит десять вариантов возникновения непонимания.Но всё-таки давайте попробуем...(Э.Уэллс)
Re[2]: Арифметическое переполнение
От: AlexRK  
Дата: 24.02.14 17:29
Оценка:
Здравствуйте, C.A.B, Вы писали:

CAB>Можно оставить как Python'е но сделать компилятор(jit) достаточно "умным" чтобы он, анализируя код, мог рассчитать сколько потребуется памяти для результата. Но это, мягко говоря, сложная задача


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

CAB>Ну а для идеального случая(просто, с полной скоростью и полной надежностью) думаю эта задача не разрешима, т.к. числа бесконечны, а память компьютера нет.


Разрешима, разрешима. Только сильно геморройно это.
Re[14]: Арифметическое переполнение
От: AlexRK  
Дата: 24.02.14 17:29
Оценка: +1
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, AlexRK, Вы писали:



ARK>>где "T > U" это выражение некоторого порядка над типами. Ну и какая-то простая алгебра над всем этим. Типа того, что одна функция "повышает порядок" значения, другая — понижает его, третья не меняет... И на основе этого какой-то простой value analysis для всех путей каждого значения... Хз, может это все утопия, конечно.


E>Просто попробуй какие-нибудь реальные программы так разметить -- поймёшь насколько это жизненно или нет...


Да, пожалуй посмотрю по коду, насколько часто вообще надо менять сигнатуры.
Re[5]: Арифметическое переполнение
От: andy1618 Россия  
Дата: 24.02.14 19:27
Оценка: +2
Здравствуйте, AlexRK, Вы писали:

ARK>А еще лучше обсудить не существующие языки, а теоретические подходы к решению проблемы.


Ну тогда лучший путь — почитать научные публикации. Довольно неплохой список, кстати,
как раз приведён в той же самой ссылке на контракты:

A>>http://research.microsoft.com/en-us/projects/contracts/


Раздел "Publications" внизу. Кстати, судя по названиям конференций, этим плотно занимаются
уже не один десяток лет:
"Proceedings of the 14th Conference on Verification, Model Checking and Abstract Interpretation"
"Proceedings of the Verified Software: Theories, Tools, and Experiments"
"Proceedings of the 3rd workshop on Numerical and Symbolic Abstract Domains"
"Proceedings of the Conference on Formal Verification of Object-oriented Software"
"Proceedings of the 17th international conference on Static analysis"
и т.д.
Re[3]: Арифметическое переполнение
От: C.A.B LinkedIn
Дата: 25.02.14 07:05
Оценка:
CAB>>Можно оставить как Python'е но сделать компилятор(jit) достаточно "умным" чтобы он, анализируя код, мог рассчитать сколько потребуется памяти для результата.
ARK>На самом деле не такая и сложная, другой вопрос, что результаты будут весьма обескураживающими — на выходе всех путей большинство значений будет иметь громадные "потенциальные" диапазоны.
Посему простого обхода путей не достаточно, нужно ещё и трассировать их для всех возможных наборов входных значений программы, затем чтобы точно определить максимум необходимой памяти для каждого результата.

CAB>>Ну а для идеального случая(просто, с полной скоростью и полной надежностью) думаю эта задача не разрешима

ARK>Разрешима, разрешима.
Не думаю, так как в некоторых случаях не возможно заранее определить сколько памяти займёт значение, простой например: инкремент значение в while цикле проверяющем какое то внешнее условие(например нажатие anykey).
Между тем,что я думаю,тем,что я хочу сказать,тем,что я,как мне кажется,говорю,и тем,что вы хотите услышать,тем,что как вам кажется,вы слышите,тем,что вы понимаете,стоит десять вариантов возникновения непонимания.Но всё-таки давайте попробуем...(Э.Уэллс)
Re[4]: Арифметическое переполнение
От: AlexRK  
Дата: 25.02.14 07:24
Оценка:
Здравствуйте, C.A.B, Вы писали:

ARK>>На самом деле не такая и сложная, другой вопрос, что результаты будут весьма обескураживающими — на выходе всех путей большинство значений будет иметь громадные "потенциальные" диапазоны.

CAB>Посему простого обхода путей не достаточно, нужно ещё и трассировать их для всех возможных наборов входных значений программы, затем чтобы точно определить максимум необходимой памяти для каждого результата.

Все пути по идее определяют и все входные значения.

CAB>>>Ну а для идеального случая(просто, с полной скоростью и полной надежностью) думаю эта задача не разрешима

ARK>>Разрешима, разрешима.
CAB>Не думаю, так как в некоторых случаях не возможно заранее определить сколько памяти займёт значение

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

CAB>простой например: инкремент значение в while цикле проверяющем какое то внешнее условие(например нажатие anykey)


Да, в данном случае максимальный размер определить нельзя, но приемлемое решение есть — анализатор просто потребует не выходить за некоторые границы при инкременте. Программист может поставить, например, проверку условия перед инкрементом.
Re[5]: Арифметическое переполнение
От: Sinix  
Дата: 25.02.14 07:56
Оценка: 4 (1)
Здравствуйте, AlexRK, Вы писали:

ARK>В принципе, я интересуюсь любой информацией на тему. Конкретные языки рояля не играют, главное — принятые там решения.


A>>Кстати, для C# есть ещё и контракты:

A>>http://research.microsoft.com/en-us/projects/contracts/
ARK>Да, я в курсе. Смесь compile-time (только примитивные случаи) и run-time проверок.
Под капотом полноценный Z3 smt solver. Он же используется в полностью верифицируемой Verve OS (pdf), так что в теории ограничений нет.

На практике придётся сильно менять язык/рантайм. Для начала:
1. Покрытие контрактами входов-выходов с полноценным выводом ограничений. Для примера:
        void A()
        {
            B("");
        }
        void B(string s)
        {
            C(s, 123);
        }
        void C(string s, int p)
        {
            Contract.NotNullOrEmpty(s);
            Contract.Ensures(p>=0);
        }

Тут верификатор должен ругаться на A — именно он передаёт пустую строку куда попало. В текущей реализации CodeContracts статический верификатор ругается на B, который по сути работает посредником и никаких проверок в себе содержать не должен.
Предлагаемое решение — копировать контракты в B() в продакшне по понятным причинам работать не будет.

2. Ко-/контравариантность контрактов по аналогии с генериками. Важно для верификации виртуальных вызовов.
3. Или никакой рефлексии/dynamic, или отказываемся от условия "полностью статически верифицируемый код".
4. Инварианты для типов. В принципе, уже есть в CodeContracts:
    struct NaturalNumber
    {
        [ContractInvariantMethod]
        protected void ObjectInvariant()
        {
            Contract.Ensures(this.Value>=0);
        }
        // ...
    }


5. Отказ от тру-параллельности, переход на модель акторов/coroutines аля Axum/Tpl DataFlow. В теории возможен и анализ разделяемого состояния как в CHESS, но на 100% верификацию это уже не катит.

Разумеется, это не все условия, но объём работы (и возможные затыки) думаю, уже понятен.
Re[5]: Арифметическое переполнение
От: C.A.B LinkedIn
Дата: 25.02.14 08:12
Оценка:
ARK>>>На самом деле не такая и сложная, другой вопрос, что результаты будут весьма обескураживающими — на выходе всех путей большинство значений будет иметь громадные "потенциальные" диапазоны.
CAB>>Посему простого обхода путей не достаточно, нужно ещё и трассировать их для всех возможных наборов входных значений программы, затем чтобы точно определить максимум необходимой памяти для каждого результата.
ARK>Все пути по идее определяют и все входные значения.
В смысле?/Не понял.

ARK>[...]

С остальным согласен.
Между тем,что я думаю,тем,что я хочу сказать,тем,что я,как мне кажется,говорю,и тем,что вы хотите услышать,тем,что как вам кажется,вы слышите,тем,что вы понимаете,стоит десять вариантов возникновения непонимания.Но всё-таки давайте попробуем...(Э.Уэллс)
Re[13]: Арифметическое переполнение
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 25.02.14 08:56
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Крутится мысль о выносе в сигнатуру функции некоторой дополнительной информации о числовых параметрах. Этакие "типы для числовых типов", но не просто диапазоны.


ARK>Может быть что-то вроде

ARK>T foo(U parameter) where T : Integer, U : Integer, T > U

Это очень похоже на то, что сделано в ATS. Там вот такая сигнатура
fn search {n,m:nat | m <= n}
  (str : string n, sub : string m) : [p:int | p <= n - m] int p = ...

гласит: функция search принимает две строки с натуральными длинами n и m, такие что m <= n, и возвращает целое число p такое, что p <= n-m. Проверяется это все в компайл-тайме, а на выходе генерится Си-код, где функция принимает два указателя и возвращает инт.
Подробнее:
http://thedeemon.livejournal.com/41545.html
Re[6]: Арифметическое переполнение
От: AlexRK  
Дата: 25.02.14 09:31
Оценка:
Здравствуйте, C.A.B, Вы писали:

ARK>>>>На самом деле не такая и сложная, другой вопрос, что результаты будут весьма обескураживающими — на выходе всех путей большинство значений будет иметь громадные "потенциальные" диапазоны.

CAB>>>Посему простого обхода путей не достаточно, нужно ещё и трассировать их для всех возможных наборов входных значений программы, затем чтобы точно определить максимум необходимой памяти для каждого результата.
ARK>>Все пути по идее определяют и все входные значения.
CAB>В смысле?/Не понял.

Может это я чего не понял? Я имею в виду, что достаточно отслеживать все возможные пути прохождения целых значений в программе или отдельном модуле. И если там встретятся взаимодействия с внешним миром — ну что ж, учтем и их при вычислении размера.
Re[14]: Арифметическое переполнение
От: AlexRK  
Дата: 25.02.14 09:49
Оценка: +1
Здравствуйте, D. Mon, Вы писали:

DM>Здравствуйте, AlexRK, Вы писали:


ARK>>Крутится мысль о выносе в сигнатуру функции некоторой дополнительной информации о числовых параметрах. Этакие "типы для числовых типов", но не просто диапазоны.


ARK>>Может быть что-то вроде

ARK>>T foo(U parameter) where T : Integer, U : Integer, T > U

DM>Это очень похоже на то, что сделано в ATS. Там вот такая сигнатура

DM>
DM>fn search {n,m:nat | m <= n}
DM>  (str : string n, sub : string m) : [p:int | p <= n - m] int p = ...
DM>

DM>гласит: функция search принимает две строки с натуральными длинами n и m, такие что m <= n, и возвращает целое число p такое, что p <= n-m. Проверяется это все в компайл-тайме, а на выходе генерится Си-код, где функция принимает два указателя и возвращает инт.
DM>Подробнее:
DM>http://thedeemon.livejournal.com/41545.html

Да-да, помню ATS. Читал доки, хотя плотно не щупал. Действительно похоже, но, ИМХО, вариант из ATS все же не для мейнстрима. Сложно для программиста.
Re[6]: Арифметическое переполнение
От: AlexRK  
Дата: 25.02.14 12:06
Оценка:
Здравствуйте, Sinix, Вы писали:

S>На практике придётся сильно менять язык/рантайм. Для начала:

S>1. Покрытие контрактами входов-выходов с полноценным выводом ограничений. Для примера:
S>Тут верификатор должен ругаться на A — именно он передаёт пустую строку куда попало. В текущей реализации CodeContracts статический верификатор ругается на B, который по сути работает посредником и никаких проверок в себе содержать не должен.
S>Предлагаемое решение — копировать контракты в B() в продакшне по понятным причинам работать не будет.

По-моему, как раз этот вариант правильный. Контракты должны быть транзитивными.

S>2. Ко-/контравариантность контрактов по аналогии с генериками. Важно для верификации виртуальных вызовов.


Да, так в Eiffel сделано (только там run-time).

S>3. Или никакой рефлексии/dynamic, или отказываемся от условия "полностью статически верифицируемый код".


Run-time рефлексию и dynamic — безусловно в топку.

S>4. Инварианты для типов. В принципе, уже есть в CodeContracts:


Опять же, в Эйфеле это уже 20 лет назад было. Инварианты нужны, естественно.

S>5. Отказ от тру-параллельности, переход на модель акторов/coroutines аля Axum/Tpl DataFlow. В теории возможен и анализ разделяемого состояния как в CHESS, но на 100% верификацию это уже не катит.


Тут не копенгаген.

S>Разумеется, это не все условия, но объём работы (и возможные затыки) думаю, уже понятен.


А что насчет переполнений?
Re[7]: Арифметическое переполнение
От: C.A.B LinkedIn
Дата: 25.02.14 14:05
Оценка:
ARK>Может это я чего не понял? Я имею в виду, что достаточно отслеживать все возможные пути прохождения целых значений в программе или отдельном модуле. И если там встретятся взаимодействия с внешним миром — ну что ж, учтем и их при вычислении размера.
Нужно отслеживать не только все возможные пути прохождения но и всё что происходит со значениями "по пути". Например:
  def f(a:Int, b:Int) = {        //у нас есть функция и мы знаем (каким-то образом) что всегда 'a' = 800..1000, 'b' = 800, потому для них нужно по 2 байта;
    val c = a - b                //здесь мы можем вычислить что всегда 'c' = 0..200, следовательно для 'с' достаточно 1 байта;
    val d = c * 1000             //для 'd' уже нужно 3 байта;
    ...                          //и т.д.
  }

Как-то так.
Между тем,что я думаю,тем,что я хочу сказать,тем,что я,как мне кажется,говорю,и тем,что вы хотите услышать,тем,что как вам кажется,вы слышите,тем,что вы понимаете,стоит десять вариантов возникновения непонимания.Но всё-таки давайте попробуем...(Э.Уэллс)
Re[8]: Арифметическое переполнение
От: AlexRK  
Дата: 25.02.14 14:07
Оценка:
Здравствуйте, C.A.B, Вы писали:

ARK>>Может это я чего не понял? Я имею в виду, что достаточно отслеживать все возможные пути прохождения целых значений в программе или отдельном модуле. И если там встретятся взаимодействия с внешним миром — ну что ж, учтем и их при вычислении размера.

CAB>Нужно отслеживать не только все возможные пути прохождения но и всё что происходит со значениями "по пути". Например:

Ну, я почему-то считал это само собой разумеющимся.
Re[7]: Арифметическое переполнение
От: Sinix  
Дата: 26.02.14 06:44
Оценка:
Здравствуйте, AlexRK, Вы писали:

S>>Тут верификатор должен ругаться на A — именно он передаёт пустую строку куда попало. В текущей реализации CodeContracts статический верификатор ругается на B, который по сути работает посредником и никаких проверок в себе содержать не должен.

S>>Предлагаемое решение — копировать контракты в B() в продакшне по понятным причинам работать не будет.

ARK>По-моему, как раз этот вариант правильный. Контракты должны быть транзитивными.

Неа. 2-3 перегрузки метода, 1 хелпер, который просто вызывает штук 5 подобных методов — и мы захлебнёмся в тонне копипасты контрактов. Я не теоретезирую, именно что пробовали использовать CodeContracts в продакшне.


S>>5. Отказ от тру-параллельности, переход на модель акторов/coroutines аля Axum/Tpl DataFlow. В теории возможен и анализ разделяемого состояния как в CHESS, но на 100% верификацию это уже не катит.


ARK>Тут не копенгаген.

Смысл в следующем — или страшная магия, или требуем, чтобы данные не изменялись другими потоками во время работы метода. Иначе с верификацией начинаются очень большие проблемы, вплоть до перехода к проверкам на основе выборок, как в CHESS:

CHESS is a tool for finding and reproducing Heisenbugs in concurrent programs. CHESS repeatedly runs a concurrent test ensuring that every run takes a different interleaving. If an interleaving results in an error, CHESS can reproduce the interleaving for improved debugging.

Ну а переход от взаимодействия потоков через глобальные переменные к передаче состояния через входные-выходные параметры неизбежно требует своей инфраструктуры аля tasks/await в c#. Причём придётся научить анализатор понимать такие штуки.

S>>Разумеется, это не все условия, но объём работы (и возможные затыки) думаю, уже понятен.

ARK>А что насчет переполнений?

А чем они принципиально отличаются от прочих ограничений? Прописываем диапазоны в контракте, если постусловия неразрешимы через SMT (как тут) — чекер предупредит.
Re[8]: Арифметическое переполнение
От: AlexRK  
Дата: 26.02.14 07:08
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Неа. 2-3 перегрузки метода, 1 хелпер, который просто вызывает штук 5 подобных методов — и мы захлебнёмся в тонне копипасты контрактов. Я не теоретезирую, именно что пробовали использовать CodeContracts в продакшне.


По-моему, все равно других вариантов нет. Иначе мы выставляем наружу зависимость от реализации. И как это может работать в условиях полиморфизма, когда мы вызываем вообще неизвестно какой метод?
ИМХО, единственный рабочий вариант — контракты на каждый метод, которые соблюдают и клиент, и поставщик.

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

S>Ну а переход от взаимодействия потоков через глобальные переменные к передаче состояния через входные-выходные параметры неизбежно требует своей инфраструктуры аля tasks/await в c#. Причём придётся научить анализатор понимать такие штуки.


А, ну это да, я убежден, что глобального состояния быть не должно. Вообще нигде.

ARK>>А что насчет переполнений?

S>А чем они принципиально отличаются от прочих ограничений? Прописываем диапазоны в контракте, если постусловия неразрешимы через SMT (как тут) — чекер предупредит.

В _принципе_ ничем, но, ИМХО, работать с диапазонами очень сложно. Нужна какая-то более простая технология. Пусть даже эта технология откинет 20% корректных программ, но позволит корректно и относительно легко создать оставшиеся 80%.
Re[9]: Арифметическое переполнение
От: Sinix  
Дата: 26.02.14 08:41
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>По-моему, все равно других вариантов нет. Иначе мы выставляем наружу зависимость от реализации.

Не, тут у нас два варианта:
1. Совмещаем явные контракты с выводом контрактов по вызываемым методам. В предельной версии это позволяет вообще отказаться от ассертов в рантайме и от части тестов. В более-менее реальной — значительно снизить необходимость в тестах.

2. Или покрывать контрактами каждый метод, даже промежуточный, или смириться с неполной верификацией кода. Это по-моему вообще ошибка в логике: делаем больше работы, получаем меньший результат.

Кстати, а чем тут плоха зависимость от реализации, если:
1. Без контрактов она всё равно выстрелит, только в рантайме
2. При смене реализации компилятор подсветит места с потенциальными ошибками
3. Если нужна слабая связность — прячем реализацию за интерфейс и прописываем контракт в интерфейсе.
?

ARK>И как это может работать в условиях полиморфизма, когда мы вызываем вообще неизвестно какой метод?

Ко- и контра- вариантность контрактов. Наследник (реализация интерфейса, делегат — неважно) не может усиливать входной и ослаблять выходной контракты.


ARK>В _принципе_ ничем, но, ИМХО, работать с диапазонами очень сложно. Нужна какая-то более простая технология. Пусть даже эта технология откинет 20% корректных программ, но позволит корректно и относительно легко создать оставшиеся 80%.


+1
Re[10]: Арифметическое переполнение
От: AlexRK  
Дата: 26.02.14 11:50
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>1. Совмещаем явные контракты с выводом контрактов по вызываемым методам. В предельной версии это позволяет вообще отказаться от ассертов в рантайме и от части тестов. В более-менее реальной — значительно снизить необходимость в тестах.

S>2. Или покрывать контрактами каждый метод, даже промежуточный, или смириться с неполной верификацией кода.

А чем плох вариант с явными контрактами на границах классов-модулей, и неявными внутри?

S>Это по-моему вообще ошибка в логике: делаем больше работы, получаем меньший результат.


Если такой перекос имеет место быть, то это, безусловно, неправильно.

S>Кстати, а чем тут плоха зависимость от реализации, если:

S>1. Без контрактов она всё равно выстрелит, только в рантайме

Пардон, не понял. Зависимость выстрелит?

S>2. При смене реализации компилятор подсветит места с потенциальными ошибками


Вот не нравится мне это. Тогда понятие интерфейса совсем размывается.

S>3. Если нужна слабая связность — прячем реализацию за интерфейс и прописываем контракт в интерфейсе.


Ну, это как раз мой вариант.

ARK>>И как это может работать в условиях полиморфизма, когда мы вызываем вообще неизвестно какой метод?

S>Ко- и контра- вариантность контрактов. Наследник (реализация интерфейса, делегат — неважно) не может усиливать входной и ослаблять выходной контракты.

Я к тому и клоню — потребуются явные контракты на интерфейсах.
Re[11]: Арифметическое переполнение
От: Sinix  
Дата: 26.02.14 13:05
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>А чем плох вариант с явными контрактами на границах классов-модулей, и неявными внутри?

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

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

Кстати, МС примерно так и делает с contract annotations, если не ошибаюсь


S>>Кстати, а чем тут плоха зависимость от реализации, если:

S>>1. Без контрактов она всё равно выстрелит, только в рантайме

ARK> Пардон, не понял. Зависимость выстрелит?

Неа, нарушение контракта Если у нас код не нарушает контракт ни одной из реализаций, то, очевидно зависимость от реализации тут никак не проявляется.

S>>2. При смене реализации компилятор подсветит места с потенциальными ошибками

ARK>Вот не нравится мне это. Тогда понятие интерфейса совсем размывается.
Есть немного. В принципе, ничего не мешает реализовать компромиссную стратегию — подсвечивать ошибку на границе модуля и даже сделать эту политику настраиваемой. Иначе у нас опять появляется необходимость в тестах для проверки корректности программы.
Re[12]: Арифметическое переполнение
От: AlexRK  
Дата: 27.02.14 11:53
Оценка: +1
Здравствуйте, Sinix, Вы писали:

ARK>>А чем плох вариант с явными контрактами на границах классов-модулей, и неявными внутри?

S>Тем, что надо отслеживать изменение контрактов и добавлять/убирать их при превращении метода в публичный.
S>Вручную — слишком много мороки.

Черт его знает, может и так.

S>С другой стороны, если это будет делаться автоматически, причём в отдельные файлы, чтоб не смешиваться с основным кодом — разница между двумя подходами исчезает.

S>Так что да, наверно лучше требовать явные контракты на границе модуля и хранить их в отдельных файлах.
S>Кстати, МС примерно так и делает с contract annotations, если не ошибаюсь

С автоматическим подходом мне не нравится один момент. При таком подходе будет _очень_ сильная зависимость от реализации. Буквально поменяли "return 1" на "return 2" — и контракт изменился. А руками человек, скорее всего, написал бы что-то более осмысленное, исходя из семантики метода.

ARK>> Пардон, не понял. Зависимость выстрелит?

S>Неа, нарушение контракта Если у нас код не нарушает контракт ни одной из реализаций, то, очевидно зависимость от реализации тут никак не проявляется.

А... ну это да. Но такие счастливые случаи вряд ли стоит рассматривать.

ARK>>Вот не нравится мне это. Тогда понятие интерфейса совсем размывается.

S>Есть немного. В принципе, ничего не мешает реализовать компромиссную стратегию — подсвечивать ошибку на границе модуля и даже сделать эту политику настраиваемой. Иначе у нас опять появляется необходимость в тестах для проверки корректности программы.

Интерфейс — это абстрагирование от реализации. Содержит только существенные детали. Если мы будем автоматически выводить контракты из реализации, то, по сути, интерфейс вообще просто исчезает — точнее, начинает содержать все детали реализации. (По крайней мере, относящиеся к обсуждаемой теме, переполнениям и т.п.)
По хорошему нам бы не надо выносить в интерфейс ВСЁ — даже автоматически. Плохо это. Что-то надо безусловно вынести, иначе дополнительного контроля мы не получим, но не всё. А вопрос, что вынести и каким образом, — это и есть Святой Грааль.
Re[13]: Арифметическое переполнение
От: Sinix  
Дата: 27.02.14 12:21
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>С автоматическим подходом мне не нравится один момент. При таком подходе будет _очень_ сильная зависимость от реализации. Буквально поменяли "return 1" на "return 2" — и контракт изменился. А руками человек, скорее всего, написал бы что-то более осмысленное, исходя из семантики метода.


Угу. Но автоматический вывод можно перекрыть явными условиями или в самом методе (например, Ensures(Return()>1), и тогда проверка остановится прямо на этих контрактах, или добавить этот же контракт где-то выше по стеку.

ARK>Интерфейс — это абстрагирование от реализации. Содержит только существенные детали. Если мы будем автоматически выводить контракты из реализации, то, по сути, интерфейс вообще просто исчезает — точнее, начинает содержать все детали реализации. (По крайней мере, относящиеся к обсуждаемой теме, переполнениям и т.п.)


Автоматические контракты ведь не отменяют возможность задать контракт вручную.
Вот и пусть "рукопашный" вариант отражается в документации, а "сгенеренный" — играет роль статических юнит-тестов. Тем более, что тесты тоже проверяют не столько контракт, сколько соответствие контракта и реализации.
Re[14]: Арифметическое переполнение
От: AlexRK  
Дата: 27.02.14 20:04
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Автоматические контракты ведь не отменяют возможность задать контракт вручную.

S>Вот и пусть "рукопашный" вариант отражается в документации, а "сгенеренный" — играет роль статических юнит-тестов.

Это верно. Но мне кажется важным обстоятельство, что язык должен подталкивать и склонять к некоторому типу действий. В принципе, ООП может быть реализовано и на С, но язык этому не способствует. C# с ключевым словом readonly способствует созданию изменяемых переменных, а Ceylon с ключевым словом variable — наоборот. Языки равны по мощности, но приучают программиста к разным вещам.
Так вот, ИМХО, автоматический вывод контрактов совершенно не способствует созданию модульного, компонентного ПО. Если вообще не препятствует этому.
Re[8]: Арифметическое переполнение
От: . Великобритания  
Дата: 27.02.14 22:35
Оценка:
Здравствуйте, C.A.B, Вы писали:

CAB> Нужно отслеживать не только все возможные пути прохождения но и всё что происходит со значениями "по пути".

Не понимаю. Вот простенькая функция:
int fun(int m, int n) {
    if (m == 0) {
        return n + 1;
    } else if (n == 0) {
        return fun(m-1, 1);
    } else {
        return fun(m-1, fun(m, n-1));
    }
}

Посчитай все пути прохождения с учётом того, что m,n не больше 5. Сколько нужно байт для хранения fun(4,4)?
avalon/1.0.432
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[9]: Арифметическое переполнение
От: AlexRK  
Дата: 28.02.14 15:20
Оценка:
Здравствуйте, ., Вы писали:

.>Здравствуйте, C.A.B, Вы писали:


CAB>> Нужно отслеживать не только все возможные пути прохождения но и всё что происходит со значениями "по пути".

.>Не понимаю. Вот простенькая функция:
.>Посчитай все пути прохождения с учётом того, что m,n не больше 5. Сколько нужно байт для хранения fun(4,4)?

Это функция Аккермана? В топку ее. И другие заковыристые функции тоже. Разумный анализатор дойдет до некоторого размера числа и дальше компилировать откажется.
Re[9]: Арифметическое переполнение
От: C.A.B LinkedIn
Дата: 28.02.14 15:44
Оценка:
Здравствуйте, ., Вы писали:
.>Не понимаю. Вот простенькая функция:
.>[...]
.>Посчитай все пути прохождения с учётом того, что m,n не больше 5. Сколько нужно байт для хранения fun(4,4)?
object Test {
  def fun(m:Int, n:Int):Int = {
    if(m == 0){
      return n + 1}
    else if(n == 0){
      return fun(m-1, 1)}
    else{
      return fun(m-1, fun(m, n-1))}}              //> fun: (m: Int, n: Int)Int
      
  fun(4,4)                                        //> java.lang.StackOverflowError
                                              
}

Oops!

Если функцию невозможно трассировать (по каким либо причинам) то и определить размер переменных не получится.
Между тем,что я думаю,тем,что я хочу сказать,тем,что я,как мне кажется,говорю,и тем,что вы хотите услышать,тем,что как вам кажется,вы слышите,тем,что вы понимаете,стоит десять вариантов возникновения непонимания.Но всё-таки давайте попробуем...(Э.Уэллс)
Re[10]: Арифметическое переполнение
От: . Великобритания  
Дата: 28.02.14 21:40
Оценка:
Здравствуйте, AlexRK, Вы писали:

CAB>>> Нужно отслеживать не только все возможные пути прохождения но и всё что происходит со значениями "по пути".

.>>Не понимаю. Вот простенькая функция:
.>>Посчитай все пути прохождения с учётом того, что m,n не больше 5. Сколько нужно байт для хранения fun(4,4)?

ARK>Это функция Аккермана? В топку ее. И другие заковыристые функции тоже. Разумный анализатор дойдет до некоторого размера числа и дальше компилировать откажется.

А не окажется ли такой анализатор на столько разумным, что будет отказываться компилировать что-то сложнее игрушечных демо-примеров?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[11]: Арифметическое переполнение
От: AlexRK  
Дата: 01.03.14 05:26
Оценка:
Здравствуйте, ., Вы писали:

.>Здравствуйте, AlexRK, Вы писали:


CAB>>>> Нужно отслеживать не только все возможные пути прохождения но и всё что происходит со значениями "по пути".

.>>>Не понимаю. Вот простенькая функция:
.>>>Посчитай все пути прохождения с учётом того, что m,n не больше 5. Сколько нужно байт для хранения fun(4,4)?

ARK>>Это функция Аккермана? В топку ее. И другие заковыристые функции тоже. Разумный анализатор дойдет до некоторого размера числа и дальше компилировать откажется.

.>А не окажется ли такой анализатор на столько разумным, что будет отказываться компилировать что-то сложнее игрушечных демо-примеров?

Однозначно на этот вопрос ответить, конечно, сложно. На мой взгляд, такого быть не должно. Существует достаточно сложное ПО, которое полностью верифицировано. Например вот: http://www.astree.ens.fr/ (раздел Industrial Applications).
Re[13]: Арифметическое переполнение
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 01.03.14 07:11
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Крутится мысль о выносе в сигнатуру функции некоторой дополнительной информации о числовых параметрах. Этакие "типы для числовых типов", но не просто диапазоны.


Контракты живут в последнем стандарте Ada 2012, заимствовано из Eiffel. Выглядит как-то так:

   procedure Dedupe (Arr: in out Int_Array; Last : out Natural) with
     Pre => Has_Duplicates(Arr),
     Post => not Has_Duplicates( Arr(Arr'First .. Last) )
             and then (for all Item of Arr'Old =>
                        (for some J in Arr'First .. Last =>
                            Item = Arr(J)))
                      -- Only duplicates removed
             and then (for all J in Arr'First .. Last =>
                        (for some Item of Arr'Old =>
                            Item = Arr(J)));
                      -- Nothing new added

   function Has_Duplicates(Arr : Int_Array) return Boolean is
   begin
      return (for some I in Arr'First .. Arr'Last-1 =>
              (for some J in I+1 .. Arr'Last => Arr(I)=Arr(J)));
   end Has_Duplicates;


То же применимо для состояния объекта

type Disc_Pt is
  record
    X, Y: Float range –1.0 .. +1.0;
  end record
  with
    Type_Invariant => Disc_Pt.X**2 + Disc_Pt.Y**2 <= 1.0;


Type_Invariant проверяется только при входе/выходе из метода. Поэтому код

P.X := 1.0;
P.Y := 0.0;


пройдет проверку даже если в начале P.Y было равно 1.0.

здесь
Re[14]: Арифметическое переполнение
От: AlexRK  
Дата: 01.03.14 08:21
Оценка:
Здравствуйте, Mystic, Вы писали:

M>Здравствуйте, AlexRK, Вы писали:


ARK>>Крутится мысль о выносе в сигнатуру функции некоторой дополнительной информации о числовых параметрах. Этакие "типы для числовых типов", но не просто диапазоны.


M>Контракты живут в последнем стандарте Ada 2012, заимствовано из Eiffel. Выглядит как-то так:


Да, я слышал про новый стандарт. Похоже на Эйфель, хотя, ИМХО, синтаксис страшнее и менее последователен. Эйфель сильно опередил свое время.
Все проверки, естественно, в рантайме?

Вообще, конечно, контракты — это однозначно хорошо, но для такой простой (даже не простой, а вездесущей) вещи, как арифметические операции, это серьезный оверкилл. Никто не будет писать их в обычном коде только из-за того, чтобы предотвратить мифический случай переполнения, которое на 95% не возникнет за все время эксплуатации этого куска кода (а потом его просто выбросят или перепишут). А если язык будет заставлять делать это, то этот язык просто не будут использовать. Нужен какой-то совершенно иной подход, поисками которого я озабочен.
Re: Арифметическое переполнение
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 01.03.14 09:16
Оценка: 106 (3) +1
Здравствуйте, AlexRK, Вы писали:

ARK>Думаю над сабжевым вопросом. Существующие языки программирования разбираются с переполнением по-разному:


Подумалось мне, что программисты часто злоупотребляют общими абстрактными решениями, забывая о практических аспектах. Я бы начинал больше с того, как обычно требуется реагировать на переполнение с точки зрения логики приложения. Мы получим:

A. Переполнение может не быть ошибкой, это может быть желаемый эффект в случае вычисления CRC, разных хэшей, кольцевого буфера и т. п.
B. Переполнение может быть нежелательным поведением, проводящей к ошибке.

Замечу, что если поведение A не поддерживается языком, то реализовать его может быть нетривиально. Даже не говоря про эффективность. Допустим в некотором языке у нас есть тип U64, который при любом переполнении бросает исключение. Типа U128 нет. Возникает вопрос, как реализовать метод, который выполнит сложение без учета переполнения? У меня затруднение.

Еще один разрез получится в случае требуемого поведения программы, если ошибка все-таки возникла в релизе. Тут есть варианты

1. Выполнить любой ценой. Например, в игре пользователю было бы очень грустно получить сообщение: "ошибка при вычислении следующего действия босса. Загрузите прошлое сохранение".
2. Остановить выполнение действия. Зачислить кому-то на счет 18446744073709551610 ¥ хоть и не смертельно, но неприятно.

Эти варианты объединяет поведение программы в отладочной сборке: как-то сообщить пользователю о неприятности. Но поведение в релизе отличается.

Также есть аспект стоимости ошибки:

a. ошибка в релизе стоит мало (один пользователь из тысячи открыл файл размером больше 4G в текстовом редакторе)
b. ошибка в релизе стоит много (ошибка в наводке ядерной боеголовки и хана мировому империализму)

И последний аспект состоит в производительности:

α. Мы сражаемся за каждый такт
ß. По сравнению с обращением к SQL-серверу экономия на арифметика выполняется чуть менее чем мгновенно.

А теперь можно думать, как это все разрулить
переполнение
Re[2]: Арифметическое переполнение
От: AlexRK  
Дата: 01.03.14 09:34
Оценка:
Здравствуйте, Mystic, Вы писали:

M>Подумалось мне, что программисты часто злоупотребляют общими абстрактными решениями, забывая о практических аспектах.


Я как раз думаю с учетом практической точки зрения.

M>A. Переполнение может не быть ошибкой, это может быть желаемый эффект в случае вычисления CRC, разных хэшей, кольцевого буфера и т. п.

M>B. Переполнение может быть нежелательным поведением, проводящей к ошибке.

В подавляющем большинстве случаев все-таки будет вариант B.

M>Замечу, что если поведение A не поддерживается языком, то реализовать его может быть нетривиально. Даже не говоря про эффективность. Допустим в некотором языке у нас есть тип U64, который при любом переполнении бросает исключение. Типа U128 нет. Возникает вопрос, как реализовать метод, который выполнит сложение без учета переполнения? У меня затруднение.


Э... а так не пойдет?

int SafeAdd(int val)
{
  return (val < Int32.MaxValue) ? (val + 1) : 0;
}


M>1. Выполнить любой ценой. Например, в игре пользователю было бы очень грустно получить сообщение: "ошибка при вычислении следующего действия босса. Загрузите прошлое сохранение".


Но программа остается непонятно в каком состоянии. Босс продолжает битву, но становится неубиваемым.

M>И последний аспект состоит в производительности:

M>α. Мы сражаемся за каждый такт
M>ß. По сравнению с обращением к SQL-серверу экономия на арифметика выполняется чуть менее чем мгновенно.

Я сейчас подумал и понял, что на самом деле для меня в списке приоритетов производительность стоит далеко не на первых местах.
А вот что я считаю ценным — так это простоту, и в том числе простоту реализации. Поэтому вариант таскать с собой рантайм с поддержкой чисел произвольной длины мне ОЧЕНЬ не нравится.
Re[2]: Арифметическое переполнение
От: andy1618 Россия  
Дата: 01.03.14 11:01
Оценка:
Здравствуйте, Mystic, Вы писали:

...
M>Еще один разрез получится в случае требуемого поведения программы, если ошибка все-таки возникла в релизе. Тут есть варианты

M>1. Выполнить любой ценой. Например, в игре пользователю было бы очень грустно получить сообщение: "ошибка при вычислении следующего действия босса. Загрузите прошлое сохранение".

M>2. Остановить выполнение действия. Зачислить кому-то на счет 18446744073709551610 ¥ хоть и не смертельно, но неприятно.

M>Эти варианты объединяет поведение программы в отладочной сборке: как-то сообщить пользователю о неприятности. Но поведение в релизе отличается.


M>Также есть аспект стоимости ошибки:


M>a. ошибка в релизе стоит мало (один пользователь из тысячи открыл файл размером больше 4G в текстовом редакторе)

M>b. ошибка в релизе стоит много (ошибка в наводке ядерной боеголовки и хана мировому империализму)


Да, эти два аспекта — классическая дилемма:

Устойчивость против корректности
Как нам показали примеры с видеоигрой и рентгеновской установкой, выбор подходящего
метода обработки ошибки зависит от приложения, в котором эта ошибка
происходит. Кроме того, обработка ошибок в общем случае может стремиться
либо к большей корректности, либо к большей устойчивости кода. Разработчики
привыкли применять эти термины неформально, но, строго говоря, эти термины
находятся на разных концах шкалы. Корректность предполагает, что нельзя
возвращать неточный результат; лучше не вернуть ничего, чем неточное значение.
Устойчивость требует всегда пытаться сделать что-то, что позволит программе
продолжить работу, даже если это приведет к частично неверным результатам.
Приложения, требовательные к безопасности, часто предпочитают корректность
устойчивости. Лучше не вернуть никакого результата, чем неправильный
результат. Радиационная машина — хороший пример применения такого принципа.
В потребительских приложениях устойчивость, напротив, предпочтительнее корректности.
Какой-то результат всегда лучше, чем прекращение работы. Текстовый
редактор, которым я пользуюсь, временами показывает последнюю на экране
строку лишь частично. Хочу ли я, чтобы при обнаружении этой ситуации
редактор завершал выполнение? Нет: когда я в следующий раз нажму Page Up или Page
Down, экран обновится, и изображение исправится.

(С) Стив Макконнелл, "Совершенный код"
Re[3]: Арифметическое переполнение
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 03.03.14 15:37
Оценка:
Здравствуйте, AlexRK, Вы писали:

M>>A. Переполнение может не быть ошибкой, это может быть желаемый эффект в случае вычисления CRC, разных хэшей, кольцевого буфера и т. п.

M>>B. Переполнение может быть нежелательным поведением, проводящей к ошибке.

ARK>В подавляющем большинстве случаев все-таки будет вариант B.


Тем не менее, вариант A, особенно Aα должен быть учтен.

ARK>Э... а так не пойдет?


ARK>
ARK>int SafeAdd(int val)
ARK>{
ARK>  return (val < Int32.MaxValue) ? (val + 1) : 0;
ARK>}
ARK>


Это просто инкремент. Не будешь же в цикле так числа складывать. Поэтому надо писать что-то вроде

int AddModU32(UInt32 a, UInt32 b)
{
  int max = UInt32.MaxValue - a;
  if (b <= max) {
    return a + b; // No overflow
  }

  return max - b; 
}


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

M>>1. Выполнить любой ценой. Например, в игре пользователю было бы очень грустно получить сообщение: "ошибка при вычислении следующего действия босса. Загрузите прошлое сохранение".


ARK>Но программа остается непонятно в каком состоянии. Босс продолжает битву, но становится неубиваемым.


В принципе понятно, в каком состоянии. Как в JA2, когда прокачанный донельзя навык скрытности персонажа приводит к переполнению, и персонаж начинает греметь как слон в посудной лавке.


M>>И последний аспект состоит в производительности:

M>>α. Мы сражаемся за каждый такт
M>>ß. По сравнению с обращением к SQL-серверу экономия на арифметика выполняется чуть менее чем мгновенно.

ARK>Я сейчас подумал и понял, что на самом деле для меня в списке приоритетов производительность стоит далеко не на первых местах.

ARK>А вот что я считаю ценным — так это простоту, и в том числе простоту реализации. Поэтому вариант таскать с собой рантайм с поддержкой чисел произвольной длины мне ОЧЕНЬ не нравится.

Зависит от решаемых задач. В данном случае речь идет о дизайне языка, так что надо или заранее предупредить о возможных проблемах с производительностью. Заранее описать, на какие из сочетаний AB12abαß ориентирован язык.
Re[4]: Арифметическое переполнение
От: AlexRK  
Дата: 03.03.14 15:45
Оценка:
Здравствуйте, Mystic, Вы писали:

M>Это просто инкремент. Не будешь же в цикле так числа складывать. Поэтому надо писать что-то вроде

M>При этом надо проверять, годиться ли этот метод для знаковых. В случае умножения застрелиться.

Ну да. Но реализовать в принципе можно.

M>Опять же, неприемлемо для Aα, потому как я смутно представляю, чтобы оптимизатор заменил этот код одной инструкцией.


Да, верно. Для битвы за каждый такт этот вариант вряд ли прокатит, разве что конпелятор будет очень крут и/или будет поддерживать специальные эвристики для оптимизаций.

ARK>>Но программа остается непонятно в каком состоянии. Босс продолжает битву, но становится неубиваемым.

M>В принципе понятно, в каком состоянии. Как в JA2, когда прокачанный донельзя навык скрытности персонажа приводит к переполнению, и персонаж начинает греметь как слон в посудной лавке.

Ну я о том и говорю.

M>Зависит от решаемых задач. В данном случае речь идет о дизайне языка, так что надо или заранее предупредить о возможных проблемах с производительностью. Заранее описать, на какие из сочетаний AB12abαß ориентирован язык.


Согласен, но главная проблема пока не в этом, а в том, чтобы придумать хоть что-то разумное.
Re[2]: Арифметическое переполнение
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 03.03.14 16:28
Оценка:
Здравствуйте, Mystic, Вы писали:

M>A. Переполнение может не быть ошибкой, это может быть желаемый эффект в случае вычисления CRC, разных хэшей, кольцевого буфера и т. п.

M>B. Переполнение может быть нежелательным поведением, проводящей к ошибке.

M>1. Выполнить любой ценой. Например, в игре пользователю было бы очень грустно получить сообщение: "ошибка при вычислении следующего действия босса. Загрузите прошлое сохранение".

M>2. Остановить выполнение действия. Зачислить кому-то на счет 18446744073709551610 ¥ хоть и не смертельно, но неприятно.

M>a. ошибка в релизе стоит мало (один пользователь из тысячи открыл файл размером больше 4G в текстовом редакторе)

M>b. ошибка в релизе стоит много (ошибка в наводке ядерной боеголовки и хана мировому империализму)

M>α. Мы сражаемся за каждый такт

M>ß. По сравнению с обращением к SQL-серверу экономия на арифметика выполняется чуть менее чем мгновенно.

M>А теперь можно думать, как это все разрулить


Продолжу свои изыски. Итак, язык должен быть эффективным в случае любой из комбинаций AB 12 ab αß.

Начинать лучше с варианта (12). Для выполнения этого требования должна быть некоторая опция (pragma), которая меняет поведение программы в debug/release. Тут я не вижу вариантов.

Далее, (AB)α. Тут варианты такие:


Такие pragm-ы реализованы во многих языках программирования, к полному удовлетворению 99% программистов.

Самый неприятный вариант Bbα. В этом случае нам надо передавать компилятору как можно больше информации о том, что происходит в программе, чтобы он мог проверять ее верифицировать (например, гарантировать отсутствие случаев переполнения). В этом случае использование обычных целых типов без дополнительной информации (диапазоны) приводит к необходимости большого количества Assert-ов, пост и предусловий. Типы-диапазоны позволяют уменьшить количество работы. Сюда же для большей прозрачности намерений, идеально вписываются модульные типы, которые дают еще дополнительный синтаксический сахар. Это путь Ada.

И добавить к существующим реализациям вроде бы нечего. Чего и следовало ожидать
Re[3]: Арифметическое переполнение
От: AlexRK  
Дата: 03.03.14 17:29
Оценка: 1 (1)
Здравствуйте, Mystic, Вы писали:

M>И добавить к существующим реализациям вроде бы нечего. Чего и следовало ожидать


Ну да, это более-менее известные подходы, применяющиеся на практике.

Что можно добавить? Я думаю, можно смотреть в направлении отказа от универсальности. Подход схож с DSL — делаем что-то одно, зато хорошо.
То бишь убираем абстрактные числовые типы вообще, а вместо них появляется семейство специальных типов — "счетчик", "деньги" и т.п., каждый со своими ограничениями.
Это просто туманное и сильно обобщенное предположение, пока что мысли не оформились, никаких деталей нет. Не уверен, что этот подход даст реальные преимущества, но направление мне кажется верным.
Re[3]: Арифметическое переполнение
От: Sinclair Россия https://github.com/evilguest/
Дата: 01.04.14 04:42
Оценка:
Здравствуйте, Mystic, Вы писали:
M>Самый неприятный вариант Bbα. В этом случае нам надо передавать компилятору как можно больше информации о том, что происходит в программе, чтобы он мог проверять ее верифицировать (например, гарантировать отсутствие случаев переполнения). В этом случае использование обычных целых типов без дополнительной информации (диапазоны) приводит к необходимости большого количества Assert-ов, пост и предусловий. Типы-диапазоны позволяют уменьшить количество работы. Сюда же для большей прозрачности намерений, идеально вписываются модульные типы, которые дают еще дополнительный синтаксический сахар. Это путь Ada.
Имхо, надо понять, какого рода ошибки хочется отлавливать, и что с ними делать.
Вот, например, классика:
public int Mid(int a, int b)
{
  return (a + b)/2; // arrgh!
}

Здесь намерения программиста прозрачны, как день. Тыкать его носом в ошибку — странно. Чего мы ожидаем от программиста? Что он напишет (a/2 + b/2)? А зачем?
В таких случаях поддержка чисел произвольной разрядности выглядит предпочтительной. Оптимизации — отдельный вопрос. Можно поработать над числами произвольной разрядности так, чтобы операции над ними были близки по производительности к нативным в случае достаточно маленьких реальных разрядностей, и разумно медленными в случае больших.

Вот — другой род ошибки:
public int Mid(int a, int b)
{
  return (a * b)/2; // arrgh!
}

Здесь мы перепутали операцию, и автоматическое расширение типа до long int только ухудшит ситуацию. Рецепт для предотвращения таких ошибок — контроль размерности.
Он же, по идее, поможет избежать ошибок масштабирования (типа * 3600 при переходе от секунд к часам, вместо наоборот).


Третий род ошибки:

public uint Factorial(uint n)
{
  switch(n)
  {
    case 0:
    case 1: return 1
    default: return n*fac(n-1);
  }
}

Ошибка, вроде бы, очевидна. Но как её исправить? Либо научиться возвращать числа достаточно большого размера (читай: произвольная разрядность), либо ограничить вход значениями от 0 до 12 (какой тогда смысл в такой функции?)
Получается, что наши "традиционные" языки программирования, построенные на концепции целых чисел фиксированной разрядности, вообще не позволяют написать осмысленную реализацию функции Factorial. Так что нужно либо отказываться от таких функций (что можно сделать, опять же, при помощи контроля размерностей), либо разрешать плавающую разрядность.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: Арифметическое переполнение
От: Jack128  
Дата: 01.04.14 19:06
Оценка:
Здравствуйте, AlexRK, Вы писали:


ARK>Это верно. Но мне кажется важным обстоятельство, что язык должен подталкивать и склонять к некоторому типу действий. В принципе, ООП может быть реализовано и на С, но язык этому не способствует. C# с ключевым словом readonly способствует созданию изменяемых переменных, а Ceylon с ключевым словом variable — наоборот. Языки равны по мощности, но приучают программиста к разным вещам.

ARK>Так вот, ИМХО, автоматический вывод контрактов совершенно не способствует созданию модульного, компонентного ПО. Если вообще не препятствует этому.

А что нить такое:


public void DoWork()
{
   Contract.GenerateContractByImplementation();// явное указание, что контракты нудно сгенерить
   
   DoWork(DefaultArg);
}


норм?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.