Разработка программного обеспечения с Адой: заглушки; отдельные и компиляционные единицы

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

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

Q2. Мой второй вопрос касается заглушек (субблоков) и использования ОТДЕЛЬНЫХ. Скажем, у меня есть основная программа следующим образом:

    WITH Ada.Float_Text_IO;
    WITH Ada.Text_IO;
    WITH Ada.Integer_Text_IO;

    PROCEDURE TEST2 IS
    A,B      : FLOAT;
    N        : INTEGER;

    PROCEDURE INPUT(A,B: OUT FLOAT; N: OUT INTEGER) IS SEPARATE;

    BEGIN -- main program
      INPUT(A,B,N);
      Ada.Float_Text_IO.Put(Item => A);
      Ada.Text_IO.New_line;
      Ada.Integer_Text_IO.Put(Item => N);
    END TEST2;

Тогда у меня есть процедура INPUT в отдельном файле:

separate(TEST2)
PROCEDURE INPUT(A,B: OUT FLOAT; N: OUT INTEGER) IS
   BEGIN
      Ada.Float_Text_IO.Get(Item => A);
      Ada.Text_IO.New_line;
      Ada.Float_Text_IO.Get(Item => B);
      Ada.Text_IO.New_line;
      Ada.Integer_Text_IO.Get(Item => N);
   END INPUT;

Мои вопросы:

a) AdaGIDE предлагает мне сохранить файл процедуры INPUT как input.adb. Но затем при компиляции основной программы test2 я получаю предупреждение:

warning: subunit "TEST2.INPUT" in file "test2-input.adb" not found
cannot generate code for file test2.adb (missing subunits)

Для AdaGIDE это скорее ошибка, так как приведенные выше предупреждения появляются перед сообщением:

Compiling...
Done--error detected

Поэтому я переименовал файл input.adb в test2-input.adb, как было предложено мне AdaGIDE при компиляции. Теперь при компиляции основного файла у меня нет никаких предупреждений. Теперь мой вопрос: можно ли писать

PROCEDURE INPUT(A,B: OUT FLOAT; N: OUT INTEGER) IS

как я сделал в файле субблока test2-input.adb, или лучше написать более описательный термин, например

PROCEDURE TEST2-INPUT(A,B: OUT FLOAT; N: OUT INTEGER) IS

чтобы подчеркнуть, что вход процедуры имеет родительскую процедуру test2 ? Эта мысль следует из того, что AdaGIDE намекает мне на test2-input.adb, как я упоминал выше.

б) Мой следующий вопрос:

Если я хорошо понимаю порядок компиляции, то я должен сначала скомпилировать основной файл test2.adb, а затем заглушку test2-input.adb. При компиляции заглушки получаю сообщение об ошибке:

cannot generate code for file test2-input.adb (subunit)
Done--error detected

Однако теперь я могу сделать привязку и линковку для test2.adb и запустить программу.

Я хотел бы знать, я сделал неправильно, пытаясь скомпилировать заглушку test2-input.adb или ее не следует компилировать?

Q3. Какая польза от субъединиц? Просто разбить большую программу на более мелкие части? Я знаю, что возникает ошибка, если в субюните не помещаются операторы между BEGIN и END. Таким образом, это означает, что всегда нужно помещать туда утверждение. И если кто-то хочет написать операторы позже, он всегда может поместить оператор NULL между BEGIN и END в субблоке и вернуться к последнему позже. Это то, как программная инженерия делается на практике?

Большое спасибо...


person yCalleecharan    schedule 11.07.2010    source источник
comment
Меня интересует выбор Ады. Было ли это основано на требованиях работы/клиента? Статистика языка (например, langpop.com) указывает на то, что этот язык не является предпочтительным для большинства проектов.   -  person Peter Rowell    schedule 11.07.2010
comment
Ну, я знаю несколько языков, таких как Basic, Pascal, C и Matlab (если этот можно рассматривать как язык программирования). Я решил выучить Аду, так как это строго типизированный язык, который помогает избежать ошибок, которые могут легко проникнуть в другие языки, которые я изучал раньше. А Ада продвигает передовые методы разработки программного обеспечения. Я не могу найти лучшего языка программирования. C может быть быстрее, но его сложнее поддерживать, чем многословный Ada. Я выбираю Аду не из-за скорости выполнения, мне нужны точные результаты, а ее отдельные блоки компиляции очень помогают при разработке большой программы.   -  person yCalleecharan    schedule 11.07.2010
comment
@yCalleecharan: Вы прекрасно понимаете преимущества и вклад Ады в качество и производительность программного обеспечения. И на самом деле его производительность тоже неплохая: groups.google.com/group/comp.lang.ada/browse_thread/thread/   -  person Marc C    schedule 11.07.2010
comment
Спасибо Марк за ваш комментарий. Мне пришлось просмотреть несколько учебников, прежде чем я начал понимать методологию разработки программного обеспечения на Аде.   -  person yCalleecharan    schedule 11.07.2010
comment
@Peter Rowell - Такое отношение прекрасно и хорошо, если ваша цель состоит в том, чтобы быть, по крайней мере, таким же хорошим, как и все остальные. Если вместо этого вы хотите стать лучше, вы не добьетесь этого, делая то, что делают все остальные. Вы должны искать инструменты, которые могут дать вам преимущество.   -  person T.E.D.    schedule 12.07.2010
comment
@ТЕД. - в вашем рассуждении есть ряд ошибок/ошибок: 1) Что в моем вопросе было какое-то отношение; 2) что программы ADA изначально спроектированы лучше, чем программы, написанные на языке X, 3) что умение работать с ADA даст ему какое-либо преимущество в текущей экономике. Я буквально потерял счет количеству языков, с которыми я работал за последние 35 с лишним лет, но одна постоянная вещь, которую я обнаружил, заключается в том, что хорошая инженерия — это скорее состояние ума и дисциплина, чем какой-либо конкретный язык. FWIW, основываясь на многолетнем опыте, в настоящее время я предпочитаю Python.   -  person Peter Rowell    schedule 12.07.2010


Ответы (3)


Q1: Это отличная практика.

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

Q2: Я считаю, что AdaGIDE на самом деле использует компилятор GNAT для всей компиляции, поэтому именно GNAT отвечает за допустимые имена файлов. (Это можно настроить, но если у вас нет очень веской причины для этого, гораздо проще просто следовать соглашениям об именах файлов GNAT/AdaGIDE.) Тем не менее, более уместным для вашего вопроса является то, что нет веских причин для включения родителя блок как часть имени отдельного блока. Но посмотрите ответ на Q3...

Q3: Подблоки были введены в первой версии Ады — Ада 83 — отчасти для того, чтобы упростить модульность кода и обеспечить отложенную разработку и компиляцию. Тем не менее, практика разработки программного обеспечения на языке Ada в значительной степени отказалась от использования подмодулей, все тела процедур/функций/задач и т. д. просто поддерживаются в теле пакета. Они все еще используются в некоторых областях, например, если может потребоваться версия подпрограммы для конкретной платформы, но по большей части они используются редко. Он оставляет меньше файлов для отслеживания и сохраняет весь код реализации пакета. Поэтому я настоятельно рекомендую вам просто игнорировать возможности подмодулей и размещать весь код реализации в телах пакетов.

person Marc C    schedule 11.07.2010
comment
Спасибо за понимание, особенно для Q3. Я использую AdaGIDE с компилятором AdaCore GNAT. 1 голос вверх. - person yCalleecharan; 11.07.2010

Вполне нормально разделить проблему на составные части (пакеты), каждый из которых поддерживает свой аспект. Если вы изучили Аду, было бы нормально сначала написать спецификации пакетов, поспорить (возможно, с самим собой), почему это правильный дизайн, а затем реализовать их. И это было бы нормально, я думаю, на любом языке, поддерживающем спецификации и тела — например, C.

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

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

У компиляторов есть свои правила относительно имен файлов и того, в каком порядке они могут быть скомпилированы. Когда GNAT видит

procedure Foo is
   procedure Bar is separate;

он ожидает найти тело Фу в файле с именем foo.adb, а тело Бара в файле foo-bar.adb (вы можете, я полагаю, назвать его по-другому - пакет gnatmake Naming - но это, вероятно, не стоит заморачиваться). Здесь лучше плыть по течению;

separate (Foo)
procedure Bar is

достаточно ясно.

Вы можете скомпилировать foo-bar.adb, и это проведет полный анализ и поймает почти все ошибки в коде; но GNAT не может генерировать код для этого самостоятельно. Вместо этого, когда вы компилируете foo.adb, он включает все отдельные тела в один сгенерированный объектный файл. Это, конечно, не неправильно.

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

person Simon Wright    schedule 11.07.2010
comment
Спасибо за все ценные комментарии. Я просто хочу еще раз подтвердить, что компиляция заглушки сама по себе приведет к сообщению об ошибке, как я получил, но это нормально. Главное, конечно, чтобы основная программа скомпилировалась и не было ошибок. 1 голос вверх. - person yCalleecharan; 11.07.2010
comment
Саймон, ваш ответ действительно очень полезен, но ответ Марка немного более полный, чем ваш. Вот почему я принимаю его ответ. Надеюсь, с тобой все в порядке. Я также дал вам по 1 голосу за то, что вы помогли мне, новичку, лучше изучить практику разработки программного обеспечения. - person yCalleecharan; 12.07.2010

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

begin
   null;
end;

И все функции реализованы примерно так:

begin
   return The_Return_Type'first; --'
end;

Что касается разделов... Мне они не нравятся. Я бы предпочел следовать правилу, согласно которому весь код пакета находится в теле пакета. Разделение минимально допустимо, если по какой-то причине подпрограмма огромна, но в этом случае лучшим решением почти всегда является рефакторинг кода. Так что каждый раз, когда я вижу один, это большой красный флаг.

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

person T.E.D.    schedule 12.07.2010
comment
Спасибо за отличные комментарии. 1 голос вверх. - person yCalleecharan; 13.07.2010