Языки программирования, 13 лекция (от 17 октября)
Материал из eSyr's wiki.
(5 промежуточных версий не показаны.) | |||
Строка 1: | Строка 1: | ||
+ | [[Языки программирования, 12 лекция (от 12 октября)|Предыдущая лекция]] | [[Языки программирования, 14 лекция (от 19 октября)|Следующая лекция]] | ||
+ | |||
<ol> | <ol> | ||
<li> | <li> | ||
Строка 7: | Строка 9: | ||
</li> | </li> | ||
</ol> | </ol> | ||
- | + | = Часть 1. Основные понятия традиционных процедурных ЯП = | |
+ | == Глава 3. Операторный базис ЯП == | ||
+ | === Пункт 2. Ветвление. === | ||
+ | |||
+ | ==== goto ==== | ||
<p>Для выхода более чем из одного уровня вложенности вJava есть goto метка.</p> | <p>Для выхода более чем из одного уровня вложенности вJava есть goto метка.</p> | ||
<p>Для очистки ресурсов раньше использовали goto очистка_ресурсов, в современных ЯП: try ... finally. </p> | <p>Для очистки ресурсов раньше использовали goto очистка_ресурсов, в современных ЯП: try ... finally. </p> | ||
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>J C# D отличает от C++ референциальная модель объектов. Объект нужно создать. В C++ есть конструкторы и деструкторы, и когда объект перестаёт существовать в памяти, автоматически вызывается деструктор. В С++ захват ресурсов – инициализация. Если нам нужен ресурс, мы обрамляем его в класс Res, в конструкторе которого желается захват ресурса, в деструкторе – освобождение. И при любом выходе из стека будут вызываться деструкторы | + | <p>J C# D отличает от C++ референциальная модель объектов. Объект нужно создать. В C++ есть конструкторы и деструкторы, и когда объект перестаёт существовать в памяти, автоматически вызывается деструктор. В С++ захват ресурсов – инициализация. Если нам нужен ресурс, мы обрамляем его в класс Res, в конструкторе которого желается захват ресурса, в деструкторе – освобождение. И при любом выходе из стека будут вызываться деструкторы объектов, влекущие за собой освобождение ресурсов. В JDC# есть конструкции, которые позволяют эмулировать эту стратегию.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
<p>Пример из UI:</p> | <p>Пример из UI:</p> | ||
<p>Когда мы проектируем UI, который характеризуется W(indow)I(con)M(ouse)P(ointer). Если пользователь заказал. Чтобы пользователь не дёргался, меняется курсор, более того, когда он видит песочные часы, он ничего не пытается предпринимать, В куче библиотек, например в Си, есть объекты, которые в конструкторе размещают объект, в деструкторе освобождает.</p> | <p>Когда мы проектируем UI, который характеризуется W(indow)I(con)M(ouse)P(ointer). Если пользователь заказал. Чтобы пользователь не дёргался, меняется курсор, более того, когда он видит песочные часы, он ничего не пытается предпринимать, В куче библиотек, например в Си, есть объекты, которые в конструкторе размещают объект, в деструкторе освобождает.</p> | ||
- | <p>Мы размещаем курсор в стеке, вызывааем | + | <p>Мы размещаем курсор в стеке, вызывааем долгую операцию. В чём проблема: даже если не работала такая семантика, </p> |
<p>CwaitCursor</p> | <p>CwaitCursor</p> | ||
<p>showcursor;</p> | <p>showcursor;</p> | ||
Строка 36: | Строка 42: | ||
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>В Модуле-3 главное | + | <p>В Модуле-3 главное понятие – Remote Procedure Call (RPC).</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | + | === Пункт 3. Составной оператор или блок. === | |
- | + | <p>Чем отличается сост оператор от блока. В Алголе не отличается, в Паскале – да.</p> | |
- | + | ||
- | + | ||
- | + | ||
- | <p>Чем | + | |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
Строка 52: | Строка 54: | ||
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>Как только | + | <p>Как только возникает разделение объявлений и операторов, при этом понятие составного оператора необязательно. Может быть в языке отдельно блок и отдельно оператор. Такое понятие нужно чисто синтаксически в языках, где отсутствует явный терминатор.</p> |
- | <p>Ада, М-2, Оберон – понятие сост оператора | + | <p>Ада, М-2, Оберон – понятие сост оператора отсутствует, так как там должно быть ключевое слово для начала блока.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
Строка 70: | Строка 72: | ||
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>В программировании 70х годов | + | <p>В программировании 70х годов считалось, что нужно опережающее описание всех переменных. Причём в Аде считалось, что нужно сначала тому, кто читает, знать обо всех объектах, а потом читать, что делается. Смешение считалось дурным тоном.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>В Паскале | + | <p>В Паскале сверху блока может быть либо заголовок процедуры, либо заголовок главной программы. </p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>В современных ЯП блок эквивалентен составному оператору. (Си++, | + | <p>В современных ЯП блок эквивалентен составному оператору. (Си++, Java, Си#). В современных языках беспорядочное объявление операторов является господствующим. </p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | + | === Пункт 4. Специализированные операторы. === | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
<p>Специфичны для конкретных ЯП.</p> | <p>Специфичны для конкретных ЯП.</p> | ||
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>Для языка Ада есть два оператора: select, accept. Относятся к области | + | <p>Для языка Ада есть два оператора: select, accept. Относятся к области взаимодействия параллельных процессов, и их аналогов в других ЯП нет или почти нет. Каждый ЯП может ввести некоторые специализированные операторы. И при изучении на них надо обращать внимание.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | + | == Глава 4. Процедурные абстракции. == | |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
<p><коммент></p> | <p><коммент></p> | ||
- | <p>Ка с тз операторного базиса, так и с тз типового | + | <p>Ка с тз операторного базиса, так и с тз типового базиса ЯП, несильно отличаются друг от друго.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>Набор ТД сильно сократился по сравнению со старыми ЯП, набор конструкции | + | <p>Набор ТД сильно сократился по сравнению со старыми ЯП, набор конструкции тоже. Базисные встроенные объекты с объектами реального мира имеют мало общего, кирпичики, из которого строят модели, очень маленькие и универсальные. Для этого предлагаются некие повторно используемые библиотеки. Например, есть STL, а есть открытые библиотеки типа boost. «то уже более мощные ЯП. В совр ЯП делается брлее мощный упор на средства развития.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
Строка 103: | Строка 101: | ||
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>Что нужно в языке: язык ассемблера – трудно развиваемый язык, ничего с | + | <p>Что нужно в языке: язык ассемблера – трудно развиваемый язык, ничего с т.зр. развития нет.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
Строка 115: | Строка 113: | ||
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>А то, что сделали на | + | <p>А то, что сделали на ASMе и джовиале, очень трудно передать.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
Строка 121: | Строка 119: | ||
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>Можно объектно | + | <p>Можно объектно программировать на ASMе.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
<p>Что нужно в языке для минимальных ср-в развития:</p> | <p>Что нужно в языке для минимальных ср-в развития:</p> | ||
- | <p>На Фортране 66 года можно было создавать достаточно сложные системы, например компилятор компиляторов. Пользовались двумя вещами – подпрограмма ( | + | <p>На Фортране 66 года можно было создавать достаточно сложные системы, например компилятор компиляторов. Пользовались двумя вещами – подпрограмма (возникла в самом первом варианте), и блок данных (возник тогда же – ужасно неприятно синтаксическая конструкция, но он позволял</p> |
- | <p>BLOCK DATE | + | <p>BLOCK DATE имя</p> |
<p>объявления данных</p> | <p>объявления данных</p> | ||
<p>END</p> | <p>END</p> | ||
Строка 135: | Строка 133: | ||
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>Блок данных | + | <p>Блок данных – изначально средство экономии памяти. Потом выяснилось, что необходим набор глобальных данных для взаимодействия разных модулей.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
Строка 147: | Строка 145: | ||
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | + | === Пункт 1. Процедуры и сопрограммы. === | |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
Строка 153: | Строка 151: | ||
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>Понятие процедуры соотв понятию | + | <p>Понятие процедуры соотв понятию структурного программирования. Это чёрный ящик, у которого один вход и один выход, а там внутри уже делается что угодно. Но в первых ЯП очевидно было, что процедура – нечто, которое может иметь и несколько входов, и несколько выходов. Фортран 77 объединял в себе особенности, которые появились в новых компиляторах. Там кроме SUBROUTINE был ENTRY – это были альтернативные входы, причём альтернативные входы могли иметь альтернативные наборы параметров.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
Строка 190: | Строка 188: | ||
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>Было ещё одно понятие, | + | <p>Было ещё одно понятие, которое было изгнано из совр ЯП: сопрограмма.</p> |
- | <p>Процедура: процедура p подразумевает всегда вызов её из надпрограммы, вызывающей, главной. В | + | <p>Процедура: процедура p подразумевает всегда вызов её из надпрограммы, вызывающей, главной. В каждый конкретный момент времени вызов программа становится главной. Причём тут асимметрия: p – точка входа (в ассемблере процедура не отличается от метки. Любимая задача лектора: если не call, как его промоделироваать, но тут ещё надо в стек загрузить адрес возврата. В 360 не было call, зато был такой косвенный оператор перехода). Всегда при вызове процедуры всегда с первого оператора, а возвращение туда, откуда вызвали, куда скажут. Чёткая асимметрия.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>Как обобщить подобную антисимметрию и сделать её симметричной: для | + | <p>Как обобщить подобную антисимметрию и сделать её симметричной: для этого назовём это сопрограммой (coroutine) – взаимодействующие программы.</p> |
- | <p>Есть call p2 – управление идёт в точку входа p2, потом делаем call p1, возвращаем туда, откуда вызвали, потом опять делаем call p2, и возвращаем управление туда, откуда ушли. Тут это вместо call называется resume. При resume начинается | + | <p>Есть call p2 – управление идёт в точку входа p2, потом делаем call p1, возвращаем туда, откуда вызвали, потом опять делаем call p2, и возвращаем управление туда, откуда ушли. Тут это вместо call называется resume. При resume начинается выполнение соответствующей сопрограммы с точки, где её покинуло.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>Книга структурное программирование – три статьи – первая Дейкстры про структурное программиорваиние, вторая Ховарда про типы данных. Третья Уве Дау (один из автор Симулы 67 – основной источник идей для Страуструпа при создании Си с классами), в которой он | + | <p>Книга структурное программирование – три статьи – первая Дейкстры про структурное программиорваиние, вторая Ховарда про типы данных. Третья Уве Дау (один из автор Симулы 67 – основной источник идей для Страуструпа при создании Си с классами), в которой он обсуждал понятие сопрограммы, реализацию в Симуле, возможности применения, насколько оно красивее.</p> |
- | <p>Явный пример: нужно | + | <p>Явный пример: нужно слить два файла. Не очень приятная задача, нужно гонять циклы то там, то там. Кроме того, возникают лишние циклы, когда один из файлов закончился. А при сопрограммах обе сопрограммы читают из своего файла в результирующий, вопрос в том, когда передавать управление, и тут всего один цикл. Сигнализация конца файла легко устанавливается и она решается за один цикл. Структура решения более простая, чем при классическом решении. Структура сопрограмм похоже на процессы. Это суть квазипараллельные процессы, и с точки параллельных процессов resume соответствует синхронизации. Для многих задач параллельные процессы естественнее, чем последовательные. Сопрограммы были впервые применены для реализации с языка Cobol. С точки зрения компиляции на что похожа сопрограмма – есть сопрограммы для лексического, синтаксического анализа, генерации кода. Тогда, когда синтаксический анализатору нужна лексема, он вызывает лексический анализатор, и он её отдаёт. Синтаксический анализатор из потока читает лексемы и отдаёт их генератору кода. Компилятор есть сеть взаимодействующих сопрограмм, и эта концепция всем понравилась. Она была внедрена в Симулу 67 и Модулу-2. Для поддержки сопрограмм были:</p> |
<p>тип COROUTINE </p> | <p>тип COROUTINE </p> | ||
<p>NEW PROCESS(VAR C:COROUTINE, P:PROC; N:INTEGER); - Вирт отвечал, что так получилось чисто исторически, PROC – встроенный тип, процедура без параметров.</p> | <p>NEW PROCESS(VAR C:COROUTINE, P:PROC; N:INTEGER); - Вирт отвечал, что так получилось чисто исторически, PROC – встроенный тип, процедура без параметров.</p> | ||
- | <p>Очень похоже на запуск нового потока. Там мы | + | <p>Очень похоже на запуск нового потока. Там мы указываем процедуру без параметров (в виндах можно указывать параметр – код возврата). </p> |
<p>Далее была неопределённая вещь – N:INTEGER;</p> | <p>Далее была неопределённая вещь – N:INTEGER;</p> | ||
<p>При создании новых потоков наследуется часть контекста. У легковесных нитей и потоков отличаются тем: легковесные общие тем, что у них сегмент данных общий, синхронизация почти не нужна. Счётчик команд различный, код может быть разный, сегмент стека разный – под локальные переменные.</p> | <p>При создании новых потоков наследуется часть контекста. У легковесных нитей и потоков отличаются тем: легковесные общие тем, что у них сегмент данных общий, синхронизация почти не нужна. Счётчик команд различный, код может быть разный, сегмент стека разный – под локальные переменные.</p> | ||
Строка 213: | Строка 211: | ||
<p>Вирт потом заменил её на ADDRESS – аналог void *</p> | <p>Вирт потом заменил её на ADDRESS – аналог void *</p> | ||
<p>Мы не раньше говорим, что это структура, теперь – что эту структуру помещаем по адресу.</p> | <p>Мы не раньше говорим, что это структура, теперь – что эту структуру помещаем по адресу.</p> | ||
- | <p>Была ещё процедура IOTRANSFER – вызов процедуры, когда приходило прерывание, там ещё было N – номер прерывание. Это позволяло писать драйверы. Это понятие сопрограммы могло быт полезным, например, при | + | <p>Была ещё процедура IOTRANSFER – вызов процедуры, когда приходило прерывание, там ещё было N – номер прерывание. Это позволяло писать драйверы. Это понятие сопрограммы могло быт полезным, например, при обработке нажатий клавиш.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
Строка 219: | Строка 217: | ||
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>Основываясь на понятии сопрограммы, можно | + | <p>Основываясь на понятии сопрограммы, можно реализовать передачу сигналов. То есть понятие сигналов – квазипараллельного программирования, на основе сопрограмм.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>Один из главных недостатков сопргр=ограмм – сложность синхронизации оп данным. У каждой сопрограммы свой стек, где хранятся локальные данные. Сопрограммы могут взаимодействовать только через глобальные переменные. Они не могут | + | <p>Один из главных недостатков сопргр=ограмм – сложность синхронизации оп данным. У каждой сопрограммы свой стек, где хранятся локальные данные. Сопрограммы могут взаимодействовать только через глобальные переменные. Они не могут экспортировать данные наружу.</p> |
<p>Кроме того, оно сочтено низкоуровневым.</p> | <p>Кроме того, оно сочтено низкоуровневым.</p> | ||
<p>Понятие потока. RSSUME – оператор языка. Это всё встроено в языка. Это лишний пример того, почему сужается базис – разные вещи могут быть реализованы с разной эффективностью. Теперь есть поток, и его реализация зависит от платформы.</p> | <p>Понятие потока. RSSUME – оператор языка. Это всё встроено в языка. Это лишний пример того, почему сужается базис – разные вещи могут быть реализованы с разной эффективностью. Теперь есть поток, и его реализация зависит от платформы.</p> | ||
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>Лектору кажется, что отсутствие понятия сопрограмм связано с | + | <p>Лектору кажется, что отсутствие понятия сопрограмм связано с наличием других средств квазипараллеьного программирования реализуемых ср-вами стандартной библиотеки или ОС.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>Явным преимущественным Ада – механизм синхронизации процессов ( | + | <p>Явным преимущественным Ада – механизм синхронизации процессов (механизм рандеву). Единственная новая концепция. Accept – принимал некоторую точку входа от параллельного процесса. Механизм рандеву всем хорош, но если программировать параллельные процессы на ОС, где пар процессы уже есть, то получалось менее эффективно. И он был полезен, где пар процессов вообще не было. Но там есть ограничение по ресурсам, и там механизм рандеву – стрельба из пушки по воробьям.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>В | + | <p>В Java есть встроенные средства программирования потоков, кроме того, там есть JNI, чему сопротивлялась Sun, но чего так хотела MS, - вызов нативного кода. Это напрямую противоречит WORA. Но получается так, что реализация встроенного механизма, оказывается менее эфективной, чем использование средств ОС. </p> |
- | <p>Встроенный механизм сопрограмм | + | <p>Встроенный механизм сопрограмм слишком низкоуровневый, и его нельзя реализовать достаточно универсально на разных архитектурах (ОС). Современные программисты потеряли вкус к параллельному программированию. Их не нужно применять для эффективности, их нужно применять для соотв структуре алгоритма.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
<p> Реализация подпрограмм. </p> | <p> Реализация подпрограмм. </p> | ||
- | + | === Пункт 2. Подпрограммы. Передача параметров.=== | |
- | <p>Разные ЯП отличаются с | + | <p>Разные ЯП отличаются с т.зр. реализации отличаются механизмом передачи параметров.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
Строка 246: | Строка 244: | ||
</p> | </p> | ||
<p>In/out – три класса входных параметров.</p> | <p>In/out – три класса входных параметров.</p> | ||
- | <p>Первый класс – in-параметры – передаются | + | <p>Первый класс – in-параметры – передаются только их значения</p> |
<p>out-параметры – меняют свои значения, но от них не требуется определённости</p> | <p>out-параметры – меняют свои значения, но от них не требуется определённости</p> | ||
<p>in/out – требуется как статус определённости, так они и могут получить новые значения.</p> | <p>in/out – требуется как статус определённости, так они и могут получить новые значения.</p> | ||
- | <p>Это | + | <p>Это классификация с т.зр. зрения in-out семантики. И способы передачи нужно классифицировать в этих терминах. Способов передачи 6:</p> |
<ol> | <ol> | ||
<li> | <li> | ||
- | <p>По значению. Есть факт параметр, есть формальный – и нужно установить взаимод, для in – параметров знач не | + | <p>По значению. Есть факт параметр, есть формальный – и нужно установить взаимод, для in – параметров знач не меняется, для out, in-out – значение может поменяться. При передаче по знач заводится место для параметра, заводится в стеке – для объекта формального параметра. Происходит Копирование из факт в формальный параметр. Установление связи есть фактически копирование. Копирование происходит перед вызовом Происходит загрузка параметров в стек.</p> |
</li> | </li> | ||
<li> | <li> | ||
- | <p>По | + | <p>По результату. Фактический := формальный перед return. Может быть формально и после return. Тут всегда перед CALL происходит загрузка параметров, и её может выполнить главная программа, а вот присвоение можно делать как одна, так и другая, но чаще после return, ибо вызывающая программа знает больше.</p> |
</li> | </li> | ||
<li> | <li> | ||
Строка 261: | Строка 259: | ||
</li> | </li> | ||
</ol> | </ol> | ||
- | <p>Чем хороши эти способы – | + | <p>Чем хороши эти способы – отвечают полностью семантике in-out. </p> |
- | <p>Главный недостаток этих способов – копирование, если параметры большие. | + | <p>Главный недостаток этих способов – копирование, если параметры большие. Понадобились ещё два способа:</p> |
<ol start="4"> | <ol start="4"> | ||
<li> | <li> | ||
- | <p>По адресу/ | + | <p>По адресу/ссылке. Выделяется формальный параметр – адрес фактическое. Место в стеке выделяется под адрес.</p> |
</li> | </li> | ||
<li> | <li> | ||
Строка 272: | Строка 270: | ||
</ol> | </ol> | ||
<p>Когда передаём адрес, мы имеем полный доступ.</p> | <p>Когда передаём адрес, мы имеем полный доступ.</p> | ||
- | <p>В фортране все параметры передавались по ссылке. Преимущество – полный доступ. Опасность – мы не хотим параметр модифицировать. Можно было также передавать константы, и их можно было изменить. Ещё один недостаток – если передаём in-параметр (просто число), то это не | + | <p>В фортране все параметры передавались по ссылке. Преимущество – полный доступ. Опасность – мы не хотим параметр модифицировать. Можно было также передавать константы, и их можно было изменить. Ещё один недостаток – если передаём in-параметр (просто число), то это не эффективно, так как каждый раз используется адрес.</p> |
<p><br /> | <p><br /> | ||
</p> | </p> | ||
- | <p>Большинство | + | <p>Большинство современных ЯП параметры передаются по значению и по указателю(программист на Си должен моделировать это передачей указателя)-ссылке (появился в СИ++)</p> |
[[Категория:Лекции]] | [[Категория:Лекции]] | ||
[[Категория:Языки программирования]] | [[Категория:Языки программирования]] | ||
+ | |||
+ | {{Языки Программирования}} | ||
+ | {{Lection-stub}} |
Текущая версия
Предыдущая лекция | Следующая лекция
-
Оператор присваивания
-
Операторы управления
Содержание |
[править] Часть 1. Основные понятия традиционных процедурных ЯП
[править] Глава 3. Операторный базис ЯП
[править] Пункт 2. Ветвление.
[править] goto
Для выхода более чем из одного уровня вложенности вJava есть goto метка.
Для очистки ресурсов раньше использовали goto очистка_ресурсов, в современных ЯП: try ... finally.
J C# D отличает от C++ референциальная модель объектов. Объект нужно создать. В C++ есть конструкторы и деструкторы, и когда объект перестаёт существовать в памяти, автоматически вызывается деструктор. В С++ захват ресурсов – инициализация. Если нам нужен ресурс, мы обрамляем его в класс Res, в конструкторе которого желается захват ресурса, в деструкторе – освобождение. И при любом выходе из стека будут вызываться деструкторы объектов, влекущие за собой освобождение ресурсов. В JDC# есть конструкции, которые позволяют эмулировать эту стратегию.
Пример из UI:
Когда мы проектируем UI, который характеризуется W(indow)I(con)M(ouse)P(ointer). Если пользователь заказал. Чтобы пользователь не дёргался, меняется курсор, более того, когда он видит песочные часы, он ничего не пытается предпринимать, В куче библиотек, например в Си, есть объекты, которые в конструкторе размещают объект, в деструкторе освобождает.
Мы размещаем курсор в стеке, вызывааем долгую операцию. В чём проблема: даже если не работала такая семантика,
CwaitCursor
showcursor;
longop;
hidecursor;
Если longop завершится аварийно, то курсор так и останется часиками, и пользователи будут считать, что программа зависла.
Goto либо просто не нужно, либо просто вредно.
X.x
goto end;
Y y;
end:
Компилятору очень трудно определить, выполнять свёртку локального объекта Y y, или нет. Компиляторы в этом случае выдают предкпреждение, что свёртка Y y игнорируется.
Программисты Модула-2 говорили, что им не хватает обработки ошибок (исключений).
В Модуле-3 главное понятие – Remote Procedure Call (RPC).
[править] Пункт 3. Составной оператор или блок.
Чем отличается сост оператор от блока. В Алголе не отличается, в Паскале – да.
Блок – объявление + операторы
Составной оператор – только операторы.
В с++ разница между сост оператором и блоком нивелирована. Там нет разница между операторами и объявлениями. Объявление класса влечет выполнение конструктора.
Как только возникает разделение объявлений и операторов, при этом понятие составного оператора необязательно. Может быть в языке отдельно блок и отдельно оператор. Такое понятие нужно чисто синтаксически в языках, где отсутствует явный терминатор.
Ада, М-2, Оберон – понятие сост оператора отсутствует, так как там должно быть ключевое слово для начала блока.
Блок – не синтаксическое понятие – он вводит локальные переменные, а потом операторы.
В Паскале есть понятие блока – синтаксически объявления, begin , операторы, end. - это блок паскаля.
Язык Ада -
declare
объявления
begin
операторы
end
В программировании 70х годов считалось, что нужно опережающее описание всех переменных. Причём в Аде считалось, что нужно сначала тому, кто читает, знать обо всех объектах, а потом читать, что делается. Смешение считалось дурным тоном.
В Паскале сверху блока может быть либо заголовок процедуры, либо заголовок главной программы.
В современных ЯП блок эквивалентен составному оператору. (Си++, Java, Си#). В современных языках беспорядочное объявление операторов является господствующим.
[править] Пункт 4. Специализированные операторы.
Специфичны для конкретных ЯП.
Для языка Ада есть два оператора: select, accept. Относятся к области взаимодействия параллельных процессов, и их аналогов в других ЯП нет или почти нет. Каждый ЯП может ввести некоторые специализированные операторы. И при изучении на них надо обращать внимание.
[править] Глава 4. Процедурные абстракции.
<коммент>
Ка с тз операторного базиса, так и с тз типового базиса ЯП, несильно отличаются друг от друго.
Набор ТД сильно сократился по сравнению со старыми ЯП, набор конструкции тоже. Базисные встроенные объекты с объектами реального мира имеют мало общего, кирпичики, из которого строят модели, очень маленькие и универсальные. Для этого предлагаются некие повторно используемые библиотеки. Например, есть STL, а есть открытые библиотеки типа boost. «то уже более мощные ЯП. В совр ЯП делается брлее мощный упор на средства развития.
</коммент>
Что нужно в языке: язык ассемблера – трудно развиваемый язык, ничего с т.зр. развития нет.
Высказывание одного из разработчиков первых систем обороны: «Эти ребята болтают про ОО, мы это делали в 50х годах то же самое, только называали другими словами».
На защите аспирантов один воскликнул: «Да мы сидели и раньше делали то же самое, и просто не считали это нужным это защищать».
Это неправильный довод, так как тут конти... знания, которые можно передать.
А то, что сделали на ASMе и джовиале, очень трудно передать.
Знания, написанные на ОО языке, передавать значительно проще.
Можно объектно программировать на ASMе.
Что нужно в языке для минимальных ср-в развития:
На Фортране 66 года можно было создавать достаточно сложные системы, например компилятор компиляторов. Пользовались двумя вещами – подпрограмма (возникла в самом первом варианте), и блок данных (возник тогда же – ужасно неприятно синтаксическая конструкция, но он позволял
BLOCK DATE имя
объявления данных
END
все объявления должны быть только для какой-то подпрограммы, и они видны только для этой подпрограммы, а тут получается набор глобальных данных, с которым могли взаимодействовать любые подпрограммы. Без этого ничего смерьёзного сделать нельзя.
Стандартная Экспонента была , а продвинутой нет, и её надо было писат, причём по способу использования рони ничем не отличались. Это очень важная парадигма.
Блок данных – изначально средство экономии памяти. Потом выяснилось, что необходим набор глобальных данных для взаимодействия разных модулей.
Средства развития минимальные есть.
Что нужно, чтобы было развитие: нужен модуль, где набор данных и набор подпрограмм.
Пятая глава – модуль, который есть развитие.
[править] Пункт 1. Процедуры и сопрограммы.
Нечто, область кода, которая имеет своё имя, которое можно использовать с помощью вызова. Поэтому в кадлом языке есть понятие процедуры и понятие вызова.
Понятие процедуры соотв понятию структурного программирования. Это чёрный ящик, у которого один вход и один выход, а там внутри уже делается что угодно. Но в первых ЯП очевидно было, что процедура – нечто, которое может иметь и несколько входов, и несколько выходов. Фортран 77 объединял в себе особенности, которые появились в новых компиляторах. Там кроме SUBROUTINE был ENTRY – это были альтернативные входы, причём альтернативные входы могли иметь альтернативные наборы параметров.
SUBROUTINE P(X, Y)
ENTRY P1(C)
EnTRY P2(C)
напоминает множественное использование goto.
В структурных ЯП такой необходимости просто не возникает.
Кроме того, можно было передавать в качестве параметров метки, и делать потом RETURN 2/
SUBROUTINE P(X, Y, *, *, *)
...
RETURN 2;
ASSIGN 555
GOT M;
Это позволяло окочательно запутаться.
Для того, чтобы совсем запутаться, можно было делать
CALL P(A, B, 333, 25, 555)
И надо было внимательно смотреть на P, и то, не факт, что поймёшь, куда делается переход.
Отдельные шутники предлагали вместо goto сделать come from.
Было ещё одно понятие, которое было изгнано из совр ЯП: сопрограмма.
Процедура: процедура p подразумевает всегда вызов её из надпрограммы, вызывающей, главной. В каждый конкретный момент времени вызов программа становится главной. Причём тут асимметрия: p – точка входа (в ассемблере процедура не отличается от метки. Любимая задача лектора: если не call, как его промоделироваать, но тут ещё надо в стек загрузить адрес возврата. В 360 не было call, зато был такой косвенный оператор перехода). Всегда при вызове процедуры всегда с первого оператора, а возвращение туда, откуда вызвали, куда скажут. Чёткая асимметрия.
Как обобщить подобную антисимметрию и сделать её симметричной: для этого назовём это сопрограммой (coroutine) – взаимодействующие программы.
Есть call p2 – управление идёт в точку входа p2, потом делаем call p1, возвращаем туда, откуда вызвали, потом опять делаем call p2, и возвращаем управление туда, откуда ушли. Тут это вместо call называется resume. При resume начинается выполнение соответствующей сопрограммы с точки, где её покинуло.
Книга структурное программирование – три статьи – первая Дейкстры про структурное программиорваиние, вторая Ховарда про типы данных. Третья Уве Дау (один из автор Симулы 67 – основной источник идей для Страуструпа при создании Си с классами), в которой он обсуждал понятие сопрограммы, реализацию в Симуле, возможности применения, насколько оно красивее.
Явный пример: нужно слить два файла. Не очень приятная задача, нужно гонять циклы то там, то там. Кроме того, возникают лишние циклы, когда один из файлов закончился. А при сопрограммах обе сопрограммы читают из своего файла в результирующий, вопрос в том, когда передавать управление, и тут всего один цикл. Сигнализация конца файла легко устанавливается и она решается за один цикл. Структура решения более простая, чем при классическом решении. Структура сопрограмм похоже на процессы. Это суть квазипараллельные процессы, и с точки параллельных процессов resume соответствует синхронизации. Для многих задач параллельные процессы естественнее, чем последовательные. Сопрограммы были впервые применены для реализации с языка Cobol. С точки зрения компиляции на что похожа сопрограмма – есть сопрограммы для лексического, синтаксического анализа, генерации кода. Тогда, когда синтаксический анализатору нужна лексема, он вызывает лексический анализатор, и он её отдаёт. Синтаксический анализатор из потока читает лексемы и отдаёт их генератору кода. Компилятор есть сеть взаимодействующих сопрограмм, и эта концепция всем понравилась. Она была внедрена в Симулу 67 и Модулу-2. Для поддержки сопрограмм были:
тип COROUTINE
NEW PROCESS(VAR C:COROUTINE, P:PROC; N:INTEGER); - Вирт отвечал, что так получилось чисто исторически, PROC – встроенный тип, процедура без параметров.
Очень похоже на запуск нового потока. Там мы указываем процедуру без параметров (в виндах можно указывать параметр – код возврата).
Далее была неопределённая вещь – N:INTEGER;
При создании новых потоков наследуется часть контекста. У легковесных нитей и потоков отличаются тем: легковесные общие тем, что у них сегмент данных общий, синхронизация почти не нужна. Счётчик команд различный, код может быть разный, сегмент стека разный – под локальные переменные.
Было две процедуры: TRANSFER(P1, P2), P1, P2 – типа COROUTINE, и потом был RESUME. Р1 передаётся для
COROUTINE – структура
Вирт потом заменил её на ADDRESS – аналог void *
Мы не раньше говорим, что это структура, теперь – что эту структуру помещаем по адресу.
Была ещё процедура IOTRANSFER – вызов процедуры, когда приходило прерывание, там ещё было N – номер прерывание. Это позволяло писать драйверы. Это понятие сопрограммы могло быт полезным, например, при обработке нажатий клавиш.
В современных ЯП сопрограммы практически не используются.
Основываясь на понятии сопрограммы, можно реализовать передачу сигналов. То есть понятие сигналов – квазипараллельного программирования, на основе сопрограмм.
Один из главных недостатков сопргр=ограмм – сложность синхронизации оп данным. У каждой сопрограммы свой стек, где хранятся локальные данные. Сопрограммы могут взаимодействовать только через глобальные переменные. Они не могут экспортировать данные наружу.
Кроме того, оно сочтено низкоуровневым.
Понятие потока. RSSUME – оператор языка. Это всё встроено в языка. Это лишний пример того, почему сужается базис – разные вещи могут быть реализованы с разной эффективностью. Теперь есть поток, и его реализация зависит от платформы.
Лектору кажется, что отсутствие понятия сопрограмм связано с наличием других средств квазипараллеьного программирования реализуемых ср-вами стандартной библиотеки или ОС.
Явным преимущественным Ада – механизм синхронизации процессов (механизм рандеву). Единственная новая концепция. Accept – принимал некоторую точку входа от параллельного процесса. Механизм рандеву всем хорош, но если программировать параллельные процессы на ОС, где пар процессы уже есть, то получалось менее эффективно. И он был полезен, где пар процессов вообще не было. Но там есть ограничение по ресурсам, и там механизм рандеву – стрельба из пушки по воробьям.
В Java есть встроенные средства программирования потоков, кроме того, там есть JNI, чему сопротивлялась Sun, но чего так хотела MS, - вызов нативного кода. Это напрямую противоречит WORA. Но получается так, что реализация встроенного механизма, оказывается менее эфективной, чем использование средств ОС.
Встроенный механизм сопрограмм слишком низкоуровневый, и его нельзя реализовать достаточно универсально на разных архитектурах (ОС). Современные программисты потеряли вкус к параллельному программированию. Их не нужно применять для эффективности, их нужно применять для соотв структуре алгоритма.
Реализация подпрограмм.
[править] Пункт 2. Подпрограммы. Передача параметров.
Разные ЯП отличаются с т.зр. реализации отличаются механизмом передачи параметров.
Существует семантика in/out и существует способ передачи. В общем случае это разные вещи.
In/out – три класса входных параметров.
Первый класс – in-параметры – передаются только их значения
out-параметры – меняют свои значения, но от них не требуется определённости
in/out – требуется как статус определённости, так они и могут получить новые значения.
Это классификация с т.зр. зрения in-out семантики. И способы передачи нужно классифицировать в этих терминах. Способов передачи 6:
-
По значению. Есть факт параметр, есть формальный – и нужно установить взаимод, для in – параметров знач не меняется, для out, in-out – значение может поменяться. При передаче по знач заводится место для параметра, заводится в стеке – для объекта формального параметра. Происходит Копирование из факт в формальный параметр. Установление связи есть фактически копирование. Копирование происходит перед вызовом Происходит загрузка параметров в стек.
-
По результату. Фактический := формальный перед return. Может быть формально и после return. Тут всегда перед CALL происходит загрузка параметров, и её может выполнить главная программа, а вот присвоение можно делать как одна, так и другая, но чаще после return, ибо вызывающая программа знает больше.
-
По значению/результату (по значению результата – чушь собачья, ошибка на экзамене. Изначально ошибка появилась при переписывании лекций с диктофона).
Чем хороши эти способы – отвечают полностью семантике in-out.
Главный недостаток этих способов – копирование, если параметры большие. Понадобились ещё два способа:
-
По адресу/ссылке. Выделяется формальный параметр – адрес фактическое. Место в стеке выделяется под адрес.
-
По имени. Интуитивно понятен.
Когда передаём адрес, мы имеем полный доступ.
В фортране все параметры передавались по ссылке. Преимущество – полный доступ. Опасность – мы не хотим параметр модифицировать. Можно было также передавать константы, и их можно было изменить. Ещё один недостаток – если передаём in-параметр (просто число), то это не эффективно, так как каждый раз используется адрес.
Большинство современных ЯП параметры передаются по значению и по указателю(программист на Си должен моделировать это передачей указателя)-ссылке (появился в СИ++)
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
Календарь
чт | вт | чт | вт | чт | вт | чт | вт | чт | вт | |
Сентябрь
| 05 | 07 | 12 | 14 | 19 | 21 | 26 | 28 | ||
Октябрь
| 03 | 05 | 10 | 12 | 17 | 19 | 24 | 26 | 31 | |
Ноябрь
| 02 | 14 | 16 | 21 | 23 | 28 | 30 | |||
Декабрь
| 05 | 07 | 12 | 14 |
Материалы к экзамену
Сравнение языков программирования