Языки программирования, 08 лекция (от 28 сентября)
Материал из eSyr's wiki.
Предыдущая лекция | Следующая лекция
Содержание |
Часть 1. Основные понятия традиционных процедурных ЯП
Глава 1. Скалярный базис
Пункт 6. Порядковые (ограниченные) типы данных (продолжение)
Перечислимые типы данных
Разногласия:
Перечислимые типы не расширяемые, что не согл с концепцией ООП. Поэтому в Oberon, Java нет перечислимых типов. До 90-х годов все языки содержали перечислимые ТД. C# содержит перечислимый ТД. При компонентном программировании перечислимые типы очень хорошо согласуются с ним. Например, есть IDL – язык для описания интерфейсов. Состоит из описания интерфейсов и перечислимых типов.
Перечислимые типы могут оказаться полезными, хотя не являются однозначно необходимыми.
Диапазоны
Ещё более горькая судьба постигла тип диапазон. Эволюция синтаксисиса:
(Pascal) i : 0..N;
(Modula) i : CARDINAL [0..50];
(Ada) INTEGER range 0..50; subtype L is range –N..N; — базовый тип по умолчанию INTEGER
(Delphi) i: 0..N;
В C отсутствует диапазон, потому что отсутствует какой-либо статический или квазистатический контроль.
Для диапазона должны быть определены соотношения предшествования, successor и predecessor. Для вещественных чисел нельзя определить диапазон, так как successor и predecessor в этом случае слишком сильно зависят от реализации.
Диапазоны служат для квазистатического контроля при индексировании массивов.
В Oberon диапазонов нет, В Java нет, В С# нет.
С математической точки зрения операция индексирования массива это функция (в Фортране и Аде она записывается именно в круглых скобках), у которой дискретный аргумент.
Полиморфизм — одному имени соответствует несколько сущностей. Например, перегрузка функций. В Си++ допускается перегрузка операций.
(C++) operator [](T i){...}
В C# есть очень эффективное средство для замены диапазонов.
(C#) T this (T1 e) {...} - индексер
В современных ЯП можно переопределить операцию индексирования. Диапазон на этом мы окончательно похороним.
Пункт 7. Указатели и ссылки
На нижнем уровне это суть адреса объектов. Основные операции, которые для них применяются — разыменование, new, присваивание.
В Ada и Oberon p.x применимо и в случае, если p — структура, и если p — указатель на структуру.
В других языках (C, Turbo Pascal) применима произвольная адресная арифметика: ++, +, -. В принципе это полбеды. Но есть ещё одна: адресная операция, которая применима к любому объекту, и тут возникают страшного рода вещи. Тут языки делятся на две группы:
- Безопасные языки
- Указатель тождественен объекту из динамической памяти
- Standart Pascal, Modula-2, Ada, Oberon
- Гибкие языки
- Указатель может указывать на любой объект памяти
- C, C++, Turbo Pascal, Delphi
- Языки без указателей
- Нет указателей - нет проблемы
- Java и С#
Но в C# есть managed код и unsafe код. Управляемый код безопасный, ибо идёт через вызовы .NET, в unsafe коде допускаются любые вызовы WinAPI, допускается получение указателей
Примеры использования:
(Modula-2/Oberon) TYPE PT = POINTER TO T; X:=NEW(T); X.i - доступ к полю данных
(Ada) type PT is access T; X:=NEW T; X.all - указатель
Проблемы использования указателей
- Мусор
(C++) X *p; X *p1; p=new X; p1=new X; p=p1;
- Висячие ссылки
(C++) X *p; X *p1; p=new X; p1=p; delete p;
Как только допускаем программисту удалять объект, язык становится небезопасным. Если забыть удалить объект, то образуется мусор. Если удалить объект и забыть очистить ссылку, то она становится висячей. Поэтому в современных языках появилась автоматическая сборка мусора.
В стандарте Ada не описан delete. Но автосборку не реализовали, т.к. писали для real-time систем и это противоречит соображениям надёжности. Тем не менее, в Аде появилось UNCHECKED_DEALLOCATION — неконтролируемое освобождение памяти.
Delphi, Модула-2 — без сборки мусора
- Ada — контролируемая сборка мусора
- Oberon, C#, Java — автоматическая сборка мусора
Страуструп хотел бы увидеть версию Си++ со сборкой мусора.
В 90х годах был отменен приказ, в котором приказывалось везде использовать адское программное обеспечение. В Аде-95 появились указатели для интерфейса с другим языком. Но сделали это грамотно, так, чтобы надёжность не упала.
(Ada-95) Type PT is access T; X : T; Y : alias T;
alias — не динамический объект, однако на него можно указывать с помощью указателя.
(Ada-95) P : PT; P := new T; //можно P := Y'access; P := X'access; //нельзя
В результате, если реализована динамическая сборка мусора, то можно отслеживать эти адреса. Это небольшое усложнение, но надёжность программ не падает и появляется возможность интерфейса с другими языками.
Что мешает сделать сборку мусора в C++? Существует такая версия, но только одна - управляемый C++ в .NET Сложности:
- &
(C++) int i; int *p; p=new int; p=&i; //появился мусор
- адресная арифметика
Указатель — слишком ненадёжная вещь. Поэтому в современных языках имеется тенденция заменять их на ссылки.
Ссылки делятся на две группы:
- Ссылки в С++ — аналог имени, применима только операция инициализации. Наиболее часто используемый случай — передача параметров. В результате возникает два способа передачи параметров — по значению и по ссылке. Поэтому в языке С прототипирование функций необязательно, а в С++ обязательно. Это —единственный тип C++, расширяющий иерархию ТД C. Если ссылка в классе, то единственное место инициализации — конструктор
(C++) int &a=b;
(C++) class X { int &r; x(int &a): r(a){...} }
- Ссылки в других языках — Java, C#, Delphi. В этих языках реализована референциальная модель объектов. Есть понятие простых ТД, а есть понятие классов
(Java) int [] a; a=new int [N]; b=a;
(C#) X x; X=new X;
(Delphi) A: X; A:=X.Create;
(WTF?) От этого менее или более сиплюплюсным язык не становился.
В Обероне понятие указателя превращено в понятие ссылки.
Пункт 8. Функциональный (процедурный) тип данных
Идейно близок к указателям или ссылкам. В большинстве ЯП есть указатель на процедуру. Объектами этого типа является все процедуры и функции в программе, которые являются соответствующими константами. К переменным подпрограммного типа применимы операции присваивания и вызова, а также сравнения на равенство.
В стандартном Паскале было 4 способа передачи параметров — по значению, по ссылке, функцию, процедуру. В ТП и Delphi появился подпрограммный тип, который позволил уменьшить количество способов передачи параметров до двух: по значению и по ссылке.
Классическая задача, которая очень удачно реализуется при помощи процедурного типа: вычисления интеграла.
(Oberon) TYPE FUNR = PROCEDURE(REAL):REAL; TYPE PROCVI = PROCEDURE(VAR:INTEGER); PROCEDURE INTEGRAL(F:FUNR;A,B,EPS:REAL):REAL;
В Java вместо функций передаются объекты, так что без них (функциональных типов) можно обойтись.
В C, или Smalltalk есть события и механизм callback - подписки на события.
(C) SetTimer(timerid,interval,...,callback); callback - процедура, которая вызовется
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 |
Материалы к экзамену
Сравнение языков программирования