Помощь - Поиск - Пользователи - Календарь
Полная версия: Немного о синтаксисе и безопасности
Форум «Всё о Паскале» > Современный Паскаль и другие языки > Ада и другие языки
volvo
Итак, Новый Год, заняться особенно нечем, а давайте я вас чуть-чуть "подразню" что-ли? smile.gif Покажу вам на простых примерах некоторые возможности одного из языков программирования, который многие считают устаревшим. Не вопрос, считайте дальше, на данный момент мы пользуемся Стандартом 2005-го года, т.е., новее, чем у С++, к 2012 готовится очередная версия Стандарта.

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

Итак.

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

(Паскаль)
var i: integer;
begin
write('i = '); readln(i);

if i > 0 then writeln('positive')
else writeln('negative or zero');
end.


(Ада)
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Text_IO; use Ada.Text_IO;
procedure Hello is
i: integer;
begin
Put("i = ");
Get(i);

if i > 0 then Put_Line ("positive");
else Put_Line("negative or zero");
end if;

end;

Что бросается в глаза? "Многословность". Похоже, это - единственный недостаток Ады smile.gif

Давайте теперь немного поговорим о преимуществах.

0. Описание переменных по мере необходимости. (Показать/Скрыть)

1. Циклы For. (Показать/Скрыть)

2. Проверка логических условий. (Показать/Скрыть)

3. Оператор Goto (Показать/Скрыть)

4. Дефолтные параметры процедур/функций. (Показать/Скрыть)

5. Инициализация массивов. (Показать/Скрыть)

6. Еще немного о массивах. (Показать/Скрыть)

7. Параметры подпрограмм. (Показать/Скрыть)

8. Дженерики. (Показать/Скрыть)



Немного о безопасности

Недавно мне задали вот такой (очень, казалось бы, простой) вопрос: "Везде, где написано про язык программирования Ада, есть утверждение, что он - более безопасный, чем тот же С/С++. А в чем это выражается?"

А давайте попробуем посмотреть в чем это выражается (в основном сравнение происходит с С-подобными языками, Паскаль может не иметь многих из нижеперечисленных недостатков)...

1. Пример программы на С
#include <stdio.h>
int main () {
int length = 8265;
int width = 0252;
int height = 8292;
printf ("length = %d\n", length);
printf ("width = %d\n", width);
printf ("height = %d\n", height);
}
Программа прекрасно компилируется и запускается на выполнение...
Но каким будет ее вывод?

Вот таким будет вывод: (Показать/Скрыть)


2. Корректен ли следующий код:
#include <limits.h>

/*
Если *y - ноль и x > 0, то *k приравнять максимальному положительному числу
Если *y - ноль и x <= 0, оставить *k без изменений
Если *y - не ноль, присвоить *k значение x деленного на *y, и увеличить *y на 1
*/
void check_divide (int *k, int x, int *y) {
if (*y = 0)
if (x > 0)
*k = INT_MAX;
else
*k = x / *y /* Здесь делить на *y безопасно, поскольку нулю оно не равно */;
*y++;
}
? Несмотря на то, что программа компилируется, здесь присутствуют как минимум 4 серьёзные проблемы. Какие?

... (Показать/Скрыть)


3. Что касается ассоциативности и приоритета операций:

Что означает условие
if (x & mask == 0) ...
?

Оно компилируется, но... (Показать/Скрыть)


А вот это:
if (x < y < z) ...
?

И это тоже компилируется, но... (Показать/Скрыть)


4. Еще о синтаксисе...

Корректен ли следующий код:
// -- Если впереди "зелёный" свет - увеличить скорость
void increase_speed_if_safe (int speed, int signal) {
if (signal == CLEAR);
increase_speed ();
}
?

Код компилируется без предупреждений, но... (Показать/Скрыть)


5. Поговорим о перечислениях...

enum Alert_Type {LOW, MEDIUM, HIGH, VERY_HIGH};

void handle_alert (enum Alert_Type alert) {
switch (alert) {
case LOW:
activate_camera ();
case MEDIUM:
send_guard ();
case HIGH:
sound_alarm ();
}
}

void process_alerts () {
handle_alert (2);
...
Программа компилируется, но выполняться будет совсем не так, как кажется. В чем дело?

А дело в том, что... (Показать/Скрыть)


6. Неопределенности

Что здесь происходит:
{
int k = 0;
int v [10];
k = v [k++];
}
?
А происходит здесь... (Показать/Скрыть)


7. Проблемы с системой типов языка.

Программа компилируется, но все равно в ней что-то не так:
typedef int Time;
typedef int Distance;
typedef int Speed;

// ...
const Speed SAFETY SPEED = 120;

void increase_speed (Speed s);

// …
void check_speed (Time t, Distance d) {
Speed s = d/t;
if (s < SAFETY_SPEED)
increase_speed (t);
}

void perform_safety_checks () {
Time t = get_time ();
Distance d = get_distance ();
// …
check_speed (d, t);
}

Что именно?
Уууу... Да здесь целый букет... (Показать/Скрыть)


8. Проблема переполнения.

Что произойдет в следующем фрагменте программы на С (или на С++):

#include <limits.h>
void compute () {
int k = INT_MAX;
k = k + 1;
}

?
... (Показать/Скрыть)


Disclaimer
Только не надо говорить, что примеры-искусственные, и специально подобраны так, что Ада показана выигрышно. Попробуйте привести примеры, как избежать в С/С++ тех неоднозначностей, о которых я написал, чтобы дать возможность компилятору не пропустить ошибку или недочет программиста.

По большей части смысл данной темы - в том, чтобы показать, что большинство проблем связано с излишней "гибкостью" языка, в котором "разрешено все то, что не запрещено" (а запрещено явно очень немного вещей), что то же самое и даже гораздо большее можно сделать и без этих правил, разрешающих "всё и вся", с таким строгим синтаксисом, как у Ады.
Unconnected
Фухх, осилил) С многим сам сталкивался, вот например кажется такой код в С++

int k;
if (k=5) {...}



, и это компилировалось, насколько помню.. только непонятно, в чем заключалось условие, в успешном присваивании?

С условиями жизненно, помню, ловил такое долго) Правда, можно сделать if U1 then if U2 then ... , тогда точно будут по отдельности выполняться.

А вот такую штуку

var a:integer;
m:array [1..a] of byte;


было бы неплохо в паскале завести, давно хочу)

Ну, я так понял, что во многом Ада даёт "защиту от дурака", и если не выделываться (ну типа if (a<b<c) - тут на ходу дотумкать можно, что компилятор может не понять правильно), то скорее всего всё будет хорошо. Ну и где надо она гибше, да.. с всеуничтожающим break хорошо придумали.
volvo
Цитата
и если не выделываться (ну типа if (a<b<c) - тут на ходу дотумкать можно, что компилятор может не понять правильно), то скорее всего всё будет хорошо
Ну вот и приведи мне решение (хочешь - на Паскале, хочешь - на Сях, хочешь - на С++), которое позволит мне на этапе компиляции забраковать неправильные варианты вызова процедур/функций (я про пункт "7. Проблемы с системой типов языка") smile.gif

Цитата
я так понял, что во многом Ада даёт "защиту от дурака"
Это не совсем "защита от дурака". Это надежность программ прежде всего.

Кстати, очень многие вещи остались "за кадром": встроенная в язык работа с подзадачами/потоками (с 1983 года !!! Причем средствами языка, нет никакой зависимости ни от ОС, ни от используемого компилятора) и межпоточное взаимодействие (аналогично, средствами языка), и защищенные типы (попробуй написать потокобезопасный контейнер на Паскале, например, чтоб с ним можно было безопасно работать из десятка потоков)... И так пост большой получился... Если кому интересно - расскажу.
-TarasBer-
> Что бросается в глаза? "Многословность".

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

> Описание переменных по мере необходимости.

Это прикольно, но процедуры на более чем 100 строк считаются дурным тоном. А для коротких процедур завести переменную в начале не обломно.

> Циклы For.

+

> Проверка логических условий.

Все уже сто лет привыкли, что полной проверки нет и пользуются этим.
На крайняк можно написать if a then if b...

> Оператор Goto

+

> Дефолтные параметры процедур/функций.

+

> Инициализация массивов.

+

> Еще немного о массивах.

> (чем не "сборка мусора"?)

Надеюсь, там не сборка, а детерминированное удаление при выходе из зоны видимости? Другой автоматизации работы с памятью я не признаю.

> Параметры подпрограмм.

Не вкурил. Есть же директива const.

> Дженерики.

То есть можно делать приколы из С++, в котором шаблоны - функциональный язык, выполняющийся во время компиляции? Это интересно.

> Системы счисления

+

> Смешивание "=" и "==".

За это надо построить машину времени, вернуться в прошлое и убить Ритчи. И эта зараза во всех новых языках!!!

> Поговорим о перечислениях...

А что, перечисления Си даже в отладчике видны как числа? Я так не смогу, я привык, что в отладчике вижу нормальные имена.

> гибкие селекторы - можно сделать и так:

Да, тут у Си полный облом.

> Ошибка компиляции: несоответствие типов параметров

Это правильно, но принудительной ретипизацией это можно обойти?

> В Аде каждый раз, когда происходит переполнение выбрасывается исключение (на всех поддерживаемых платформах). То же смое касается и попытки деления на 0, и выхода за пределы массива, ну, и так далее...

Не понял, в код вставляются проверки выхода за диапазон? Это отрубаемо, надеюсь?

> только непонятно, в чем заключалось условие, в успешном присваивании?

Нет. В том, что результат присваивания не ноль.

> var a:integer;
> m:array [1..a] of byte;

И как ты это себе представляешь?
Не, ну если массив идёт в самом конце описания, то это ещё можно сделать теоретически. А если нет? То что делать с участком памяти, идущим за массивом, когда массив захотелось удлинить?




-TarasBer-
А вот что меня напрягает в синтаксисе Паскаля (и у Ады тоже, кажется, есть этот минус), так это то, что функции, не принимающие параметров, можно записывать без пустых скобочек.
Где-то была тема, в которой три человека очень долго думали, что в данном контексте значила pointer(a) - вызов метода или указатель на метод? Нужен был указатель, но почему он не вызовется, сказать наверняка было невозможно.
Да и вообще, это нарушает логичность.
volvo
Цитата
Насколько я знаю, для закрытия блока надо тоже его назвать.
Это настраиваемо. Мой компилятор с этим справляется сам, посему у меня отключено. А вообще - да, окончательную проверку на Styling программа не пройдет, пока все отступы не будут выровнены, все блоки не будут названы, и все подпрограммы не будут размещены в алфавитном порядке с предварительным описанием в файле спецификаций (некий аналог Interface-части юнитов Паскаля. Кстати, по той же причине - облегчение поиска в случае необходимости).

Цитата
А для коротких процедур завести переменную в начале не обломно.
Ниже я написал один из способов применения. Это удобно...

Цитата
Все уже сто лет привыкли, что полной проверки нет и пользуются этим.
А если мне НАДО полную проверку? Ада-решение: вместо "and then" пишется просто "and", вместо "or else" - просто "or"... Паскаль заставляет меня опять заморачиваться с директивами компиляции, остальные языки - тоже...

Цитата
Надеюсь, там не сборка, а детерминированное удаление при выходе из зоны видимости? Другой автоматизации работы с памятью я не признаю.
Я тоже не терплю языков, которые навязывают мне свой GC. По этой причине я не стал изучать ничего из .NET-а, по этой же причине не ушел на Оберон... Там именно удаление при выходе из области видимости... Сборшик мусора Стандартом Ады не запрещен, но и не навязывается. Есть - используй, нет - не используй...

Цитата
А что, перечисления Си даже в отладчике видны как числа?
Отладчик добавляет к числу еще и идентификатор. Но все равно, неявное приведение к типу int делает свое черное дело при работе программы...

Цитата
Не понял, в код вставляются проверки выхода за диапазон? Это отрубаемо, надеюсь?
Да, для этого надо пересобрать программу с другими ключами.

Добавлено через 9 мин.
Цитата
Нужен был указатель, но почему он не вызовется, сказать наверняка было невозможно.
У Ады совершенно нет этой проблемы (по крайней мере, попадать в такое положение, при котором возникала бы неоднозначность мне не приходилось). Если нужен указатель на метод - P'Access, нужен вызов метода - просто P... В Паскале - помню, было... А пустые скобки меня в Дельфи/FPC напрягают, например.
TarasBer
> Ниже я написал один из способов применения. Это удобно...

С одной стороны, удобно, с другой, не бьёт по рукам любителей простыней.

> А если мне НАДО полную проверку?

Зачем? Ради побочных эффектов вычисления операндов?
Тогда заранее в отдельные переменные записываешь результаты вычислений операндов.
По-моему это не так часто происходит, чтобы заводить отдельно оператор "и-с-полной-проверкой" и оператор "и-с-неполной-проверкой".
По крайней мере я ни разу не ощутил потребность в таком операторе.

> Там именно удаление при выходе из области видимости...

И можно создавать свои объекты, которые в автовызываемом деструкторе делают освобождения ресурсов, закрытия файлов итд?
А ГЦ недетерминирован, ставит крест на приложениях реального времени, всё равно в кривых руках память течёт (да), а в прямых, если в языке есть автовызов деструктора, нафиг он нужен? Стандартный счётчик ссылок не работает только в хитрых структурах, двусвязных списках, например, ну так для них объектную оболочку можно сделать, чтобы все опасные операции внутри реализации класса были зашиты, а оболочка это сама всё вычистит при выходе из зоны видимости.

> Да, для этого надо пересобрать программу с другими ключами.

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

> У Ады совершенно нет этой проблемы

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

А в Дельфи я нашёл эту тему с неоднозначностью:
http://www.gamedev.ru/code/forum/?id=141396
volvo
Цитата
И можно создавать свои объекты, которые в автовызываемом деструкторе делают освобождения ресурсов, закрытия файлов итд?
Угу.

-- В отдельном пакете описываем объект:
type MyObject is new Controlled with
record
... -- Тут все, что мне нужно
end record;

procedure Initialize (Obj : in out MyObject);
procedure Finalize (Obj : in out MyObject);


Для Controlled-типов процедуры Initialize и Finalize (конструктор/деструктор, можно и так) вызываются автоматически. Все, что мне останется сделать:

declare
Obj : MyObject; -- Тут вызовется Initialize
begin
-- Работаем с объектом
end; -- Тут же, при выходе из области видимости, вызовется Finalize


Если же мне захочется самому вызывать конструктор/деструктор - не надо наследоваться от Controlled...
TarasBer
> Для Controlled-типов процедуры Initialize и Finalize (конструктор/деструктор, можно и так) вызываются автоматически.

Всё, хочу перейти на Аду.
Есть какие-нибудь бесплатные среды под Вин32? Мне достаточно редактора кода и заголовков от ВинАПИ, формошлёпалку не надо.

Добавлено через 9 мин.
А, я что ещё вспомнил.
Могут ли out-параметры быть по умолчанию?
Мне не удалось в Дельфи написать var s: string = nil^, пришлось вспомнить, что передача по ссылке - это неявная передача указателя и написать s: PString = nil.
volvo
Цитата
Есть какие-нибудь бесплатные среды под Вин32?
Есть. Без формошлепалки, IDE для Win/Lin со всеми необходимыми пакетами можно взять здесь (просто выбираешь Free sortware or Academic Development, можешь даже не указывать мыло, и собираешь для себя пакет скачки. Обязательно качать Gnat GPL и Win32Ada, это как раз то, что ты описал - заголовки WinAPI и компилятор со всеми прибамбасами. Я для себя еще брал QtAda, но это - для любителя особых извращений...)

Добавлено через 8 мин.
Цитата
Могут ли out-параметры быть по умолчанию?
Нет, только In-параметры. Даже In Out не могут. А оно надо?
TarasBer
> Нет, только In-параметры. Даже In Out не могут. А оно надо?

Ну мне как-то понадобилось, чтобы функция когда надо - возвращала значение в некий параметр, а когда не надо - не возвращала, ну то есть иногда он мне не интересен, а заводить спец переменную ради возвращения того, что мне не надо, некрасиво. Пришлось извращаться через передачу указателя.
volvo
Цитата
а заводить спец переменную ради возвращения того, что мне не надо, некрасиво.

lol.gif Я посмотрю, что ты скажешь, когда Ада заставит тебя вместо
ReleaseDC (hwnd, My_DC);
написать
i_Result : Win32.INT;
-- ...
i_Result := ReleaseDC (hwnd, My_DC);
, ибо функция должна в любом случае значение вернуть (а еще интереснее - если подряд вызываются три функции, одна возвращает Win32.BOOL, вторая - Win32.INT, а третья - Win32.LONG. Вот и опишешь три переменных: i_Result, b_Result и L_Result, хотя они тебе тоже не особо и сдались...). Это тебе не С, где на такие вещи можно просто не обращать внимание. Это - Ада. Не сделал - не откомпилировал...

Все Сиш-ные и Дельфийские замашки, основанные на хаках и бесконтрольном приведении типов придется забыть. Ибо Ада тебе даже не гарантирует, что матрица хранится по строкам. Она может храниться и по столбцам, как в Фортране...
Lapp
volvo, спасибо за это эссе, +1 good.gif

Я встряну мимоходом.
Цитата(volvo @ 4.01.2011 20:43) *
А если мне НАДО полную проверку? Ада-решение: вместо "and then" пишется просто "and", вместо "or else" - просто "or"... Паскаль заставляет меня опять заморачиваться с директивами компиляции, остальные языки - тоже...
Я уже как-то говорил об этом.. За всю свою практику я не встретил ни одного случая, где это было "НАДО". Все примеры на эту тему как правило сродни чесанию правой пяткой за левым ухом. Так что я для себя сейчас считаю, что если мне это вдруг "НАДО" - значит, что-то не так )). Логика - штука хитрая. Красота выражения говорит о его правильности обычно. Так что лично я не буду возражать, если мне однажды все-таки придется "заморочиться с директивами".. smile.gif

Цитата(Unconnected @ 4.01.2011 15:05) *
Фухх, осилил) С многим сам сталкивался, вот например кажется такой код в С++
int k;
if (k=5) {...}

, и это компилировалось, насколько помню..
А вот это как раз очень жизненно. С одной стороны, этой ошибке подвержены практически все, кто переходит с Паскаля на Си. А с другой,
Цитата
только непонятно, в чем заключалось условие, в успешном присваивании?
- такая конструкция очень удобна и часто применяется. Значит она следующее: присваиваем k некоторое значение (конечно, там стоит обычно выражение из переменных или функций), и если оно ненулевое, то..
Забавно, что паскалисту (я говорю про начинающих, а не зрелых, которые осознают потребность такого даже в Паскале) такая конструкция совершенно чужда, он просто не мыслит в таких категориях )).

Offtop:
Это сообщение не увидело бы свет, если бы FF после крэша машины (блин, это меня уже напрягает, надо что-то делать) не восстановил практически полный его текст. За что ему спасибо! smile.gif


подправил, была опечатка..
TarasBer
> Все Сиш-ные и Дельфийские замашки, основанные на хаках и бесконтрольном приведении типов придется забыть.

Э, а как же прямая отрисовка в буфер? У меня есть только указатель на начало пиксельного блока, ширина и высота картинки. Вся отрисовка держится на бесконтрольной ретипизации.

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

А такая?


if (i := 5) <> 0 then begin
end;

TarasBer
> for i in 1 .. 10 loop -- i вообще не описывается

А если написать так?
for i in 1 .. L.Count - 1 loop
то, надеюсь, будет использован знаковый тип? Вспомнился прикол, как некоторые брали word и материли "глючную дельфу", которая почему-то для пустого списка пыталась перебирать индексы от 0 до 65535.
volvo
Цитата
Вся отрисовка держится на бесконтрольной ретипизации.
Для крайних случаев (когда без этого уже совсем никак не обойтись) есть модуль Ada.Unchecked_Conversion, который позволяет привести любой тип к любому другому. Но слишком часто прибегать к его услугам (в смысле строить программу так, чтобы были сплошные преобразования типов, потому что "я сам знаю, как мне делать, почему меня компилятор ограничивает?") - это моветон.

Цитата
А если написать так?
for i in 1 .. L.Count - 1 loop
то, надеюсь, будет использован знаковый тип?

Нажмите для просмотра прикрепленного файла
Еще сомневаешься?
TarasBer
> Я посмотрю, что ты скажешь, когда Ада заставит тебя вместо

Мда, я представил для SendMessage... Ну для самый частых функций ещё обёртку можно сделать, проглатывающую возвращаемое значение. Кстати, инлайн-функции там есть?

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

А мне, кроме графического модуля, нигде и не надо.
В Д7 я ещё делал наглые преобразования к типу, с которым работает некоторая структура, но это от отсутствия генериков.

> Еще сомневаешься?

Тогда нормально.
А вместо диапазона писать название перечислимого типа можно?
for i in TMyType do...
А то так запарило в одном месте для 3 разных типов писать

var
imt: TMyType;
...
for imt := Low(TMyType) to High(TMyType) do...



Что ещё не хватало в Дельфи.
А, контроль вариантных полей во время выполнения (во время компиляции, увы, никак).


type
TMyRec = record
case Selector: byte of
0: b: array [0 .. 9] of byte;
1: w: array [0 .. 4] of word;
end;
end;
...
r.Selector := 0;
r.w[0] := 1; // чтобы тут выдавало ошибку выполнения (потому что поле относится к другому значению селектора),
// разумеется, при включённых флагах компиляции

volvo
Цитата
А вместо диапазона писать название перечислимого типа можно?
Легко...
Нажмите для просмотра прикрепленного файла
Будет перебираться весь тип, от самого первого до самого последнего значения, и всего делов. Обрати внимание, для того чтобы напечатать идентификатор элемента, достаточно сделать MyType'Image. Это тоже встроено в язык, не нужны никакие Дельфийские шаманства с RTTI.

Цитата
А, контроль вариантных полей во время выполнения (во время компиляции, увы, никак).

Увы - это ты про Дельфи? smile.gif Вот это что-ли?
Нажмите для просмотра прикрепленного файла

(правда тут у тебя небольшой облом - селектор должен задаваться один раз, при инициализации переменной. Менять его ты не имеешь права. Задавать переменную без селектора - тоже). Но как доп. средство для контроля - пойдет.
TarasBer
> Обрати внимание, для того чтобы напечатать идентификатор элемента, достаточно сделать MyType'Image.

Да, такую фичу я тоже хотел (типа чтобы Str(mt, S) писало в S имя mt), но так, в качестве баловства, серьёзного применения ей пока не вижу.
Image - это функция, возвращающая строку?

> правда тут у тебя небольшой облом - селектор должен задаваться один раз, при инициализации переменной

Это я на стадии компиляции должен указывать значение селектора?
Тогда что вообще дают такие вариантные записи?
Или всё это не обязательно?
volvo
Ну, максимум что можно предложить - это описать запись как "нелимитированную", то есть дать селектору значение по умолчанию, что позволит описывать экземпляр структуры без начального значения селектора, и, следовательно, разрешит менять селектор в рантайме. Только менять его можно будет только вот таким образом:
Нажмите для просмотра прикрепленного файла
(то есть, в агрегате должны присутствовать все поля, связанные с данным селектором. Как видишь, это очень просто делается. А потом - уже меняй любое нужное тебе значение. Если то, что ты меняешь недоступно при установленном в настоящий момент селекторе, вылетит CONSTRAINT_ERROR).
TarasBer
> и, следовательно, разрешит менять селектор в рантайме

Во, тогда нормально.

> Если то, что ты меняешь недоступно при установленном в настоящий момент селекторе, вылетит CONSTRAINT_ERROR

Да, этого я и хотел (но опять же, как отключаемую опцию компилятора).

Я понял, почему Image для перечислимых типов для меня бесполезен. Типы я перечисляю в коде на английском, сообщения для пользователя пишу на русском (возможность писать идентификаторы на русском не предлагать, запарюсь переключаться). Да, будь я носителем языка с латинницей, оценил бы эту возможность по достоинству.

Система типов интересная (я про Unsigned_8 итд), намного логичнее, чем long long long int и прочие нелепые названия.
volvo
Цитата
этого я и хотел (но опять же, как отключаемую опцию компилятора).
Обрати внимание на вывод внизу экрана, ошибки уже нет. Достаточно было просто поставить одну-единственную галочку...

TarasBer
Я нашёл в википедии забавный пример, который показывает, зачем в Си такой switch.
http://ru.wikipedia.org/wiki/Устройство_Даффа


strcpy(to, from, count)
register char *to, *from;
register count;
{
register n = (count + 7) / 8;
switch (count % 8) {
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n > 0);
}
}



Правда, остаётся вопрос, зачем нужен этот пример.
Lapp
Цитата(TarasBer @ 9.01.2011 13:53) *
зачем в Си такой switch.
Аму-дарьеть.. Я б сам ни в жизь не допер..
volvo
Цитата
остаётся вопрос, зачем нужен этот пример.
Чтоб огрести проблем с выходом новой редакции Стандарта (и новой версии компилятора, придерживающейся этой редакции).

Тема разделена: Настройка GPS (IDE для Ады)
volvo
Из недавнего - просто вспомнилось (к вопросу о безопасности и контроле программиста над происходящим в программе)...

Все помнят такую особенности Дельфи / Object Pascal, как передачу объекта класса по ссылке, и к чему это приводит, да? Иллюстрация:

// есть вот такой класс
type
T = class
value : Integer;
constructor Create(AValue : Integer);
procedure Print;
end;

constructor T.Create (AValue : Integer);
begin
Inherited Create;
Value := AValue;
end;

procedure T.Print;
begin
writeln(value);
end;


// и вот такая процедура (полиморфная)
procedure DoSomething (Const Obj : T);
begin
Obj.Print;
Obj.value := 10; // <--- Изменение объекта
end;

// Используется вот так
var
Obj : T;
begin
Obj := T.Create(5);
Obj.Print;

DoSomething(Obj);

Obj.Print;
Obj.Free;
end.


Как вы думаете, что в данном случае означает Const? Неужели - то, что объкет класса нельзя изменить, и Дельфи мне выдаст ошибку компиляции или хотя бы аварийно завершит программу при попытке изменения объекта Obj? Да ничего подобного. Легко изменяется любое поле объекта, хоть напрямую, хоть через методы/свойства.

Это по меньшей мере нелогично. Если я передаю объект в процедуру с таким прототипом:
procedure DoSomething (Const Obj : T);
, я ожидаю, что объект не будет изменен. Дельфи мне этого обеспечить не может. В отличие от С++. Что делается в Аде? Тут как раз все в порядке:

(описание класса)
--  Specification file (ADS)
package MyObj is

type Root is tagged record
A : Integer;
end record;

procedure Print (Obj : Root);
procedure Set_Value (Obj : in out Root; Value : Integer);

end MyObj;

-- Body file (ADB)
with ada.Text_IO; use ada.Text_IO;

package body MyObj is

procedure Print (Obj : Root) is
begin
Put_Line (Integer'Image (Obj.A));
end Print;

procedure Set_Value (Obj : in out Root; Value : Integer) is
begin
Obj.A := Value;
end Set_Value;

end MyObj;


(основная программа)
   procedure Polymorphic (Obj : in MyObj.Root) is
begin
Obj.Print; -- Да пожалуйста, объект не будет изменяться
Obj.Set_Value (3); -- А вот тут - стоп !!! Это изменит объект
end Polymorphic;

, компиляция прекратится при попытке вызвать метод, модифицирующий Obj. Так что вот вам еще одна ступень защиты. Если же параметр Obj описать как in out, то есть, изменяемый - то и Set_Value прекрасно отработает.
TarasBer
Эээ, а кто может обеспечить безопасность данных, передаваемых по указателю, даже если он передан с модификатором const?
Что касается классов, то в Дельфи класс - это указатель.
А в С++ просто классы сделаны как положено (да, мне С++ная концепция ООП нравится куда больше), а не в виде указателей, которые ещё и надо РУКАМИ удалять.
В Дельфи, чтобы передать содержимое, а не указатель, надо пользоваться не class, а object.
Короче, ООП от Борланда мне (из-за этого в том числе) стало казаться настолько неестественным, что я стал жёстко структурить, выдавая иногда перлы типа http://govnokod.ru/4249 или http://govnokod.ru/5261 (да, именно тут мне захотелось контроля обращения к вариантному полю в зависимости от знаения селектора).
Зато, я считаю, только после таких вещей начинаешь по-настоящему понимать смысл ООП, а не так, что дяди сказали, что ООП типо крута, а сам сидишь и лепишь его везде.
volvo
Цитата
Эээ, а кто может обеспечить безопасность данных, передаваемых по указателю, даже если он передан с модификатором const?
Хм. Значит, надо было отменять модификатор const, или доделывать его, чтоб он работал со всеми сущностями, а не отсылать программиста разбираться, является ли классом строка, и почему на нее спецификатор действует, а на другие классы - нет.

Тем более, что это возможно, как оказалось. В Аде объекты тоже не передаются по значению, однако если я заказал доступ только по чтению - то он таким и будет, и мне не надо волноваться, что мой объект будет изменен в результате.
TarasBer
Забавно, но самый страшный баг был написан именно на Аде:

http://ru.wikipedia.org/wiki/Авария_ракеты...5_(4_июня_1996)
volvo
Блин... Это не проблема Ады. Есть посекундный анализ этой катастрофы, который показал, в чем на самом деле была проблема. Показать? Кому-то просто выгодно муссировать слухи, о том, что именно язык МО США дал такой сбой...
TarasBer
> Есть посекундный анализ этой катастрофы, который показал, в чем на самом деле была проблема. Показать?

Да.

> Кому-то просто выгодно муссировать слухи, о том, что именно язык МО США дал такой сбой...

Во всех официальных источниках обвиняется именно программное обеспечение.
Хотя я понимаю, что С++ бы туда за пушечный выстрел не допустили и с ним бы ракета, скорее всего, даже не взлетела бы.
volvo
Цитата
Во всех официальных источниках обвиняется именно программное обеспечение.
Уточняю: во воех русскоязычных официальных источниках... Вот перевод отчета Комиссии по Расследованию: http://forums.airbase.ru/2007/03/t54337--a...shibk.2155.html

( на всякий случай - вот ссылка на англоязычный оригинал: http://homepages.inf.ed.ac.uk/perdita/Book/ariane5rep.html )

Что видим? А вот что:
Цитата
Было обосновано, что в случае события отмены старта период в 50 сек. после H0-9 будет достаточным для того, чтобы наземное оборудование смогло восстановить полный контроль за Инерциальной Платформой без потери информации – за это время Платформа прекратит начавшееся было перемещение, а соответствующий программный модуль всю информацию о ее состоянии зафиксирует, что поможет оперативно возвратить ее в исходное положение (напомним, что все это в случае, когда ракета продолжает находиться на месте старта). И действительно, однажды, в 1989 г., при старте под номером 33 ракеты Ariane 4, эта особенность была с успехом задействована.

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

<...>

Расследование показало, что в данном программном модуле присутствовало целых семь переменных, вовлеченных в операции преобразования типов. Оказалось, что разработчики проводили анализ всех операций, способных потенциально генерировать исключение, на уязвимость. И это было их вполне сознательным решением добавить надлежащую защиту к четырем переменным, а три – включая BH – оставить незащищенными. Основанием для такого решения была уверенность в том, что для этих трех переменных возникновение ситуации переполнения невозможно в принципе. Уверенность эта была подкреплена расчетами, показывающими, что ожидаемый диапазон физических полетных параметров, на основании которых определяются величины упомянутых переменных, таков, что к нежелательной ситуации привести не может. И это было верно – но для траектории, рассчитанной для модели Ariane 4. А ракета нового поколения Ariane 5 стартовала по совсем другой траектории, для которой никаких оценок не выполнялось. Между тем она (вкупе с высоким начальным ускорением) была такова, что "горизонтальная скорость" превзошла расчетную (для Ariane 4) более чем в пять раз.

Но почему же не была (пусть в порядке перестраховки) обеспечена защита для всех семи, включая BH, переменных? Оказывается, для компьютера IRS была продекларирована максимальная величина рабочей нагрузки в 80%, и поэтому разработчики должны были искать пути снижения излишних вычислительных издержек. Вот они и ослабили защиту там, где теоретически нежелательной ситуации возникнуть не могло. Когда же она возникла, то вступил в действие такой механизм обработки исключительной ситуации, который оказался совершенно неадекватным.

Этот механизм предусматривал следующие три основных действия. Прежде всего, информация о возникновении нештатной ситуации должна быть передана по шине на бортовой компьютер OBC; параллельно она – вместе со всем контекстом – записывалась в перепрограммируемую память EEPROM (которую во время расследования удалось восстановить и прочесть ее содержимое), и наконец, работа процессора IRS должна была аварийно завершиться. Последнее действие и оказалось фатальным – именно оно, случившееся в ситуации, которая на самом деле была нормальной (несмотря на сгенерированное из-за незащищенного переполнения программное исключение), и привело к катастрофе.


Итого: недостаток вычислительной мощности, из-за которого программисты осмысленно снимают защиту (что в результате приводит к сбою) - это проблема языка? Нет. То, что траектория Ариан-5 не оценивалась во всей серьезностью, а кто-то положился на то, что все будет так же, как и в Ариан-4 - это что, проблема Ады? Нет. В чем же тогда обвиняют язык? В том, что кто-то неизвестно почему не мог усилить процессоры? В том, что не было выделено средств на тестирование баллистических характеристик? В том, что кто-то вообще не дал программистам просмотреть код, чтоб не платить им, а заявил, что будет использоваться прекрасно показавшая себя в прошлом проекте часть? Почему Ада виновата?
TarasBer
> Итого: недостаток вычислительной мощности, из-за которого программисты осмысленно снимают защиту (что в результате приводит к сбою) - это проблема языка?

Это может быть проблемой компилятора, не умеющего эффективно оптимизировать код (не знаю, насколько это относится к Аде).
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.