"Введение в структурное программирование на языке C#"

Автор: Терехина Анна Олеговна
Должность: учитель информатики
Учебное заведение: Лицей №1533(информационных технологий)
Населённый пункт: Москва
Наименование материала: конспект
Тема: "Введение в структурное программирование на языке C#"
Дата публикации: 11.07.2016







Вернуться назад       Перейти в раздел





Текстовая часть публикации

ООП 1-1
Введение
Моя задача – научить правильно, эффективно программировать, писать «хорошие», а это значит – правильно оформленные, грамотные (с эффективным использованием имеющихся конструкций), логически продуманные программы. Это, кстати, самое сложное в программировании, так как программист должен сначала решить задачу в своей голове, продумать все до мельчайших подробностей, а только потом садиться за кодирование. Наши программы, чтобы стать действительно работающими, должны быть абсолютно выверены и просты.
Роль языка программирования
Часто спрашивают, какой язык должен прежде всего знать программист. Ответ на этот вопрос не изменился с тех пор, когда еще не придумали программирование: свой родной язык. Русский, английский, испанский… Давайте попробуем понять, что это так. Посмотрим, как происходит процесс создания программы. Сначала необходима
постановка задачи
. На этом этапе мы должны разобраться, какие начальные состояния нас интересуют, и какие конечные состояния мы хотим получить. Например, на входе — последовательность покупок в универсальном магазине, а на выходе — месячный отчет о продажах. На входе — текст, на выходе — список орфографических ошибок в этом тексте. И так далее. (Этап «черный ящик») Второй этап -
разработка алгоритма
(или использование уже известного). Что такое алгоритм? Чем он отличается от текста программы? Разница состоит в том, что алгоритм, как правило, не имеет отношения к языку программирования. Алгоритм можно описать словами, картинкой или как угодно еще. Способов великое множество. В качестве примера – случай из жизни: Эта история началась 20 января 2000 года, когда судья Южного Округа Нью-Йорка вынес решение, запрещающее распространять код программы, способной декодировать защиту DVD дисков. Международное сообщество программистов отреагировало на этот запрет своеобразным видом протеста. Раз запрещено публиковать текст программы, решили они, но есть статья Конституции, гарантирующая свободу слова, то можно создать некое представление алгоритма, которое само не являлось бы программой, но по которому можно было бы легко восстановить текст запрещенной программы. Таким образом впервые в истории был проведен эксперимент по описанию алгоритма наибольшим возможным числом способов. Было создано несколько десятков различных способов представления алгоритма decss. В том числе: изложение в виде текста на английском языке, математических формул, чтения текста программы вслух, электронной схемы, рисунков, фильма и даже в виде хайку. Алгоритм разработан и по-существу, решение уже есть. Следующий этап -
Кодирование
как раз и означает запись алгоритма на выбран- ном языке программирования. Какова же роль языка в этом процессе?
Язык определяет способ мышления.
Согласно гипотезе лингвистической относительности, иначе называемой «гипотеза Сепира-Уорфа», люди, говорящие на разных языках, по-разному воспринимают мир и по- разному мыслят. Неизвестно, верна ли эта гипотеза в отношении естественных языков, но для языков программирования в этом утверждении имеется большая доля истины. Анализируя алгоритмы, которые используют программисты легко заметить сходство приемов и методов. Дело в том, что, несмотря на изобилие способов представления алгоритмов, программисты обычно используют для создания алгоритма тот же язык программирования, на котором пишут программу, и придумывают алгоритм, исходя из возможностей этого языка. Почему это так ? Давайте рассмотрим простой пример.
ООП 1-2 Пусть нам нужно найти, сколькими различными способами можно расставить N предметов (N может находиться в диапазоне от 13 до 20), причем предмет номер 0 должен находиться на 10-м месте справа. Можно придумать простой алгоритм: 1. создаем полный список всех возможных перестановок, 2. просматриваем его и считаем только те, которые удовлетворяют условию. Проблема в том, что, во-первых, при N=20 этот алгоритм потребует примерно два миллиона терабайт памяти, а во-вторых, будет выполняться более 2000 лет, хотя алгоритм этот формально правильный. Эта задача – классическая задача комбинаторики и алгоритм ее решения уже давно разработан: N различных предметов, расположенных на N различных местах, можно переставить N! (эн-факториал)=1*2*3*...*N способами. В нашей задаче, при N=20, это будет число, равное 121645100408832000. Тут возникает другая проблема: это число не влезает в 32 разряда – 4 байта (но влезает в 64 – 8 байт). Следовательно, решение задачи сведется либо к созданию подпрограмм для работы с 64-битными целыми числами. Однако, в некоторых языках возможность работы с такими числами входит в стандартные спецификации, так что задача сводится к написанию подпрограммы вычисления факториала числа. Соответственно, алгоритмы, которые в теории должны быть безотносительны к языкам программирования, на самом деле должны учитывать особенности того языка, который выбран для написания программы. Давайте вспомним историю языков программирования. Как все начиналось и что сегодня у нас имеется. Естественно, вам предлагается мой субъективный взгляд на эту историю и вы можете со мной не согласится.
Машинный код. Ассемблер
Началась все с разработки машинного языка: языка логических нулей и единиц. Запись на этом языке была очень сложной и утомительной, поэтому в конце 40-х для облегчения работы первых программистов был создан язык ассемблер. Вместо двоичных цифр, обозначающих какую-то команду, писались короткие слова или аббревиатура. Программисты называют ассемблер языком программирования низкого уровня, поскольку он близок к машинному языку - языку программирования самого низкого уровня. Программы на ассемблере зависят от характеристик конкретного процессора, поэтому его называют машинно-ориентированным языком. Несмотря на всю сложность написания программ и необходимость знаний устройств компьютера именно программы на ассемблере являются самыми эффективными и работоспособными.
Алгоритмические языки. Структурное программирование
Вскоре возникла необходимость создания новых, более совершенных языков программирования, которые бы напоминали естественные языки и позволяли бы не работать напрямую с машинными командами. Они стали называться языками высокого уровня. Такие языки ориентированы на описание алгоритмов. Поэтому их еще называют алгоритмическими языками. От ассемблера они отличались возможностью использования конструкций, подобных предложениям. С появлением языков нового уровня, программисты получили возможность производить разработку алгоритма решения задачи, не тратя усилий на программную
ООП 1-3 реализацию (в ассемблере основная проблема заключалась в постоянном запоминании ненужных, по сути, сведений по ходу написания программы и утомляющем кодировании мельчайших подробностей работы программы). Итак, первым был Fortran. Он появился в 1957 году. Fortran - это сокращение от двух английских слов FORmula TRANslator - что переводится как "транслятор формул". Как видно из названия, первоначально язык создавался с целью использования при математических расчетах. Он предназначался для написания программ, используемых при решении прикладных технических задач. Основу языка составляли арифметические операторы, соответствующие по своему синтаксису традиционной записи математических выражений. В дополнение к этому в языке имелись средства разбиения сложных алгоритмов на более простые за счет явного определения подпрограмм (SUBROUTINE) и функций (FUNCTION). Описания данных в Fortran были ориентированы на представление главным образом числовой информации, поэтому и типы данных были просты: это целые и действительные числа, а также массивы из таких чисел. Fortran обладал хорошо развитым математическим аппаратом, и под него за время его существования было написано множество удобных и полезных библиотек, он до сих пор иногда используется при программировании сложных вычислений. Но Fortran приносил радость и утешение лишь ученым, которые решали с его помощью свои специфические научные и инженерные задачи. ЭВМ между тем развивались, и становилось понятным, что с их помощью можно решать самые разнообразные проблемы, зачастую не связанные с научными приложениями. Поэтому постепенно разрабатывались и компиляторы других языков программирования. Так, в конце 1959 года, в США группа разработчиков представила совершенно новый универсальный язык программирования COBOL - это аббревиатура от Common Business- Oriented Language - универсальный язык, ориентированный на задачи бизнеса. В Коболе, в отличие от большинства других языков, все данные описываются в отдельной секции, которая не совпадает с секцией команд. Это позволяет использовать одни и те же описания данных в различных программах. COBOL был аппаратно независим, и это также способствовало его потрясающей популярности в 60-х - 70-х годах, особенно после выхода в 1962 году его новой версии. Особенно эффективно программы, написанные на COBOL"е, производят простые арифметические операции с большими массивами данных, что довольно часто приходится делать в бухгалтерских расчетах. В нашей стране этот язык тоже достаточно широко использовался, причем он, один из немногих, был переведен на русский язык. ...На заре развития вычислительной техники программисты были чем-то вроде обособленной секты, неохотно пускающей в свои ряды новичков. В основном этому способствовали техническое несовершенство компьютеров и малое их количество. Но среди программистов были и те, которые считали необходимым сделать программирование такой же простой и обыденной учебной дисциплиной, как математика. Отцы-основатели BASIC"а (расшифровывается как Basic Beginner"s All-purpose Symbolic Instruction Code - универсальный код символических инструкций для начинающих) - два ярких представителя программистов старшего поколения, сотрудники математического факультета Дармутского колледжа Томас Курц и Джон Кемени. Одно время популярность BASIC"а была столь велика, что PC выпускались с его интерпретатором, прошитым прямо в ПЗУ компьютера. Но, несмотря на все свои достоинства, и он скоро стал сдавать свои позиции, уступая их объектно-ориентированным языкам программирования. Не помогли даже пересмотры стандарта языка и исключение вечного камня преткновения - оператора безусловного перехода GOTO, который запутывал программу, делая из
ООП 1-4 нее нечто похожее на блюдо спагетти. К слову сказать, Microsoft до сих пор продвигает своего первенца - теперь это уже хорошо разросшийся Visual Basic - целый пакет визуального программирования, который вряд ли кто-нибудь обвинит в "объектной неориентированности", и VBA — Visual Basic for Applications, на котором можно писать макросы внутри документов MS Office (всякие кнопки в документах и сложное форматирование). Несмотря на практически полностью измененный интерфейс, этот язык и сейчас остается простым в изучении и отлично подходит для написания небольших, нетребовательных к ресурсам программ. Еще один очень интересный пример языка, сошедшего с пути исторического развития, о котором сегодня помнят разве что специалисты, - PL/1. Свое название язык получил как аббревиатуру от Programming Language One PL/1. Язык совмещал особенности трех лидеров данного сектора рынка - Фортрана, Кобола и Алгола. Возникает резонный вопрос: почему же мы сегодня ничего не знаем об PL/1, раз он такой хороший и так много всего в себе совмещает? Оказалось, что разработчики далеко не всегда брали от его "родителей" все самое лучшее, как следствие, язык получился перегруженным возможностями и концепциями. Но вернемся к началу 60-х годов. Все основные языки программирования все еще можно было пересчитать по пальцам, но вскоре их число начало резко возрастать. Поэтому были предприняты попытки создать универсальный язык программирования, но ни одна из этих попыток не увенчалась успехом. Среди десятка наиболее распространенных на тот период времени языков программирования каждый был ориентирован на решение определенных задач. Бейсик употреблялся для написания простых программ. Фортран - с его четко определенными правилами выполнения арифметических операций - являлся классическим языком программирования для решения математических и физических задач. Язык программирования COBOL был задуман как основной язык для массовой обработки данных в сферах управления и бизнеса. Другие языки программирования были также специализированы. Еще один заслуживающий внимания язык программирования - Алгол - предназначался для записи алгоритмов, которые строятся в виде последовательности процедур, применяемых для решения поставленной задачи. Программисты далеко неоднозначно приняли Алгол, широкого одобрения он не получил. Но все же влияние Алгола на развитие других языков программирования оказалось значительным. Среди языков, целью создания которых было улучшение Алгола, следует особо отметить Паскаль, разработанный в конце 60-х годов швейцарским ученым Никлаусом Виртом. Pascal был назван в честь французского философа и математика XVII века Блеза Паскаля. Как известно, история повторяется, и вся новизна лишь в том, что на каждом новом витке - она делает это на более высоком уровне. Некоторое время Никлаус Вирт был профессором информатики в Федеральном техническом университете в Швейцарии и нуждался в языке, с помощью которого относительно легко можно было бы обучать студентов навыкам программирования на хорошем уровне. Базовая концепция Паскаля была разработана Виртом примерно в 1970 году, и Паскаль очень быстро начал повсеместно распространяться, прежде всего, благодаря легкости в изучении и наглядности написанных на нем программ. Язык Паскаль требовал от программиста определения всех переменных в отдельной секции в начале программы. Так как эти определения задавались явным образом, то в программах появлялось сравнительно немного ошибок, и их было проще понять и исправить разработчику. Это сделало Паскаль популярным при создании больших программ. В 1962 году он был объявлен официальным языком программирования для учащихся средних школ, которые намерены специализироваться в области вычислительной техники и программирования в американских университетах. Но, на мой взгляд, наибольшей популярности, все-таки достиг язык Си. Первая версия языка Си была разработана в 1972 году сотрудником фирмы Bell Laboratories Денисом Ритчи. Первоначально язык Си задумывался как заменитель
ООП 1-5 Ассемблера для написания операционных систем. Поскольку Си - это язык высокого уровня, не зависящий от конкретной архитектуры, текст операционной системы оказывался легко переносимым с одной платформы на другую. Несомненный успех - Первой операционной системой, написанной практически целиком на Си, была система Unix. Кроме того, многие компиляторы и интерпретаторы других языков программирования (Фортран, APL, Pascal, LISP(Так много дурацких скобок [Lot of silly parenthesis - "куча глупых скобок" - старинная шуточная расшифровка названия языка Lisp]), Basic) написаны на языке Си. Язык С#, на котором вам предстоит писать программы, непосредственно связан с С, С++ и Java. И это не случайно. Ведь это три самых широко распространенных и признанных во всем мире языка программирования. Кроме того, на момент создания С# практически все профессиональные программисты уже владели С, С++ или Java. Благодаря тому что С# построен на столь прочном и понятном основании, перейти на этот язык из С, С++ или Java не представляло особого труда. Предком С# во втором поколении является С, от которого он унаследовал синтаксис, многие ключевые слова и операторы. Кроме того, С# построен на усовершенствованной объектной модели, определенной в С++. Если вы знаете С или С++, то будете чувствовать себя уютно и с языком С#. Создателем языка является сотрудник Microsoft Андреас Хейлсберг. Он стал известным в мире программистов задолго до того, как пришел в Microsoft. Хейлсберг входил в число ведущих разработчиков одной из самых популярных сред разработки — Delphi, а в Microsoft участвовал в создании версии Java - J++. Мы рассмотрели все сколько-нибудь значимые алгоритмические языки, но кодирование задачи — это только малая и не самая сложная часть процесса, который называется программированием. Процесс создания программы содержит еще два этапа:
Отладка программы
(- процесс обнаружения и устранения ошибок в программе, производимой по результатам ее тестирования на компьютере),которая тоже зависит от выбранного языка и системы программирования.
Оформление программного продукта
(- комплекс взаимосвязанных программ для решения определенной проблемы (задачи), подготовленной к реализации). А теперь давайте поподробнее остановимся на процессе обработке программы (текст на каком-нибудь языке программирования) машиной. Процессом этим занимаются трансляторы.
Трансляторы
Первым шагом на пути «очеловечивания» машинного языка как раз и стало создание специальных программ, переводящих символические имена в машинные коды - трансляторов. Транслятор— это программа-переводчик. Она преобразует программу, написанную на одном из языков, в программу, состоящую из машинных команд. В целом в процессе трансляции обычно выделяют следующие этапы: 1) синтаксический разбор, т.е. распознавание правильных синтаксических конструкций и сообщение об ошибках; 2) распределение памяти исходя из имен переменных, их описаний; 3) генерация объектного кода, т. е. выполнение подстановок (Так как вы знакомы с языком С или С++, то может быть вам знаком механизм препроцессорной обработки.); 4) оптимизация программы в объектном коде.
ООП 1-6 Трансляторы реализуются в виде компиляторов или интерпретаторов. С точки зрения выполнения работы компилятор и интерпретатор существенно различаются. Компилятор (англ. Compiler — составитель, собиратель) читает всю программу целиком, делает ее перевод и создает законченный вариант программы на машинном языке, который затем и выполняется. Интерпретатор (англ. Interpreter — истолкователь, устный переводчик) переводит и выполняет программу строка за строкой. После того, как программа откомпилирована, ни сама исходная программа, ни компилятор более не нужны. В то же время программа, обрабатываемая интерпретатором, должна заново переводиться на машинный язык при каждом очередном запуске программы. Откомпилированные программы работают быстрее, но интерпретируемые проще исправлять и изменять. Каждый конкретный язык ориентирован либо на компиляцию, либо на интерпретацию — в зависимости от того, для каких целей он создавался. В программе трансляторе "заложены" все правила алгоритмического языка и способы преобразования различных его конструкции на машинный язык. Трансляция — только часть работы с программой. Появились, так называемые, интегрированные среды программирования , которые содержали сразу: текстовый редактор, транслятор, компоновщик, встроенный отладчик и некоторые другие возможности в зависимости от системы и ее версии. Например: I. Программы можно написать как в любом символическом редакторе, так и в самой ИСП, в результате должен быть создан исходный файл Source file !! Язык Си не имеет своего символического редактора, интегрированная среда имеет,но она к языку не относится. I. Программа поступает на обработку в компилятор. С помощью этой системной программы (компилятора) - осуществляется перевод исходного текста программы в машинные команды. Формируется промежуточный файл (объектный код) object file. II. С помощью системной программы - редактора связей - осуществляется подключение к объектному коду стандартных библиотек, других модулей, необходимых для работы разрабатываемой программы. Формируется исполнительный файл (загрузочный модуль) executive file. III. Программа поступает в ОС на исполнение Исполняемый файл executive file *.exe Операционная система
Интегрированная

среда

программирования

Borland C
Компилятор object file *.obj Символический редактор Source file *.cpp
ООП 1-7 Раньше разработчики писали программы, в которых весь код умещался в одном файле. Это могли быть как маленькие программы, так и довольно крупные проекты. Со временем программы становились все крупнее и крупнее, что очень сильно мешало разработчикам, ведь крайне сложно вносить какие-то изменения в этот один огромный код. Особое неудобство создавала проблема с использованием большого числа похожих цветов - самоубийству было подобно. Проблема требовала решения - и оно пришло в виде ООП.
Объектно-ориентированное программирование (ООП)
В конце 70-х и начале 80-х были созданы основы нового Объектно- ориентированного программирования. Оно сохранило все лучшие моменты структурного программирования, а также приобрело ряд новых (отличительных понятий : инкапсуляция, наследование и полиморфизм — об этом подробнее мы будем говорить через пару месяцев). Например, понятие Класса - как организованной структуры разнородных данных и методов. Было создано много языков, поддерживающих концепцию ООП : С++, Object Pascal,Java... Для этих языков создавались новые ИСП ( MS Visual Studio, С++Builder, Delphi, VisualBasic) — появилось понятие графического интерфейса со встроенными визуальными средствами программирования. Теперь создание всех привычных пользователю кнопок, меню, полей, включения в программу рисунков и звуков требует очень немного времени, а код генерируется автоматически. Создание концепции визуального программирования кардинальным образом изменило ситуацию. Объектно-ориентированный подход давно стал естественным для Windows приложений. Когда вы начинаете выполнять любую Windows программу, вы видите диалоговое окно с кнопками, меню, списками и т.д. Всё это объекты сами по себе не производят никаких действий, пока не получат сообщения от пользователя (щелчок мыши, нажатие клавиши клавиатуры), или от другого приложения. После получения сообщения происходят какие- то действия (вычисления или смена окна или ещё что-нибудь), затем активность затухает до следующего сообщения от пользователя или другого объекта. Т.е. объектно-ориентированная программа представляет из себя систему объектов, которая выполняет некоторые задачи, в зависимости от вызванной функции объекта. Но технологии не стоят на месте. Каждые несколько лет современному программисту приходиться обновлять свои знания, чтобы оставаться в курсе новейших технологий. Вот и эти среды постепенно заменяются более новыми. Вот в такой среде нам с вами и предстоит работать: Программы, написанные на языке С#, отличаются от традиционных программ под Windows. Согласно официальной версии :Платформа Microsoft .NET(дот-нэт) — платформа для создания прило жений всех Ос . Но в действительности, э то не так. Платформа .NET ограничивается только ОС Windows (настольными и мобильными). В Linux её применение минимально. Мы познакомимся с ее самым распространенным продуктом, будем работать в Microsoft Visual Studio.NET 2012. Откомпилированный код исполняется в среде, которая проверяет условия защиты, гарантирует безопасное исполнение и управляет ресурсами, выделяемыми программе, с целью повысить надежность системы в целом и минимизировать степень воздействия программ друг на друга. Основная идея Visual Studio - реализация единой среды разработки, которая использует одинаковую для всех наиболее распространенных языков (!!!) логику создания приложений, общий набор различных программных компонентов и библиотек. Принципиально поменялась схема «язык — среда программирования». Если ранее речь шла об адаптации одного языка для разных платформ, то сейчас речь идет об адаптации разных языков для одной платформы. Среда исполнения - Common Language Runtime (CLR) будет исполнять байт код, написанный на языке
ООП 1-8 Microsoft Intermediate Language (MSIL). Причем этот код можно будет написать на разных языках. Неверно думать, что C# - это Java в интерпретации Microsoft. Патформа .NET не зависит ни от какого языка. Среда исполнения Java требует, чтобы программа была написана именно на Java, а для .NET вполне достаточно, что компилятор умеет генерировать код на языке MSIL. Коль скоро это условие выполнено, исходный язык не имеет никакого значения. Фактически во время выполнения программы в среде CLR неизвестно, на каком языке программирования разработчик написал исходный код. Уже сейчас существует более 20 языков, пригодных для платформы .NET, так что вы можете выбрать тот, который лучше всего подходит для решения конкретной задачи, или продолжать пользоваться тем, к которому привыкли. Насколько я знаю, на данный момент разработаны компиляторы для C++, C#, VisualBasic, Jscript, Java, APL,COBOL,EIFFEL,Pascal, PERL, PHP и т.д. Другой эффект применения MSIL состоит в кросс-языковой совместимости, начиная с уровня инфраструктуры и выше. На платформе .NET могут одновременно работать модули, написанные на любых ,ΝΕΤ-совместимых языках. Можно даже написать на одном языке класс, который будет наследовать классу, созданному на другом языке. Итак, в нашей новой среде будет редактор, где мы будет писать код. Этот код, в принципе, может писаться на любом языке который входит в множество языков платформы .NET. Ну и будет .NET компилятор. То место, которое раньше занимал Ассемблер теперь займет MSIL. Идея эта не нова, Java как раз для этого и придумали. Собственно связывание частей в единую программу машина производит в кодах. Объединение программных текстов в мaшинных кодах позволяет компилировать результаты трансляции с разных языков высокого уровня. После завершения процесса компиляции программа готова к загрузке и исполнению. Единая среда исполнения (Common Language Runtime - CLR) отвечает за загрузку, компиляцию, связывание и контролируемое исполнение программы. Помимо того, что традиционно принято относить к среде исполнения, CLR предоставляет службы для своевременной компиляции, отладки и профилирования. Библиотеки .NET, содержащие классы для организации пользовательского интерфейса, доступа к данным и к API операционной системы, находятся поверх CLR и взаимодействуют с ней. Microsoft Visual Studio.NET – это среда объектно-ориентированного визуального программирования. Работая в ней, даже начинающий программист может создать программу с профессионально выглядящим интерфейсом. Такая программа может выполнять несложные действия, порой выдавать ошибочные ответы, но при этом ее интерфейс не будет отличаться от многих Windows-приложений. Тем не менее, за кажущейся простотой всё равно скрывается необходимость глубокого понимания тонкостей языка программирования, работы ОС и оборудования, без которых написание качественной программы является невозможным. Поэтому, мы и будем с вами учиться создавать качественные программы.
О настоящем и будущем программирования….
Сейчас накопилось уже довольно много программ для часто используемых задач, поэтому деятельность программиста уже не сводится к скрупулезному написанию программы оператор за оператором. Работа программиста напоминает, скорее, действия опытного конструктора, создающего изделие из готовых узлов. Компоновку текста программы человек передает ЭВМ, указывая имена заимствованных программ и место их подсоединения.
ООП 1-9 В прошлом году я впервые поняла, что то, что я называла будущем - стало настоящем. Народ стал в своих дипломах активно использовать движки (Unreal Engine и Unity), сочетающие в себе и программирование, и компьютерную графику. Появились-то они давно (в конце 2000), но теперь вы можете пользоваться бесплатными версиями. В движке игровую логику пишут с помощью визуальной системы программирования — Blueprint (те самые кирпичики), но и на С-языках. Но тем не менее, ответственность за каждую строчку кода программы всё равно остаётся на программисте, который всегда отвечает за качество созданной им программы. Программируйте аккуратно и внимательно, не надейтесь на автоматику! Напоследок, что касается специализации – я хочу вам привести слова американского писателя – фантаста Роберта А. Хайнлайн