Записи по ЯП, страница 3
Описание файла
Документ из архива "Записи по ЯП", который расположен в категории "". Всё это находится в предмете "языки программирования" из 7 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Онлайн просмотр документа "Записи по ЯП"
Текст 3 страницы из документа "Записи по ЯП"
New( P2 );
P := P2; {порождение мусора}
Dispose(P2); {P – «висячая ссылка», попытка обращения к памяти, которую она занимает, приведёт к ошибке}
Различают системы с динамической сборкой мусора и без таковой.
Строгий язык с динамической сборкой мусора довольно надёжен.
От висячих ссылок защиты нет
Ада
В чистой Аде есть только new(p). В модуле STANDARD есть UNCHECKED_DEALLOCATION(p) – подчёркивается небезопасность этой операции
Примеры ошибок:
T *p;
Void f()
{
T x;
P = &x; //!!!адрес локальной переменной!!!
}
void Foo()
{
f();
free(p); //!!!попытка освобождения невыделенной памяти!!! – выдастся ошибка
}
new(p1);
p := p1;
Dispose(p1); {р «висит»}
Для Java, C# - указатели трансформировались в ссылки
Операторы перехода
goto
break;
continue; (в Модуле-2 EXIT)
return;
В современных языках программирования goto является только локальным
Для организации не локальных переходов:
setjmp, longjmp – В Си++ используются для обработки ошибок.
throw, trace – Обработка исключений
Также существуют специальные операторы для организации параллелеризма
Lock(obj) {блок} – Си#. Поток управления блокируется, если блок кем-то используется
accept, select – Ада
Базисы:
Язык Ассемблера <––> Си <––> Си++ < ––> Java, C#
Языки программирования в первую очередь различаются за счёт средств развития и их защиты.
Каков минимальный набор средств развития?
Этого уже достаточно для создания больших сложных программ, но без защиты новых абстракций
Глава 5. Подпрограмма
п5.1 Потоки управления – подпрограммы и сопрограммы
Управление входит через заголовок в блоке и возвращается в точку вызове, после выполнения тела.
CALLER – вызывающий подпрограмму(надпрограмма)
CALLEE – вызываемая подпрограмма
SUBROUTINE – подпрограмма
COROUTINE – сопрограмма
Также нарушение априорного порядка выполнения команд может происходить при генерации исключений.
Впервые механизм сопрограмм был придуман для компилятора COBOL. Вспомните задание по Си++ в 4-м семестре, где нужно было написать транслятор модельного языка:
Лексический анализатор, Синтаксический анализатор, Генератор кода – всё это сопрограммы.
Сопрограммы – фактически квазипараллельные процессы.
Модула-2
Вызов сопрограммы аналогичен длинному переходу на некоторый абстрактный адрес, по которому находится команда сопрограммы, с которой нужно начать выполнение. Но, помимо этого, нужно ещё как-то запомнить адрес возврата и другую служебную информацию, передать входные параметры, наследуется часть контекста. Для этой цели Вирт в своём языке Модула-2 ввёл тип данных ADDRESS (то же самое, что и «void *»).
Этот тип данных является потенциальной дырой в системе безопасности, т.к. любой указатель «Т *» автоматически приводится к «void *», и возможно обратное явное преобразование «Т *» = (Т *)«void *». Для Вирта было неприятной неожиданность то, что программисты часто использовали тип данных ADDRESS.
Строгость типизации зависит от возможностей преобразования.
Типы – непересекающиеся области эквивалентности, определяемые операциями на объектами этих областей.
Итак, в Модуле-2 вызов сопрограммы имеет такой вид:
NEWPROCESS(P, C,N);
Где P – процедура без параметров типа PROCEDURE, который является встроенным, C – переменная типа ADDRESS. N - размер области для «запоминания» информации. Область начинается с адреса C
PROCEDURE NEWPROCESS(P : PROCEDURE; VAR C : ADDRESS; N : INTEGER);
Передача управления от одного процесса другому на уровне сопpогpамм осуществляется процедурой "Передать управление от процесса P1 процессу P2". В Модуле-2 эта процедура выглядела как
PROCEDURE TRANSFER(VAR P1,P2 : ADDRESS);
При этом в переменную P1 записывается запись реактивации этого процесса, а значение переменной P2 определяет запись активации процесса P2.
RESUME; – оператор языка.
Маленькое замечание:
Изначально Вирт вместо ADDRESS использовал тип COROUTINE, теперь понятнее? Тип COROUTINE был похож не структуру.
В современных языках сопрограммы трансформировались в понятие потока.
.Net Thread Квазипараллельный поток
C# 2.0:
foreach(T x in C)
Тип T должен реализовывать интерфейс IEnumerable. Этот интерфейс содержит метод GetEnumerator(), который возвращает объект некоторого типа, который должен реализовывать интерфейс IEnumerator со свойствами Current,методом Reset и методом bool MoveNext(). Любой класс, поддерживающий интерфейс IEnumerable должен содержать класс, поддерживающий IEnumerator.
yield-операторы в C# 2.0:
yield return <expression>;
yield break;
Итератор – процесс(сопрограмма), выдающий последовательно очередные элементы коллекции тогда, когда они понадобятся. yield-оператор используется в блоке итератора для предоставления значения объекта перечислителя или для сообщения о конце итерации. Т.е. это не простой «return» или «break», а оператор, совмещающий в себе дополнительно работу по переходу между сопрограммами (от процесса-итератора в основной процесс). Выражение expression вычисляется и возвращается в виде значения объекту перечислителя; выражение expression должно неявно преобразовываться в тип результата итератора.
ublic class List
{
//using System.Collections;
public static IEnumerable Power(int number, int exponent)
{
int counter = 0;
int result = 1;
while (counter++ < exponent)
{
result = result * number;
yield return result;
}
}
static void Main()
{
// Display powers of 2 up to the exponent 8:
foreach (int i in Power(2, 8))
{
Console.Write("{0} ", i);
}
}
}
/* Output:
2 4 8 16 32 64 128 256 */
Генеральная линия развития C# - добавление элементов функционального программирования
п.5.2 Потоки данных в подпрограммах
-
Через глобальные данные
-
Через параметры
Побочный эффект действия процедур и функций – изменение значений глобальных переменных и данных, а так же модификация данных, глобальных по отношению к самой процедуре\функции.
Глобальная переменная – переменная, которая видна везде
В объектно-ориентированной парадигме:
Виды формальных параметров(семантика):
-
Входные (in) – должны быть определены до входа
-
Выходные (out) – должны быть определены к моменту выхода
-
Вх/Вых(InOut) – и то и другое
Способы передачи
Способ передачи – способ связывания фактических и формальных параметров:
-
По значению (семантика - in)
-
По результату (семантика – out)
-
По значению/результату (семантика – InOut)
-
По адресу(по ссылке) (семантика - любая)
-
По имени
Ада83:
Квалификаторы: in, out, inout
Procedure P(int X:T;inout Y:T;out Z:T);
X может быть выражением типа T. Компилятор может вставлять квазистатические проверки. Эффект процедуры – модификация Y и Z. Каков способ передачи определяет компилятор( что не есть хорошо, т.к. различные компиляторы в одной и той же ситуации могут выбрать разные способы передачи, что приведёт к различной работе программ).
Пользователь определяет семантику использования.
Формальные параметры – те, которые объявлены в заголовке подпрограммы и используются в теле. Большинство ЯП переменные, которые объявлены в заголовке, считают частью тела.
Фактические параметры – те, которые передаются в подпрограмму при её вызове.
При вызове подпрограммы фактические параметры, указанные в команде вызова, становятся значениями соответствующих формальных параметров, чем и обеспечивается передача данных в подпрограмму.
Способ передачи | Семантика | Что делается |
По значению | in | При вызове подпрограммы фактические параметры копируются в Запись Активацаии |
По результату | Out | При выходе из подпрограммы из записи активации формальные параметры копируются в фактические |
По значению и результату | inout | При вызове подпрограммы фактические параметры копируются в Запись Активацаии При выходе из подпрограммы из записи активации формальные параметры обратно копируются в фактические |
По Адресу | Любая | При передаче по Адресу в Запись активации копируется адрес фактического параметры. Именование и разыменование происходят автоматически |
-
В Фортране обычно параметры передаются по адресу, но когда передаётся простой объект данных, чтобы не происходило лишних операций разыменования, можно передавать «по значению и результату»( /<параметр>/)
-
В Аде-83 способ передачи зависел от компилятора, т.е. компилятор сам выбирал способ передачи в зависимости от ситуации. Пример программы, в которой это важно:
Procedure P(inout X : T; inout Y : T)
X := <newvalueX>;
<возбуждение исключения>
Y := <newvalueY>;
End P;
….
P(a,a);
Предположим, что оно не обрабатывается. Тогда запись активации пропадает. Значит, если была передача по ссылке, то значение «а» изменится, а если по значению и результату, то не изменится, т.к. копировать в «а» будет нечего.
Энтропия – явление, при котором программа может выдавать различные результаты при одних и тех же исходных данных. Если в программе есть энтропия, то это очень плохо. Очевидно, что при программировании на Ада риск энтропии значительно повышается, т.к. не известно какой способ передачи выберет в этот раз компилятор.
-
В Ада-95 – по значению, по ссылке
-
В Си – не определяется семантика использования. Способ передачи только по значению
-
В Си++ – по значению, по адресу (ссылке). Контроль семантики: in – ссылка константная, out, inout – не константная
void f( T &); //Компилятор считает, что f будет менять значение => константный объект //передавать нельзя
Это указание для компилятора, чтобы он следил за соблюдением семантики
class X
{
void f(); //неконстантная функция;
}
……..
const X a;// X * const this; внутри методов
a.f();// ошибка!!
class X
{
void f() const; //константная функция;
}
……..
const X a;// X * const this; внутри методов
a.f();// Правильно!!
-
С#, Java
void f( T x) {….;}
……
T a; // a – ссылка, если Т – объект
f(a); // передаётся ссылка
Оба языка поддерживают идею примитивных типов (которые в C# являются подмножеством типов-значений — value types), и оба для трансляции примитивных типов в объектные обеспечивают их автоматическое «заворачивание» в объекты (boxing) и «разворачивание» (unboxing) (в Java — начиная с версии 1.5).
object – предок всех классов. => Объект любого класса неявно приводится к типу object.
object o;
int i;
o = i;
i = o; // ошибка!
Автоупаковка, Автораспаковка:
o = i; // o = new Integer(i) – Java
// o = new Int32(i) – C#
Так что если функция объявляется как void f(object o), то в неё можно передавать любой объект( для примитивных типов будет производится автоупраковка\распаковка)
-
Java:
В Java параметры метода передаются только по значению, но поскольку для экземпляров классов передаётся ссылка, ничто не мешает изменить в методе экземпляр, переданный через параметр. Структур в Java нет.
Передача объектов примитивных типов в методы «как по ссылке» выполняется через классы-обёртки:
void f(Integer X){…X = ….; }
…..
int i = 1;
Integer px = new Integer(i);
f(px);
i = px;
Integer – класс-обёртка для примитивного типа «int». Суть способа – преобразовать объект примитивного типа в объект класса и работать внутри функции с объектом класса.
-
C#
для C# создана более развитая терминология:
Тип-значение(value type) – тип, объекты которого передаются по значению. Если где-то нужен объект такого типа, то отводится место под сам объект. типами-значениями являются простые(примитивные) типы данных и структуры