Еволюція та "природний відбір" базових концепцій мов програмування: на прикладах мов C, C++, Java та C#

Коротко нагадуються деякі важливі історичні події, що мали суттєвий вплив на формування концепцій сучасних мов програмування загального призначення. Розглядається набір фундаментальних конструкцій та концепцій, які є свого роду будівельними цеглинками вказаних у назві чотирьох мов. Пропонується сист...

Повний опис

Збережено в:
Бібліографічні деталі
Дата:2004
Автор: Колодницький, М.М.
Формат: Стаття
Мова:Українська
Опубліковано: Інститут програмних систем НАН України 2004
Теми:
Онлайн доступ:https://nasplib.isofts.kiev.ua/handle/123456789/1348
Теги: Додати тег
Немає тегів, Будьте першим, хто поставить тег для цього запису!
Назва журналу:Digital Library of Periodicals of National Academy of Sciences of Ukraine
Цитувати:Еволюція та "природний відбір" базових концепцій мов програмуван-ня: на прикладах мов C, C++, Java та C# / М.М. Колодницький // Проблеми програмування. — 2004. — N 4. — С. 63-94. — Бібліогр.: 30 назв. — укр.

Репозитарії

Digital Library of Periodicals of National Academy of Sciences of Ukraine
_version_ 1860249403110981632
author Колодницький, М.М.
author_facet Колодницький, М.М.
citation_txt Еволюція та "природний відбір" базових концепцій мов програмуван-ня: на прикладах мов C, C++, Java та C# / М.М. Колодницький // Проблеми програмування. — 2004. — N 4. — С. 63-94. — Бібліогр.: 30 назв. — укр.
collection DSpace DC
description Коротко нагадуються деякі важливі історичні події, що мали суттєвий вплив на формування концепцій сучасних мов програмування загального призначення. Розглядається набір фундаментальних конструкцій та концепцій, які є свого роду будівельними цеглинками вказаних у назві чотирьох мов. Пропонується систематизація такого набору, яка показує, як відображаються компоненти архітектури комп’ютера у відповідні концепції мов програмування. Дану систематизацію зручно взяти за основу для проведення порівняльного аналізу цих мов. Наводяться систематизовані порівняльні таблиці базових імперативних концепцій чотирьох мов, а також порівнюються реалізації об’єктно-орієнтованих конструкцій в мовах C++, Java 2 та C#. На основі таких матеріалів проводиться аналіз еволюції базових концепцій цих мов. Кратко напоминаются некоторые важные исторические события, оказавшие существенное влияние на формирование концепций современных языков программирования общего назначения. Рассматривается набор фундаментальных конструкций и концепций, которые есть своего рода строительными блоками указанных в названии четырех языков. Предлагается систематизация такого набора, которая показывает, как отображаются компоненты архитектуры компьютера в соответствующие концепции языков программирования. Данную систематизацию удобно взять за основу для проведения сравнительного анализа этих языков. Приводятся систематизированные сравнительные таблицы базовых императивных концепций четырех языков, а также сравниваются реализации объектно-ориентированных конструкций в языках C++, The paper starts with a brief reminder of those important milestones in the history of programming languages (PL), which had a significant impact on the modern concepts of general purpose PL. It is followed by the consideration of the fundamental constructions and concepts, which are sort of building blocks of the languages discussed. Along the consideration path, a systematic presentation of the concepts is introduced. The systematic presentation displays how the computer architecture constituents are being mapped into corresponding programming language concepts. The systematic presentation is, then, taken as a basis for the comparative study of the languages. The result of the study is presented in the imperative language fundamental concepts comparative tables for four languages along with the comparative analysis of object-oriented constructions implementation in C++, Java 2 and C#. The result presented is a kind of input for the evaluation of the evolution of the programming languages fundamental concepts performed in the last section of the paper.
first_indexed 2025-12-07T18:41:07Z
format Article
fulltext Інструментальні засоби та середовища програмування © М.М. Колодницький, 2004 ISSN 1727-4907. Проблеми програмування. 2004. № 4 63 УДК 681.3.06 М.М. Колодницький ЕВОЛЮЦІЯ ТА "ПРИРОДНИЙ ВІДБІР" БАЗОВИХ КОНЦЕПЦІЙ МОВ ПРОГРАМУВАННЯ: НА ПРИКЛАДАХ МОВ C, C++, JAVA ТА C# Коротко нагадуються деякі важливі історичні події, що мали суттєвий вплив на формування концепцій сучасних мов програмування загального призначення. Розглядається набір фундаментальних конструкцій та конце- пцій, які є свого роду будівельними цеглинками вказаних у назві чоти- рьох мов. Пропонується систематизація такого набору, яка показує, як відображаються компоненти архітектури комп’ютера у відповідні концеп- ції мов програмування. Дану систематизацію зручно взяти за основу для проведення порівняльного аналізу цих мов. Наводяться систематизовані порівняльні таблиці базових імперативних концепцій чотирьох мов, а та- кож порівнюються реалізації об’єктно-орієнтованих конструкцій в мовах C++, Java 2 та C#. На основі таких матеріалів проводиться аналіз еволю- ції базових концепцій цих мов. Вступ Мови програмування, без сумніву, є однією із основних областей комп’ютерних наук та інформаційних технологій. Для ефективного володіння певною мо- вою важливо добре розуміти її базові концепції, свого роду бу- дівельні цеглинки мов, а для кращого їх розуміння корисно прослідкувати їх еволюцію та взаємозв’язок з різними мовами програмування. Особливо ак- туальною така задача є для нових мов програмування, таких, напри- клад, як Java та C# (читається: "сі-шарп"). Дана стаття присвя- чена саме цій проблемі. Після короткого історичного екскурсу щодо розвитку мов програмування проаналізуємо модифікації їх ба- зових концепцій на прикладі цих чотирьох мов та проведемо порів- няння об’єктно-орієнтованих (ОО) конструкцій мов С++, Java та C#, звернемо увагу на ті елементи мови, що були відібрані в ре- зультаті еволюції цих мов. 1. Коротка історія мов програму- вання: від Plankalkül до наших днів Найголовнішою рисою комп’ю- тера як технічної системи є те, що він є програмно керованою си- стемою. Більш детально цей факт можна представити рис. 1. Те, які можливості надають- ся для проведення програмного керування (на рис. 1 — program control), цілком і повністю ви- значається архітектурою ком- п’ютера (на рис. 1 — computer ar- chitecture). Згідно означення [1], архітектура комп’ютера — це опис поведінки функціональних компонентів комп’ютера, який проводиться в термінах машинної мови комп’ютера, тобто мови, що є не природною, а мовою програ- мування, проте — програмування Application Domain Software Hardware Functional components implementation Program control Computer architecture Рис. 1. Представлення комп’ютера як багаторівневої системи прошарків Інструментальні засоби та середовища програмування 64 найнижчого рівня. Власне, причи- ною створення мов програмування високого рівня (таких, як FORTRAN, C, Java) і була потреба у спрощенні процесу запису алгоритму керування комп’ютером при вирішенні прикладних задач з певної галузі застосування (на рис. 1 — application domain). Таким чином, на, так би мовити, природу мов програмування висо- кого рівня, тобто на набір їх базових концепцій, чиниться вплив одночасно з двох протилеж- них напрямків — з боку архітек- тури комп’ютера та з боку при- кладних задач (application do- main) для вирішення яких та чи інша мова проектується. Історично першими мовами програмування високого рівня бу- ли "Plankalkül" (Zuse, 1945), "Short Code" (Mauchky et al, 1949), "Intermediate PL" (Burks, 1950), "AUTOCODE" (Glennie, 1952), "A-2" (Hopper et al, 1953), "Algebraic Interpreter" (Lanin та Zierler, 1953), "FORTRAN" (Bacus et al, 1954- 1957), "ПП-2" (Камынин и Любимс- кий, 1954), "MATH-MATIC" (Katz et all, 1956-1958) та інші. Їх детальний огляд та аналіз прове- дено в [2]. Як бачимо, навіть за перше десятиріччя свого розвитку мови програмування вже відзнача- лися своєю різноманітністю як за їх кількістю, так і за змістом, тобто за тими концепціями про- грамування, що вони реалізовува- ли. Звичайно, задача проекту- вання мови як такої виконувалась разом із задачею створення її компілятора, тобто програми, що переводила процедуру керування комп’ютером, описану мовою "ви- сокого рівня", в таку, що відпо- відала рівню архітектури комп’ютера — "машинну програму", яка могла безпосередньо викону- ватися апаратними засобами комп’ютера. Розвиток технологій розробки компіляторів спричиню- вав, у свою чергу, вплив на роз- виток самих мов програмування, для яких такі компілятори ство- рювались. Це породжувало свого роду ланцюгову реакцію. Наступне десятиріччя харак- теризувалось "бумом" виникнення все нових та нових мов програму- вання. Ця ситуація у 1969 році в одній із публікацій була пред- ставлена у вигляді "Вавілонської вежі мов програмування" у порів- нянні з відомим біблейським "прототипом" [3]. Наведений факт звертає нашу увагу на те, що вже на досить ранніх етапах історії розвитку мов у зв’язку із склад- ністю процесу програмування була розпізнана важливість проблеми створення підходящого набору концепцій, який би допоміг зро- бити процес програмування мовами високого рівня більш легким. Пройшло ще 10 років, і в 1978 році темі обговорення ево- люції мов програмування вже була присвячена окрема конференція — Перша конференція з історії мов програмування, на якій обговорю- валося 13 мов та їх сімейств: APL, APT, ALGOL 60, BASIC, COBOL 60, FORTRAN, GPSS, JOSS, JOVIAL, LISP, PL / 1, SIMULA, SNOBOL [4]. Зауважимо також, що серед них не всі були мовами програмування загального призна- чення (general purpose languages), деякі з них — мови моделювання (specific domain- oriented), наприклад GPSS (dis- crete events system simulation), а деякі навіть мови керування певним обладнанням, як, напри- клад, токарним чи іншим верста- тами — APT (automatically pro- grammed tools). У даній статті надалі обме- жимося розглядом лише мов про- грамування загального призначен- ня і не будемо обговорювати спе- ціальні мови моделювання на зра- Інструментальні засоби та середовища програмування 65 зок GPSS, MatLab, Macsysma (так звані mathsoft та / або CAS — Com- puter Algebra System), а також не розглядатимемо мови логічного програмування типу Prolog або дуже спеціалізовані мови на зра- зок SNOBOL (string processing, text editing), RPG (Report Gen- erators), мови CASE-засобів, ле- ксичного (lex) та синтаксичного (syntax generators) аналізу, compiler compilers тощо. На Першій конференції з іс- торії мов програмування, зокре- ма, також зверталася увага на те, що в концепціях, які "вина- ходилися" в нових мовах програ- мування, багато що насправді вперше було запропоновано ще на початку 50-х років в найперших мовах програмування. Це ще раз свідчить про те, що питання ви- бору "раціонального" набору кон- цепцій мови програмування все ще залишалось актуальним на той час. У роботах Другої конферен- ції з історії мов програмування (1993) до дискусії про еволюцію мов та їх концепцій вже були включені також сучасні мови, та- кі, як С, С++, ADA, та інші [5– 18]. Інструментальні засоби та середовища програмування 66 2. Базові концепції імперативних мов програмування Як бачимо, проблема визна- чення набору базових концепцій мов програмування високого рівня та систематизація таких концеп- цій привертала до себе увагу протягом майже всього часу їх розвитку, і цій темі було при- свячено немало публікацій як в періодиці, так і в навчальнiй літературі [19–24]. Так, в одно- му з історично перших підручни- ків, присвячених цій темі, роз- глядається система концепцій мов програмування на прикладах мов Fortran IV, Algol-60, Cobol, SNOBOL, Lisp та PL/1 [20], піз- ніше до розгляду були включені також мови Pascal та Ada [21]. Деякі книги з цієї теми, напри- клад [22], поповнювалися и пере- видавалися декілька разів за останні 20 років, вводячи до роз- гляду все нові та нові сучасні мови програмування: C, C++, Prolog, ML, Smalltalk, Fortran- 90, Ada-95. В [23–24] поруч з розглядом мов імперативного про- грамування почали розглядатися також об’єктно-орієнтовані конс- трукції, мови функціонального програмування ML, Lisp, Haskell та інші парадигми. Все це лише ще раз підкреслює актуальність проблеми, якій і присвячена дана стаття. Набір базових концепцій, що наводиться нижче, був сформова- ний на основі вивчення зазначе- ної літератури, “офіційних” спе- цифікацій мов [26–30], а також аналізу того факту, що, як вже згадувалося вище, на мову про- грамування чиниться вплив з двох протилежних сторін — прикладних задач, що мають вирішуватися, та архітектури комп’ютера; це є свого роду вісь з двома полюса- ми: "потреби – засоби" (needs – means). Прикладом того, як впливала специфіка прикладних задач на конструкції мови програмування протягом їх історичного розвит- ку, може бути табл. 1, де показа- но, що виникнення потреби у та- ких специфічних задачах, як про- ведення обробки текстових даних (business data processing), спи- сків (list processing), маніпу- ляцій з символами (symbolic (formula) manipulation), ство- рення структур даних, визначених користувачем (user-defined data structures), тощо, приводило до впровадження відповідних конс- трукцій у різних мовах або на- віть до виникнення нових мов програмування. (Ще раз нагадаємо, що тут розглядаються тільки імперативні (imperative, або procedural, або command) мови програмування, а Таблиця 1. Вплив на базові конструкції мов програмування, спричи- нений вимогами прикладних задач Вимоги прикладних задач (application domain requirements) Numerical scientific computa- tion Business data process- ing List proc- es- sing Symbolic (formula) manipulati on Multi- pur- pose User- defined data structures Dynamic storage alloca- tion Inter- active System program- ming Мови, в яких вимо- ги були реалізова- ними впер- ше FORTRAN- IV Family*, ALGOL-60 COBOL LISP FORMAC JOVIAL , PL / 1 ALGOL-68 APL, SNOBOL JOSS, BASIC CPL, BCPL, C (1969– 73) Рік 1954– 1960 1959 1962 1959, 1968 1960, 1964, 1962, Інструментальні засоби та середовища програмування 67 також об’єктно-орієнтований під- хід і не розглядаються мови ло- гічного або функціонального про- грамування, мови-сценаріїв (scripts) тощо.) Для оцінки того, який зв’язок існує між конструкціями мови програмування та архітектурою комп’ютера, доцільно звернути увагу на те, що остання фактично може бути представлена наступним списком концепцій — табл. 2. Інструментальні засоби та середовища програмування 68 Таблиця 2. Базові концепції для представлення архітектури комп’ютера L * Складові/компоненти концепції архітектури комп’ютера 1 Дані (Data): – Імена (Name): – Пам’ять (Memory type, Address type, space (size), and organi- zation) – Режим адресації (Addressing method) – Значення (Value, data format): – Числа десяткові (Fixed-Point Numbers) – Числа, представлені у форматі з плаваючою комою (Floating- Point Numbers) – Логічні значення (Logical Data) – Символи та рядки символів (Character Strings) – Агрегатні дані та масиви (Arrays) 2 Операції (Operations): – Арифметика десяткових чисел (Fixed-Point Arithmetic) – Арифметика чисел у форматі з плаваючою комою (Floating-Point Arithmetic) – Логічні (Logic) – Бінарних відношень (Relational Operations) – Обробки символів та рядків символів (Data Handling) – Обробки масивів чисел (Numeric-Array Operations) 3 Виконання інструкцій (Instruction Sequencing): – Лінійна послідовність (Linear Sequence) – Розгалуження (Decision) – Циклічна послідовність (Iteration) К е р у в а н н я о б ч и с л е н н я м и ( c o m p u t i n g c o n t r o l ) – Виклик функцій чи процедур (Delegation) 4 Більш високий рівень керування (Supervision and Operating System support): – "Одночасне" виконання певних дій (Concurrency and multiprocessor computation) – Перемикання між процесами (Control Switching and interruption) – Збереження стану обчислень (State-Saving) – Взаємодія процесів (Inter Process Communication, IPC) та синхроні- зація процессів – Цілісність даних (Data Integrity, memory protection, resource sharing, data access) 5 Введення / виведення (Input / Output) та зв’язок по мережі (and communication): – На зовнішніх пристроях (Input / Output Devices) К е р у в а н н я р е с у р с а м и к о м п ’ ю т е р а ( c o m p u t e r r e s o u r c e s m a n a g e m e n t ) Інструментальні засоби та середовища програмування 69 Детально ці концепції роз- глядаються в [1] і в даній стат- ті додатково не описуються. В даному контексті достатньо мати лише їх представлення у певному, систематизованому вигляді, тобто деякого структурованого списку, як у табл. 2. Як побачимо далі, перша ча- стина табл. 2 — керування обчис- леннями (computing control) — відображається у відповідних концепціях та конструкціях мов програмування (див. нижче в табл. 3 розділи 3–7, тобто data (variables, constants), expressions, control flow operators, functions). Друга ча- стина табл. 2 — керування ресур- сами комп’ютера (computer re- sources management) — знаходить своє відображення у структурі бібліотек стандартних функцій (чи класів), що звичайно поста- чаються з компілятором мови про- грамування та “бібліотеки часу виконання” (run-time library). Отже, об’єднавши зазначені вище ідеї, тобто розглянувши су- місний вплив на набір концепцій мови одночасно і з боку констру- кцій задач предметної області і з боку різноманітності компонен- тів архітектури комп’ютера, отримуємо набір базових концеп- цій мов програмування високого рівня — табл. 3, друга колонка. В колонках 3–6 табл. 3 вказується на те, чи є така концепція або конструкція реалізованою в мовах С, С++, Java та C# відповідно (знаки “+” чи “–”), а також на- водяться посилання на короткі коментарі (пронумеровані цифрами від 1 до 42) щодо особливостей семантики цих конструкцій. Зауважимо тут також, що концепції, пов’язані з об’єктно- орієнтованим програмуванням (ООП), не включені до табл. 3, а розглядаються трохи нижче (див. табл. 4 та 5). Одночасно мова С вилучена із порівняння в табл. 5, оскільки не є об’єктно- орієнтованою. В табл. 3 та 5, крім того, назви конструкцій та концепцій мови в основному наведені англійською мовою, тобто мовою їх першо- джерела, з метою уникнення над- лишковості, спричиненої транслі- терацією термінів. Це сприяє та- кож вживанню коректної та уніфі- кованої термінології, не спотво- реної неточними перекладами. Са- мі терміни в табл. 3 та комен- тарі до них наводяться у досить стислому виді, що пов’язано з обмеженими розмірами даної пуб- лікації. З цією ж метою в тексті також опущені деякі посилання на літературу, з якої запозиченні загально прийняті означення тер- мінів та певні “сталі вирази”. Проте це не повинно спричинити труднощі для читача, обізнаного з основами теорії мов програму- вання або маючого досвід з про- грамування хоча б однією з мов, що тут розглядається. Додамо та- кож, що табл. 3–5 ні в якому разі не можуть розглядатися як такі, що дають абсолютно вичерпну ін- формацію з усім можливим ступе- нем детальності про всі констру- кції вказаних мов. Для цієї мети служать специфікації мов та до- даткова документація до них. За мету створення даних таблиць ав- тор бачив необхідність наведення стислого та систематизованого переліку концепцій та конструк- цій мов, який був би корисним на практиці при вивченні мов та їх порівнянні. Нижче наводять стислі ко- ментарі до табл. 3, пронумерова- ні цифрами від 1 до 42. 1 C / C++ програма складаєть- ся з одного або декілька (source-) файлів, що називаються “translation unit”; source-файл є колекцією речень. В Java-- програмі “translation unit” це або клас, або package, в якому містяться декілька класів; в C# Інструментальні засоби та середовища програмування 70 — це або клас, або namespace, в якому містяться декілька класів. Кожний клас в package / namespace складається із речень (sentence). Додамо, що в традиційно (див., наприклад, [20]) класич- них імперативних мовах, таких, як Fortran, Algol-60, PL/1, Pascal, розглядалася система іє- рархічних рівнів програми, та- ких, як 1) програма (program) — одиниця виконання; 2) процедура (procedure) — одиниця компіля- ції, модульності; 3) блок (block) — одиниця облас- ті дії iмен та обробки перери- вань; 4) оператор (statement, compound statement) — Інструментальні засоби та середовища програмування 71 Таблиця 3. Базові концепції мов програмування С, С++, Java 2 та C# Базові концепції та конструкції мов програмування С С++ Java C# 1 2 3 4 5 6 1 Структура програми (program structure 1 ): – a primary translation unit (містить main() функцію): – header file (optional) + + – – – source file (складається із речень (sentences) мови) + 2 + + + 2 – other translation units: – header files + + – – – source files + + + + 2 Речення (sentences 3, іноді вживається також термін statements): – directives and pragmas див. нижче п. 3 – data declarations, definitions, and initialization; (див. також коментар № 19) див. нижче п. 4 – expression and control flow див. нижче п. 5, 6 – functions див. нижче п. 7 – comments 4 and punctuators (separators) + + + + 3 Директиви, макроси та прагми компілятора (directives, macro and pragmas): – compiler directives, macro definitions (#include, #define, etc.) + + – 5 + 6 4 Дані (data), тобто змінні величини (variables) чи константи: 4.1. Імена змінних (names, identifiers) 7a: 4.1.1. Naming rules: – only letters and digits starting with a letter or underscore symbol "_" + + + 7 + 7 – case sensitiveness; distinct from reserved words + + + + 8 – the unlimited length of a name. – 9 – 9 + + 4.1.2. Scope (or access) 10 (область дії або “доступ до…”): – scoping rules + 11 + 12 + 12a + 12a 4.1.3. Namespace (referencing environment) 13: – типи namespace – + 14 + 14a + 14a 4.1.4. Address of a storage area 15: – variable’s address, address alias + + + 15a + 15a – address type: static memory, register, stack, and heap (див. також “Lifetime”) + + + + 4.1.5. Linkage 16 of names: – external + + – 16 + 16 – internal and none + + + + 4.2. Значення (values, objects 17): 4.2.1. Types 18 (або data format): – різноманіття вбудованих типів даних (build-in types) див. табл. 3.1 – data declaration and definition 19; forward declaration + + + 19a + 19a – name type compatibility (anonymous type names, type name alias) + 20 + 20 – 21 – 21 – type checking, conversion (див. також п. 5. Expressions / type conversion) + + + + 22 4.2.2. Lifetime 23 або storage classes (categories of variables according to their lifetime): – static 24; stack-dynamic (are allocated from run-time stack, local variables) + + + + – explicit or implicit heap-dynamic; fixed + 25 + 25 + 25 + 25a 4.2.3. Initialization: – Initial values for different storage classes 26 + + + 26a + 26a 4 a Data; constants (вживається також термін literals 27): – 4.1.a. Named constants (manifest constants: const та final) + 28 + + 28 + – constants with scope and /or dynamic binding of values 29 – + + + – 4.2.a. Typed constants (build-in types of constants – див. табл. 3.2) + + + + 4 b Data; labels. + + – + 5 Вирази (Expressions: operations (operators) with typed variables or constants): – general notions: – operators: – rules: precedence, associativity; side effect; "l- values" and "r-values" 30 + + + + Інструментальні засоби та середовища програмування 72 Продовження табл. 3 1 2 3 4 5 6 – assignment statement: – simple assignment ( x = b; ) + + + + – multiple assignment ( x = y = b; ) + + + + – conditional assignment (_ ?Op1:Op2_) + + + + – compound assignment ( += –= *= /= %= <<= >>= &= ^= |= ) + + + + – arithmetic expressions: – arithmetic operators: ( + – * / % Op++ Op–– ) + + + + – operands: numeric types as well as some others + + + + – relational expressions: – relational operators: ( > < >= <= == !=, а також is та as для C#) + + + + – operands: numeric types as well as some others + + + + – Boolean expressions: – logical (Boolean) operations (short-circuit evaluation): ( && || ! ) + + + 31a + 31a – operands: Boolean type + + + + – Bitwise Boolean expressions: ( & | ~ ^ << >> ) + + + 31 + 31a – операція взяття адреса & та значення за адресом (dereference) *Op; boxing / unboxing + + + + – coma operator: ( , ) + + + + – overloaded operators: – overloaded operators for build-in primitive types (arithmetic +, / etc. for int, float, etc) – + + + – overloaded operators for user-defined types (string, arrays, etc.) – + + + – перетворення типів (type conversion; див. також вище п. 4.2.1. Types): – явне (explicit), тобто casting: (int), (float), ... та as для C# + + 32a + + – неявне (implicit); issues 32 + + + + – typeof, sizeof, sizeof( ), instanceof, checked, unchecked опера- тори 33 + + + + – object creation / deletion operations – + + + – доступ до елементів об’єкта складного типу: – елемент масиву: [ ] або [ ][ ] + + + + – член структури, union, об’єкту класового типу: . .* -> ->* : : base + 34 + + 34a + 34a – елемент в межах namespace: with – + + + – exception handling (overflow, underflow, divide by 0): try- catch-throw оператори – + + + 6 Оператори керування обчисленнями (control flow operators або statements): – compound statement 35 + + + + – selection statements: – two-way selection statement (if / then / else) + + + + – multiple selections (switch / case / break / default) + + + + 36 – iterative statements: – counter-controlled loop 37: for (expr_1; expr_2; expr_3) {statement} + 37a + 37b + + – logically controlled loops (while / do): – while (expression) {statement} + + + + – do {statement} while (expression) + + + + – how a single loop or several nested loops can be exited?: break / continue + + + + – iterations based on the data structure: iterator; foreach / in – – + + 38 – unconditional branch statement ( goto label) + + – 39 + 7 Функції, визначені користувачем (user defined functions) 40: – function prototype (or signature): – parameter passing: by value, by address, by name (reference); return value – 40a + + + – variable number of parameters + + – + – parameter initial values – + – – – functions as parameters + + – + 40b – variety of function organization: – global functions (local and non-local variables, side- effect) + + – 41a – 41a Інструментальні засоби та середовища програмування 73 одиниця послідовності обчис- лень; 5) вираз (expression) — констру- кція, що створює значення; 6) посилання (reference) — засіб доступу до значень; 7) маркер (token (keyword, identifier)) — молекулярна синтаксична одиниця; 8) символ алфавіту (character) — атомарна синтаксична одиниця. В даному пункті таблиці розгляда- ється найвищий рівень такої іє- рархії — рівень “програмної оди- ниці компіляції”. Інші ієрархіч- ні рівні програмних елементів розглядаються в даній таблиці в інших відповідних розділах за- пропонованої тут систематизації. 2 Головна функція (main- function) викликається на почат- ку роботи програми (program start-up). В одному або декіль- кох класах C# може бути декілька функцій Main(), хоча і різного прототипу, але лише одна з них викликається на початку. 3 З точку зору компілятора кожне речення (sentence) є по- слідовністю tokens (lexemes, terminals), розділених сепарато- рами (separators): blank charac- ter, tabs, carriage-return, line-feed, form-feed, comment. Подалі tokens поділяються за їх семантикою на групи: identifiers (names), constants, operations (operator), keywords (control flow statements, declarators, etc.), punctuators. Речення у всіх мовах закінчуються пунктуа- тором “;”. (Нагадаємо, що в мові Pascal, на відміну, наприклад, від C, символ “;” вживався для розмежування операторів мови, тобто як “separators”, а не як ознака кінця речення-statements, тобто не як “delimiter”.) Кожний token складається із символів наперед визначеного алфавіту: стандартний набір ASCII символів для tokens, спеціальні послідов- ності символів для керування введення / виведення (escape sequences), стандартний та не- стандартній набір ASCII символів для коментарів. В Java та C# підтримується також набір Unicode символів (Unicode character set). 4 В мові ANSI C дозволяють- ся багаторядкові, але не вкладе- ні коментарі, що вводяться за допомогою пари символів /* та */. В мовах C++ / Java / C# додат- ково вводять однорядкові комен- тарі “ / / ”. І нарешті, в C#, крім цого, надається також мож- ливість коментувати текст симво- лом “ / / / ” для подальшого його використання в XML-файлах. 5 В Java-програмі “дирек- тив” та “прагм” немає; проте ключове слово import (а далі слідує ім’я package) можна роз- глядати як певний аналог дирек- тиви “#include” в C / C++. 6 В C#-програмі, як і в C / C++, є багатий набір “дирек- тив”, наприклад ряд директив для умовної компіляції, таких, як #define, #undef, #if, #elif, #else, #endif, а також для іншо- го призначення: #line, #error, #region, #endregion. Ключове слово using, а далі слідує ім’я namespace, можна також розгляда- ти як певний аналог директиви “#include” в C / C++. Крім того, C# надає механізм для визначення декларативних тегів, що назива- ються атрибути (attributes), якими можна позначити необхідні фрагменти програми, щоб ввести опис певної бажаної додаткової інформації. Потім, під час вико- нання програми, ця інформація може бути використання за допо- могою механізму, що називається reflection. Так що концепцію attribute в C# можна також вва- жати певним різновидом директив компілятора. 7a Імена (names) використо- вуються для посилання на конс- трукції дані, декларованих у Інструментальні засоби та середовища програмування 74 програмі. В Java / C# такими конструкціями є пакет або об- ласть імен (package/namespace), класовий тип (class type), ін- терфейс (interface type), члени такого типу даних, як посилання (reference type), параметри фун- кцій або локальні змінні. Корот- ко кажучи, імена вводяться для пакетів, типів та змінних. В останньому випадку — для імен змінних — використовується також термін “ідентифікатори”. В мові ANSI C ідентификатор позначає: 1) об’єкт, 2) функцію, або 3) одну з наступних конструкцій: 3.1) тег структури (structure), об’єднання (union), або перера- хування (enumeration); 3.2) член структури, об’єднання, або пере- рахування; 3.3) ім’я нового типу (typedef name); 3.4) ім’я мітки (label name); 3.5) ім’я макросу (macro name); 3.6) параметр мак- росу (macro parameter). В ООП імена (ідентифікатори) вводяться також для класів та пов’язаних з ними конструкцій. Ідентифікатор називають простим, у випадку простих (не структурованих) змінних та кваліфікованим (qualified) — у випадку імен– членів складних об’єктів, як-то структури, класи тощо. Кваліфі- кований ідентифікатор є послідо- вністю ідентифікаторів, розділе- них символом крапка “.” Для того щоб компілятор міг “працювати” з ім’ям змінної (тобто ідентифікатором) в про- грамі, ім’я повинно бути допов- нено інформацією про певні його атрибути та відповідне йому зна- чення. Тобто повна інформація про ідентифікатор в компіляторі представляється як трійка- сукупність трьох відомостей: Name / Attributes / Value. При цьому атрибути харак- теризують такі властивості іден- тифіксатора, як [21]: 1) тип (type), тобто дозволений діапа- зон значень даних для цього ти- пу; 2) як і коли він створюється (life-time); 3) діапазон його видимості (scope of its name); 4) тип пам’яті, де зберігається його значення (storage class). Як правило, змінні вводяться в програму за допомогою механізму, відомого як декларація (declaration). Встановлення від- повідності між ідентифікатором та його атрибутами та значенням називається binding (“прив’язка”). Процес binding для деяких атрибутів може відбу- ватися відразу при декларації змінних на етапі компіляції, для деяких інших атрибутів — на ета- пі виконання програми. Значення можуть бути надані змінним за допомогою процесів: 1) ініціалі- зації (initialization), тобто тоді, коли змінна створюється; 2) оператора присвоювання (assignment); 3) передачі (trans- mission) значення до змінної при операції введення (input). 7 В Java / C#-програмі допус- тимі символи для ідентифікаторів вибираються не з ASCII, а з Unicode набору для букв (letters) та цифр (digits); В C# вони також не повинні включати такі спеціальні символи, як “#” чи “$”. 8 В C#-програмі, як і в Java, ідентифікатори не повинні співпадати з ключовими (зарезер- вованими) словами (див. відпові- дні таблиці ключових слів у до- кументах по специфікації мов [26–30]), а також назвами буле- вих літералів (true та false) та null; проте в C# додатково до- зволяються імена, що складаються із символу "@" на початку та на- ступного за ним ключового слова, наприклад “@if ”. 9 В ANSI C-програмі макси- мальна довжина ідентифікатора складає 6 або 31 символів алфа- віту, в MS Visual C++ — 247. Інструментальні засоби та середовища програмування 75 10 Концепція scope означає діапазон операторів тексту про- грами, у якому змінна є видима, тобто може бути використана. Для того щоб змінна була видима в певному діапазоні, вона повинна бути в ньому задекларована. 11 Існує чотири типи діапа- зону видимості: 1) блок, 2) фун- кція, 3) прототип функції, та 4) файл. Діапазон видимості файлу, що містить main-функцію, назива- ють також глобальною областю ви- димості (global scope). 12 На доповнення до вказаних вище в мовах C++ / Java / C# вво- диться також п’ятий вид “області дії” — класовий (class scope). 12a В мовах Java / C# змінні некласового типу або функції, що не є членами класу, не підтриму- ються, тобто не можуть мати гло- бальної області видимості (global scope level). 13 Традиційно в різних мовах програмування виділяють різні набори програмних елементів, що можуть мати імена [22]: 1) змін- на; 2) тип, визначений користу- вачем; 3) константи вбудованих типів; 4) константи типів, ви- значених користувачем; 5) базові операції; 6) мітки (labels) опе- раторів (свого роду імена опера- торів); 7) формальні параметри; 8) підпрограми; 9) виняткові си- туації. В мовах C / C++ / Java / C#, якщо більше ніж одна декларація певного іде- нтифікатора є видимою в певній точці програми, така багатознач- ність розв’язується на основі синтаксичного контексту, в якому знаходиться посилання на даний ідентифікатор. Таким чином, іс- нують відмінні області імен (name spaces) для різних катего- рій ідентифікаторів, наприклад: імена міток; імена тагів струк- тур, об’єднань та перерахувань; імена членів структур чи об’єднань. Фактично, name space — це свого роду внутрішнє (для компілятора) ім’я масиву, в яко- му зберігаються імена ідентифі- каторів. Тобто для різного виду ідентифікаторів використовуються різні масиви: один — для імен структур, один — для імен міток, один — для імен звичайних змін- них. Для кожного з таких типів ідентифікаторів name space в C++ означає область декларації (declarative region). 14 В C++/C# існує також клю- чове слово namespace. По суті, воно відображає подальший розви- ток концепції scope, є наступним рівнем абстракції після class scope. Воно є аналогом ключового слова package в Java. Конструк- ція namespace створює область декларації (declarative region), яка приєднує додатковий іденти- фікатор до кожного імені, об’явленого в межах цієї облас- ті. 14a В Java / C# немає глоба- льних змінних, але є global namespace; в Java йому відпові- дає unnamed package. 15 Потрібно розрізняти по- няття “адреси значення змінної” та “адреси ідентифікатора”, оскільки можуть бути однакові імена (що мають різну область видимості — scope) і, значить, вони будуть мати різні адреси. В той же час деяка величина може зберігатися за певною адресою, на яку можуть вказувати також деякі інші змінні-вказівники (pointers або references). Таким чином, ідентифікатор змінної має синоніми (alias). 15a В Java / C# хоч і немає вказівників (pointers), викорис- товуючи reference type, можливо зробити так, щоб дві змінні по- силалися на той самий об’єкт. 16 Можна зробити так, щоб один і той же ідентифікатор, об’явлений у різних областях ви- димості, міг посилатися на одне й теж саме значення змінної (чи Інструментальні засоби та середовища програмування 76 об’єкта) або функції. Процес, що це забезпечує, називається лін- ковка (linkage). В мовах Java ключове слово “external” відсут- нє, але поняття, подібні до external linkage, використову- ються (див. наприклад, “імпорт пакетів”). 17 Об’єкт (object) є імено- вана область зберігання даних в обчислювальному середовищі; зміст цієї області може предста- вляти значення (див. також l- values нижче). За винятком біто- вих полів (bit-fields), об’єкти складаються з неперервної послі- довності одного або декількох бітів, кількість, порядок та внутрішній формат яких є або яв- но описаним, або визначається неявно реалізацією [26]. Якщо ідентифікатор об’єкта чи змінної був об’явлений з локальною обла- стю видимості (тобто в блоці або функції), тоді об’єкт чи змінна звичайно називаються “локальни- ми”; у протилежному випадку вони “глобальні” в мові С / C++ та “нелокальні” в Java / C#. (Більш детальніше про об’єкти в C++ / Java / C# див. нижче в табл. 4, 5.) Див. також коментар 1 до табл. 3.1. 18 У кожній мові розгляда- ється певна кількість вбудованих типів даних (build-in types — див. табл. 3.1) та надається мо- жливість конструювати нові, ви- значені користувачем (user- defined) типи. 19 Для кожної змінної вели- чини (variables) або об’єкта (object) розглядається поняття declaration (див. також коментар 7a) та definition. Декларація вводить до розгляду імена змін- них (тобто ідентифікатори) та їх типи і, як правило, не резервує для них пам’ять, значить, ніяк не визначає їх початкові значен- ня. (Для уточнення див. поняття змінних з global scope, а також static memory.) Дефініція змін- них резервує для них пам’ять ви- значеного (типом даних) формату. У всіх чотирьох мовах декларація є явною. 19a В Java / C# немає необ- хідності у forward declaration, оскільки порядок декларації є несуттєвим. 20 Конструкція, наприклад "struct tagStruct {int i;} s1;", вводить до розгляду новий (стру- ктурний) тип tagStruct. Якщо в такій конструкції ім’я tagStruct буде опущено, то такий тип нази- вається анонімним. В мові C за допомогою оператора typedef можуть бути введені до розгляду синоні- ми імені типу tagStruct. В С++ ім’я tagStruct та ім’я типу є синонімами по замовчуванню. 21 В Java / C# немає операто- ра typedef. В той же час ідея синонімів імен типу (type name alias) також присутня, але в трохи іншому вигляді: імена вбу- дованих типів (int, float, і т.д.) є синонімами певних, напе- ред визначених в системі струк- тур (наприклад, System.Int32 то- що). Нові типи ж вводяться за допомогою опису нового класу (class) — див. нижче розділ ООП, і таким чином потреба в конструкції typedef відпадає. 22 В C# додатково до звичай- них правил type conversion, що присутні у всіх чотирьох мовах, існує також конструкція “boxing / unboxing” для проведен- ня перетворень між даними value type та reference type. 23 Поняття часу життя (lifetime) змінної чи об’єкта означає той час, коли змінна чи об’єкт є асоційованими (bound) до певної області пам’яті. 24 Поняття статичної (static) змінної означає, що її значення залишаються дійсними, тобто зберігаються в пам’яті, за час, що проходить між різними викликами функцій, в яких ця Інструментальні засоби та середовища програмування 77 змінна знаходиться. Іншими сло- вами, статична змінна має глоба- льний час життя (іноді кажуть також history non-sensitive). 25 У мові C для виділення пам’яті динамічним змінним вико- ристовуються функції alloc(), malloc(), realloc(). В мовах C++ / C# / Java введено нове клю- чове слово new та слово delete в мові C++. Динамічні змінні є асоційованими (bound) з областю динамічних даних, що часто нази- вається “кучею” (heap), тільки тоді, коли цим змінним присвою- ється деяке значення. 25a В C# будь-який динаміч- ний об’єкт можна позначити за допомогою ключового слова fixed, для того щоб тимчасово перешко- дити його вилучення із кучі за- собом компілятора, що називаєть- ся “збір сміття” (garbage col- lector). 26 Для глобальних змінних класового типу порядок їх ініці- алізації визначається порядком їх декларації (див. також комен- тар 12а). В мовах C++ / Java / C# для глобальних об’єктів, які ма- ють в свою чергу члени-об’єкти, порядок ініціалізації не визна- чено мовою. 26a В Java / C# будь-яка змінна повинна мати початкове значення, перед тим як вона буде використана. 27 Доцільно тут звернути увагу на походження слова “literal”, яке (так само як і його синонім “literally”) в анг- лійській мові означає “букваль- но, дословно”. 28 У мові C конструкція manifest constants вводиться ли- ше за допомогою директиви пре- процесора #define і не існує ключового слова const, як в ін- ших C-подібних мовах. В мові Java використовується ключове слово final, а також існує клю- чове слово const, але воно не використовується за призначенням і служить лише для контролю ком- пілятором над вживанням цього зарезервованого слова як іденти- фікатора. 29 У мові C++ синтаксис для членів класу, що мають модифіка- тор const static, ускладнює де- кларацію символьних констант в середині цього класу. Зокрема, компілятор може не обрахувати (not bind) значення статичних констант-членів класу. Це озна- чає, наприклад, що такі констан- ти (тобто їх величини) не можуть бути використані для декларації розміру масиву. Щоб подолати та- кий недолік конструкції “статич- ні константи”, можна використати тип enum. В C# константи по за- мовчуванню розглядаються як static члени і декларація конс- тант не дозволяє використовувати static модифікатор. 30 Терміни "l-values" (зна- чення локатор виразу (locator expression)) та "r-values" (зна- чення E2 виразу) походять від задачі опису виразу загального виду: E1 = E2. Конструкція l- value є вираз, що посилається на об’єкт (див. також концепцію “об’єкт” вище). 30a Позначення Op є скоро- ченням слова “Operand”. 31 В мові Java додатково іс- нують також операції >>>, >>>=, які означають unsigned right shift та unsigned right shift assignment відповідно. 31a В Java / C# операції bitwise operation називаються logical operation, а logical Boolean operation — conditional operation. Операндами bitwise operation можуть бути не тільки бульові, але і цілі типи: на- приклад 0x03 | 0x05 як результат дасть 0x07. 32 Перетворення int в float означає, що 9 десяткових цифр 4- х байт перетворюються в 7 десят- кових цифр 4-х байт; перетворен- ня float в int називають також Інструментальні засоби та середовища програмування 78 “coercion”. В Java ключове слово strictfp вказує, що вирази від- повідають умові FP-strict. 32a В C++ дозволяється явне перетворення типів з використан- ням синтаксису, подібного до ви- клику функцій (function-style syntax): d = float (i); явне пе- ретворення типів можна також за- давати, використовуючи кастінг- синтаксис (casting). Попередній приклад, переписаний з викорис- танням кастінгу, буде мати на- ступний вигляд: d = (float) i. Обидва випадки перетворень нада- ють однаковий результат, коли перетворюються прості значення. Проте у випадку синтаксису функ- ціонального стилю можна задавати більше ніж один аргумент для пе- ретворення. Така відмінність є важливо для типів, заданих кори- стувачем (user-defined types). 33 В цих мовах існує різна комбінація набору таких операто- рів, але їх деталі тут не роз- глядаються. 34 У мові C, оскільки вона не є мовою ООП, не підтримується доступ до об’єктів класового ти- пу, статичних членів та scope resolution “: :”. 34a У мовах Java / C# існує тільки оператор “.”, оскільки в них немає типу вказівник (pointer). 35 Складний оператор (compound statement) дозволяє представити (абстрагувати) набір операторів як один, більш абст- рактний оператор; блок (block) є складним оператором, що, крім того, містить декларацію даних, тобто серед операторів якого є оператори декларації даних. 36 В C# кожний оператор ви- бору (case) повинен включати оператор break. Крім того, в операторі switch керуючий пара- метр може бути не тільки типу int або enum, але і string. 37 В кожній мові програму- вання при описі оператора циклу (loop statement) розглядається набiр його характеристик (common features): 1) специфікація опе- ратора циклу: ключове слово та наступна за ним синтаксична структура; 2) позиція тестування; 3) тип змінної керування (змін- ної циклу); 4) початкове значення: констант- не, змінне або задане виразом; 5) крок (прирощення) циклу; 6) верхня границя (граничне значен- ня); 7) те, чи можна переходити граничне значення протягом вико- нання циклу; 8) спосіб виходу з циклу та/або спосіб пропуску кроку циклу; 9) те, чи зберіга- ється значення контрольного па- раметру при виході із циклу та чому воно дорівнює. 37a У мові C тіло оператора циклу for виконується нуль або більше разів, доки виконується умова. Можна також, використову- ючи додаткові вирази, ініціювати та змінювати значення змінних протягом виконання циклу for. 37b В мові C++ специфікація оператора циклу for може включати також дефініцію змінних; крім то- го, термінальний вираз може бути типу Boolean. Наступний оператор циклу for: for (for-init-statement; expression1; expression2) { // Statements } є еквівалентним оператору циклу while: for-init-statement; while( expression1 ) { // Statements expression2; } Якщо керуюча змінна циклу була продекларована у середині виразу for-init-statement, тобто з локальною областю видимості, тоді її значення не буде збере- Інструментальні засоби та середовища програмування 79 женим за межами циклу, тобто при виході із нього. 38 В C # оператор foreach / in може застосовуватися не тільки до масивів, але і до будь-яких класів, що реалізують інтерфейс IEnumerable. 39 В Java ключове слово goto є, але воно забороняється компі- лятором до використання. 40 Використання процедур є важливими з наступних причин [23]: 1) економічність; 2) захист да- них; 3) абстракція; 4) приховування реалізації (implementation hiding); 5) можливість нарощува- ти програму (extensibility); 6) модульність; 7) робота з бібліо- теками. 1. Економічність: процедури дозволяють використовувати одну й ту ж частину коду декілька ра- зів. Процедури є конструкціями, що надають ім’я для такої части- ни коду. Самі частини коду нази- вають тілом процедури. 2. Захист даних (protection): в межах кожної но- вої процедури можна тепер орга- нізувати: новий діапазом видимо- сті для роботи з іменами; новий режим виділення пам’яті для да- них; нову локалізацію для оброб- ки помилок. 3. Абстракція: дескриптивні імена процедур, такі, наприклад, як sort, дозволяють абстрагува- тися від деталей реалізації та проектувати програму в термінах операцій предметної області чи задачі, що вирішується. Такий тип абстрагування отримав назву process abstraction. 4. Приховування реалізації, або encapsulation: алгоритм, ізольований в процедурі, може бути пізніше модифікованим, виз- вавши тим самим зміни лише в од- ному модулі процедури, а не в усій програмі. 5. Можливість нарощувати програму (extensibility): конце- пція процедур дозволяє нарощува- ти можливості мови за рахунок нарощення функціональних можли- востей операторів та вбудованих функцій. 6. Модульність (modularity): процедури дозволя- ють розбити велику програму на менші модулі, надаючи базис для модульного програмування (яке іноді також називали “structural programming”). 7. Робота з бібліотеками: стандартна колекція процедур мо- же бути організована у бібліоте- ку. Декларація процедури явно вводить до розгляду елементи або частини процедури: 1) ім’я процедури; 2) тіло процедури, яке складається з локальних деклара- цій та операторів мови; 3) формальні параметри, які є заготовленими місцями для під- становки в них актуальних зна- чень (що іноді називають аргуме- нтами); 4) необов’язковий опис типу значення, що повертається (result type). Історично так склалося, що процедуру, яка не повертає ні- якого значення, називали підпро- грамою (subroutine), а ту, що повертає певне значення, функці- єю (function). В мовах C / C++ / Java / C# в усіх випадках використовується термін функція. Тоді, коли функція не повертає ніякого значення, в цих мовах прийнято вказувати функцію, що повертає значення void (“пус- тий”). В Java / C# функції нази- ваються методами (класу). Сукупність імені функції та її формальних параметрів прийня- то називати прототипом функції (prototype or signature). Кожна функція має єдину “точку входу”, тобто місце, з Інструментальні засоби та середовища програмування 80 якого починається виконання опе- раторів функції — тіла функції. Кожне виконання тіла функції на- зивають активізацією функції. Функція називається рекурсивною (recursive), якщо вона може бути активізована із середини її вла- сного тіла, безпосередньо викли- каючи саму себе, або опосередко- вано, через виклики інших функ- цій. Обчислення в тілі функції, що викликала іншу, тимчасово припиняються протягом виконання функції, що була викликана; по завершенні її роботи контроль завжди повертається в тіло функ- ції, що викликала іншу. Це від- різняє підпрограми та функції від так званих ко- програм (co-routines). Якщо функція має параметри, розглядається декілька методів їх передачі: 1) за значенням (call-by- value); 2) за ссилкою (call-by- reference); 3) вхідні/вихідні параметри (call-by-value-result: in/out/ in-out parameters); 4) за ім’ям (call-by-name), яке на сьогодні має лише істори- чне значення і було подібне до макро-підстановки). 40a У мові C передача пара- метрів за ссилкою реалізована з використанням вказівників (pointer). 40b У мові C# передача функ- цій як параметрів реалізована з використанням ключового слова delegate. 41a У Java / C# немає глоба- льних функцій (див. також комен- тарі 11, 12 та 12а). 41 У мові C, оскільки вона не є мовою ООП, не підтримується class-member, inline та overloaded functions. 42 У Java / C# generic та template functions не підтриму- ється, у всякому разі у той спо- сіб, у який вони були задумані початково у C++. Нижче наводяться стислі ко- ментарі до табл. 3.1, пронумеро- вані цифрами від 1 до 13: Інструментальні засоби та середовища програмування 81 1 У різних мовах програму- вання класифікація типів даних проводиться по-різному, викорис- товуючи при цьому різну терміно- логію. Так, часто всі типи даних прийнято поділяти на прості та складні, або basic (fundamental) та derived, або primitive (embedded) та composed, чи scalar та aggregate, чи predefined та user-defined. В ANSI C концепція “type” поділя- ється на три підвиди: object types, function types та incomplete types. (Object type фактично означає value type, тобто це тип даних — змінних ве- личин чи констант, оскільки в даному контексті термін object є синонімом до слова “значення” (value), тобто значення змінної величини. Див. також коментар 17 до табл. 3.) У мовах Java / C# введена інша класифікація типів даних: value type та reference type. Змінні reference type фак- тично відповідають таким змін- ним, пам’ять для яких повинна виділятися динамічно. Тому змін- ні такого типу “мають діло” ско- ріше з адресою пам’яті, де їх значення буде зберігатися, а не з самим значенням. Проте вони відрізняються від звичайних вка- зівників мови C (pointers) тим, що “робота з адресою”, а тим са- мим і “динамічний характер” цих змінних, так би мовити, завуа- льовується, оскільки врешті-решт через ці адреси надається можли- вість працювати безпосередньо із значеннями величин цих змінних (подібно до reference type в мо- ві C++). Таблиця 3.1. Типи даних в мовах програмування С, С++, Java 2 та C# Типи даних (змінних величин) 1 С С++ Java C# 1 Primitive data types (i.e. which are not defined in terms of other types): – numeric (or arithmetic) supported directly by hardware: – byte (with modifiers signed or unsigned) – 2 – 2 1 4 1 – integer (a string of bits) with modifiers signed or unsigned: – short int (or ushort) 2 3 2 2 4 2 – int (or uint) 4 4 4 4 4 – long int (or ulong) 4 4 8 4 8 – float (4 bytes) 4 4 4 4 – double (8 bytes) 8 8 8 8 – long double (8 bytes, but depends on the compiler implementation) 8 8 – – – decimal (16 bytes; provides 28 significant digits) – – – 16 – char 1 1 2 2 – bool (boolean) – 5 + + + – void + + + + 2 Predefined reference types: – object – – + + – string (див. також нижче п. 3.3) – 6 – 6 + 6 + 6 3 User defined types, i.e. derived types 7: 3.1. Scalar types: – pointer + + – + 7a – reference (а також delegate type в C#) – + + + 3.2. Ordinal types: – enumerations, допомогає уникнути помилок, пов’язаних з кон- стантами 8 + + + 8a + – interval type – – – + 9 3.3. Aggregate types: – array type 10: – багатовимірні масиви: [ , ] + + + 10a + 10a – “зубчаті” масиви (jagged arrays): [ ][ ] – 11 – 11 + + – string type (див. також вище п. 2) – 6 – 6 + 6 + 6 – structure type + + – + 12 Інструментальні засоби та середовища програмування 82 В даній таблиці використо- вується систематизація, яка до- зволяє провести порівняння типів даних всіх чотирьох мов, тобто як С / С++, так і Java та C#. Тут цікаво також звернути увагу на те, що в Java та C# всі (базові) типи, включаючи value type, є похідними від класу object системної бібліотеки кла- сів. В цьому розумінні вони, строго кажучи, не є базовими (basic, fundamental або primitive). Проте з точки зору прикладних задач їх все ж доці- льно певною мірою вважати базо- вими типами. (Те, що всі такі “базові” типи тут є похідними від типу/класу object, забезпе- чує підняття рівня мови на сту- пінь вище, тобто далі від архі- тектури комп’ютера, що робить можливим більш легке перенесення (portability) програм на інші платформи.) Зауважимо також, що назва класу “object” є, на думку автора, трохи такою, що може “збити з пантелику”, нав’язуючи занадто строгі асоціації з тер- міном “об’єктно-орієнтоване про- грамування” (хоч, без сумніву, ця асоціація тут має місце). Та все ж замість назви “object” для цього базового класу може було б більш доцільно вжити назву “value type”, або “instance type”, або навіть просто “value” чи “instance”. В доказ достатньо лише розглянути декларацію цього класу, тобто його methods- members, і ми побачимо, що його конструктор та методи (public: Equals, GetHashCode, GetType, ReferenceEquals, ToString; protected: Finalize, Member- wiseClone) виконують звичайні, так би мовити, досить рутинні операції, які програмістам на С++ доводилось реалізовувати власноручно кожного разу, коли вони вводили до розгляду новий тип (type) даних — клас чи стру- ктуру і надалі мали працювати із динамічними значеннями (values, instances) цього типу. Тобто ні- якої магії в класі “object” не- має, проте така назва класу по- декуди приводить читачів- програмістів до конфузів, оскі- льки вона певною мірою розмиває границю між поняттями типу даних (введенного класом) та значенням змінної (об’єкта) цього типу (хоч і створеним динамічно та з посиланням на нього за допомогою адреси). Проте, звичайно, якби автори С# вибрали за назву цього базового класу термін, напри- клад, “value” (або навпаки — “class”) замість “object”, тоді замість терміну “object-oriented programming” прийшлось би вжива- ти термін “value-oriented pro- gramming” чи “class-oriented programming”, що навряд чи виз- вало б захоплення у прихильників ООП. 2 У мовах С / С++ немає вбу- дованого типу даних byte, але він може бути легко змодельова- ний з використанням unsigned char. 3 У відповідній клітинці таблиці вказано кількість байт, що відводиться для представлення (зберігання) вказаного типу да- них, наприклад 1 байт чи 8. 4 У Java немає типу беззна- кові цілі (unsigned int, short або long), а також знакового байта (sbyte). 5 У мові С немає вбудованого типу даних bool, замість нього використовується тип int; змінна цього типу має приймати тільки два значення: 0 та 1. 6 У мовах С / С++ / Java немає вбудованого типу даних string; він моделюється як масив симво- лів в С / С++ (і тоді для обробки такої змінної-string використо- вується вказівник на цей масив) або як class — в С++ / Java. У мові C# тип string підтримується Інструментальні засоби та середовища програмування 83 і як базовий тип (синонім систе- много класу), і як class. 7 При опису типів даних, заданих користувачем, звичайно розглядаються наступні питання: як зконструювати новий тип? (на- приклад: [ ] — для масивів, ( ) — для функцій, * — для вказівни- ків); які операції будуть нада- ватися для змінних такого типу (наприклад, операції доступу до членів структурованих даних: “.”; “->”; “ : : ”, тощо); як ці операції визначаються. 7a У мові C# тип pointer підтримується в режимі unsafety mode. 8 Декларація типу enum ви- значає ім’я для групи логічно пов’язаних один з одним констант цілого типу, виражених символь- ними назвами. Тип enum часто ви- користовується у випадку, коли потрібно організувати багаточи- сельний вибір серед кількості варіантів, наперед відомих на етапі компіляції. 8a У Java тип enum безпосе- редньо не підтримуються. Проте він може бути змодельованим з використанням класів. 9 У мові C# тип interval наближено можна змоделювати, ви- користовуючи тип enum, оскільки останній дозволяє задавати зна- чення констант і тим самим їх діапазон. 10 При описі масивів роз- глядають такі поняття, як type of array elements, subscripts (or indexes) та range checking. Зауважимо також, що іноді слово “масив” вживається в двох зна- ченнях: ім’я типу і назва об’єкта такого типу. Наприклад, у виразі “int A[2][10]” мови С ім’я маси- ву A вживається у двох значен- нях. 10a У мовах Java / C#, оскі- льки масиви є змінними типу reference, тобто динамічними змінними, то, як і для будь-яких динамічних змінних, їх дефініція складається із двох частин: ви- ділення пам’яті певного розміру та визначення/ініціалізація зна- чень елементів масиву у виділе- ній пам’яті. Проте синтаксис мо- ви дозволяє певні скорочення у запису. Так, наступні конструк- ції є еквівалентними: 1) float [] Arr = new float [3]; Arr [0] = 1.0; Arr [1] = 2.0; Arr [2] = 3.0; Таблиця 3.2. Типізовані константи в мовах програмування С, С++, Java та C# С С++ Java C# Типи констант Приклади: – numeric (supported directly by hardware): + + + + – integer with or without suffix l or L: and with or without suffix u or U + + – + – decimal 28 | 28uL 28 | 28uL 28 | 28L 28 | 28L – hexadecimal 0x1C | 0x1CuL 0x1C | 0x1CuL 0x1C | 0x1CL 0x1C | 0x1CL – octal 034 | 034uL 034 | 034uL 034 | 034L 034 | 034L – float (4 bytes) with suffix f or F 28.0 | 28.0F 28.0 | 28.0F 28.0 | 28.0F 28.0 | 28.0F – double (8 bytes) – unsuffixed constant 28.0 28.0 28.0 | 28.0D 28.0 | 28.0D – long double with suffix l or L 28.0, 28.0L 28.0, 28.0L – – – decimal (16 bytes) – – – 28.0 | 28.0M Інструментальні засоби та середовища програмування 84 2) float [] Arr = new float [3] {1.0; 2.0; 3.0}; 3) float [] Arr = {1.0; 2.0; 3.0}. 11 У мовах С / С++ “зубчаті” (jagged) масиви безпосередньо не підтримуються. Проте їх можна змоделювати, використовуючи ма- сиви вказівників та динамічне виділення пам’яті для їх елемен- тів. 12 Хоч структури і класи ба- гато в чому подібні — structs можуть реалізовувати інтерфейси та можуть мати такі самі види членів, як і класи, — потрібно пам’ятати, що в мові C# структу- ри є value type, а класи — reference type, звідки і випли- ває відповідна відмінність у їх реалізації. Наслідування також не підтримується для структур. 13 Більш детально про класи в мовах C++ / Java / C# дивись ниж- че, в наступному розділі статті. Як бачимо, наведений пере- лік імперативних концепцій та конструкцій мов дозволяє провес- ти їх критичну оцінку та порів- няльний аналіз, що, без сумніву, має бути корисним для кращого володіння певною мовою програму- вання. Крім того, він може бути корисним для тих, хто у своїй практиці програмування, в силу певних причин, володіє лише де- якою підмножиною можливостей мо- ви. У цьому випадку розуміння решти конструкцій та концепцій мови може надати негаданих пере- ваг таким практикам. У сучасній літературі та в Internet-джерелах (див., напри- клад, MSDN) починають наводитися порівняльні таблиці конструкцій для ряду нових мов, таких, як C, C++, Visual Basic, Java, JavaScript, Visual FoxPro, C#, проте там такі порівняння прово- дяться в основному з позицій огляду граматичних (в основному — синтаксичних) конструкцій мов, тобто з позицій, коли мова пред- ставляється так би мовити з точ- ки зору компілятора мови, але не так, як вона повинна представля- тися з урахуванням того, що ця мова є інструментом опису при- кладної задачі обробки інформа- ції за допомогою комп’ютера, як програмно керованої системи. Тобто, у відомих з літератури порівняннях наводяться окремі таблиці для операторів керування (control flow operators), типів даних, виразів чи інших констру- кцій, але не наводиться упоряд- коване подання та аналіз системи концепцій та конструкцій мов, як це зроблено в даній статті. Зауважимо також, що в офі- ційних специфікаціях цих мов (див. [29, 30]) порядок викла- дення набору конструкцій навіть для таких споріднених мов, як Java та C#, є суттєво різним. Це наводить на думку, що на сього- дні все ще не існує загально прийнятого порядку розгляду пе- реліку конструкцій мов програму- вання, і означає, в свою чергу, що ця проблема все ще не є оста- точно вирішеною. В той же час у ряді випадків, особливо при ви- вченні нової мови, доцільно мати такий упорядкований набір конс- трукцій мови. 3. Еволюція об’єктно- орієнтованих конструкцій мов програмування Як ми могли побачити з по- переднього розділу, концепції імперативного програмування на- дають багаті можливості по про- грамному керуванню комп’ютером для вирішення широкого кола при- кладних задач. Проводячи деком- позицію задачі на менш складні функціональні модулі, можна створювати програми, що вирішу- ють складні задачі. В той же час підхід імперативного, функціона- льно-модульного програмування не надає ефективних засобів для об- Інструментальні засоби та середовища програмування 85 робки складних даних. Серед та- ких засобів, в першу чергу, не- обхідним є створення типів да- них, визначених користувачем, — user defined types, а також змінних таких типів, за допомо- гою яких (типів та відповідних їм змінних) можна було б набага- то легше моделювати складну при- кладну задачу, ніж використову- вати вбудовані в мову програму- вання типи. В таких сферах засто- сування, як, наприклад, інформа- ційні системи для бізнесу, сис- теми "штучного інтелекту" та де- які інші, складність програмної системи в основному пов’язана з даними, а не алгоритмами їх об- числення. Тут дані мають складну структуру і характеризуються складними взаємозв’язками між їх компонентами. Концепція user defined types була розвинута далі й при- вела до поняття "абстрактних ти- пів даних" (ADT), тобто таких, які, по-перше, визначені корис- тувачем, а по-друге, для яких користувач встанавив також набір операцій чи функцій обробки змінних такого типу. (Нагадаємо, що, за означенням, тип даних — це множина значень та операції, визначені над нею.) Причому без- посередній доступ до компонентів таких типів тепер забороняється, і він стає можливим лише за до- помогою наперед заданих функцій. Деталі реалізації самих даних виявляються схованими від корис- тувача (data hiding); це дозво- ляє змінювати внутрішнє предста- влення даних без негативного впливу на модулі, що користують- ся такими даними (data encapsulation; інкапсулювати ча- стину алгоритму означає локалі- зувати її в одній секції програ- ми). Опис такого абстрактного типу даних може бути виконано як окремий модуль або компонент. Тоді програма проектується так, щоб вона складалась із модулів, які репрезентують абстрактні ти- пи даних, тобто модель даних по- чаткової задачі. Звернемо ще раз увагу на те, що механізм абстрактних ти- пів даних був націлений на вирі- шення проблеми складності не ал- горитмів обробки даних, а саме структур даних в прикладних за- дачах. Наступна проблема складнос- ті вже не вирішувалася ефективно навіть з використанням абстракт- них типів даних. Виявилося, що існує велика кількість приклад- них задач, в яких потрібно обро- бляти певну кількість об’єктів (змінних) абстрактного типу да- них при виконанні додаткових умов, таких, наприклад, як на- ступні: об’єкти повинні створю- ватися та знищуватися динамічно; можуть існувати об’єкти, що ма- ють підмножину характеристик іс- нуючих об’єктів та певні власні відмінні риси; повинна забезпе- чуватись можливість різного виду ініціалізації значень об’єктів; при модуляризації програми на абстрактні типи даних потрібно забезпечити вирішення проблем "доступу" (scope) до компонен- тів, "лінковки" функцій- операцій, що оброблюють дані, тощо. Для вирішення такого роду проблем у мовах програмування була запропонована концепція "клас", а програмування з вико- ристанням класів та об’єктів (екземплярів, змінних) заданого класу стали називати об’єктно- орієнтованим програмуванням (ООП). Таким чином, відбулося зміщення акценту уваги від process-oriented до data- oriented, а потім і до object- oriented програмування. Такий розвиток відбувся як розвиток концепції “абстрагування” обчис- лень, а точніше — абстрагування Інструментальні засоби та середовища програмування 86 послідовності програмного керу- вання. На шляху такого розвитку були створенні такі концепції абстрагування: 1) складний оператор та блок (compound statement and block) — для абстрагування послідовності обчислень та пов’язаних з ним де- кларацій змінних; 2) функція (a function) — абстрагування процесу обчислень (process abstraction); 3) абстрактний тип даних (abstract data type, ADT) — абс- трагування реалізації форматів даних; 4) клас (class) в Simula 67. В табл. 4. наводиться осно- вний перелік об’єктно- орієнтованих конструкцій мов програмування та їх наявність в історичних попередниках мови С++. Більш детальний розгляд ООП концепцій та порівняння їх реа- лізацій в мовах C++ / Java / C# наводиться нижче, в табл. 5. Нижче наводять стислі ко- ментарі до табл. 5, пронумерова- ні цифрами від 1 до 13: 1 Згідно означення, абстра- кція даних є специфікацією: 1) множини об’єктів даних; 2) мно- жини абстрактних операцій над цими об’єктами; 3) інкапсуляція цього всього у такий спосіб, що користувач но- вого типу не може маніпулювати об’єктами даних напряму, а лише використовувати введені опера- ції. Як бачимо, абстрагування даних означає те, що ми не звер- таємо уваги на деталі реалізації даних в новому типі даних, нас цікавить більш абстрактний (менш детальний) рівень їх використан- ня, тобто те, як використовувати ці данні, іншими словами, як проводити над цими даними опера- ції (і нас не хвилює те, як ці операції були реалізовані). 2 У мовах С++ / Java / С# члени класу можуть включати: 1) константи (тобто значення, що можуть бути вичислені на етапі компіляції); 2) змінні, які тут називаються полями (fields): static або non-static з або без атрибуту read-only в Java / С#); 3) функції, які тут називаються методами (methods); 4) операто- ри (члени, що визначають зна- чення виразу-оператора (expres- sion operator), який може бути застосованим до екземпляру кла- су, тобто змінної класового ти- пу; 5) конструктори екземпляру класу (instance constructors), тобто члени, що реалізують дії, необхідні для ініціалізації ек- земплярів класу; 6) деструктори (за винятком мови Java; в C# деструктори екземплярів класу викликаються автоматично при “збиранні сміття” — garbage collection); 7) вкладені декла- рації типів (nested types declarations). 2a У С# члени класу можуть, крім того, включати: 8) статич- ний конструктор, тобто член, що реалізує дії, необхідні для іні- ціалізації класу як типу даних; 9) властивості (properties), тобто члени, що забезпечують до- Таблиця 4. Об’єктно-орієнтовані конструкції мови С++, їх попере- дники та аналогії в інших мовах Об’єктно-орієнтовані конструкції мови С++ SIMULA- 67 1964, 67 Modula, Euclid 1977 CLU 1973 ADA (1975, 83) C++ 1982 -1985 SMALL- TALK- 72 / 80 1. User defined data types, data abstraction, and encapsulation class module cluste r package clas s obje ct 2. Objects creation and initialization + + + + + + 3. Inheritance + + – – + + 4. Dynamical binding and polymorphism – + – – + + 5. Parameterized types – – + + + + 6. Exception handling – – + + + + Інструментальні засоби та середовища програмування 87 ступ до даних об’єкта або класу; 10) індексер (indexer), тобто член, що дозволяє організувати індексацію об’єкта у такий же спосіб, як це робиться у маси- вах; 11) події (events), тобто члени, що дозволяють передавати повідомлення (notifications) для об’єкта або класу. Методи, влас- тивості та індексери можуть бути віртуальними (virtual); це озна- чає, що їх реалізація може бути переписана у похідному класі. Клас може вказувати на те, що не всі його методи імплементовані, і він запроектований бути лише базовим класом для інших класів; у цьому випадку використовується модифікатор abstract. Такий клас називається абстрактним (abstract class). Абстрактний клас може також мати абстрактні методи (abstract members), тобто члени, які мають бути реалізова- ними у похідному класі (див. та- кож табл. 5, п. 4). 2b У С# параметри функцій- методів класу можуть мати out, params (parameter array) та ref модифікатори. 3 У Java змінні можуть бути позначені модифікатором transient, щоб вказати на те, що вони не будуть зберігатися на диск, методами, реалізованими системним класом object. 4 Користувачеві не потрібно більше знати сховану реалізацію членів класу. Навіть більше — відтепер навіть не дозволяється безпосередньо використовувати сховані (hidden) дані. 4a У С# існує два додаткових типи доступу: internal та protected internal. 4b У С#, крім того, існує спеціальна конструкція, яка реа- лізує функції-властивості (property-functions). 5 Оскільки об’єкти вводять- ся в програму шляхом опису їх імен (так само, як і імена змін- них вбудованих у мову типів), то на імена об’єктів класу поширю- ється все те, що було сказано вище стосовно імен змінних — див. табл. 3. Інструментальні засоби та середовища програмування 88 Таблиця 5. Базові концепції ООП в С++, Java 2 та C# ООП конструкції мов програмування С++ Java C# 1 Data Abstraction 1: – class as a new data type: – is a user-defined type + + + – class members, i.e. a collection of logically related things (data aggregation) 2: – class data (fields), static versus class instance data; final (constant) fields + + 3 + 2a – class functions (methods) + + + 2b – others: properties, indexers, events, etc. – – + 2a – nested classes (as a nested data types); див. також in- heritance + + + – class as a new type of scope – class scope: – the class scope is more powerful than block, function or file scope + + + – there is no need to have the global scope any more – + + – class as a data hiding and access control technique 4: – private, public, protected; internal, protected internal + + + 4a – data access functions (so-called "properties", see also below) + + + 4b – friends + – – – class as an encapsulation mechanism (to gain the modularisa- tion ): – is an ADT + + + – is a compilation unit – + + – package/namespace as a file and as a compilation unit – + + 2 Objects creation and initialisation 5: – constructors and initialisation: – instance constructors + + + – static constructor – – 5a + – destructor + – 5b + – multiple instances of class data but single instance of class methods + + + – constant objects and const member functions treatment + + + 3 Inheritance, i.e. the extension of the basic class 6: – single inheritance + + 7 + 7 – multiple inheritance + – – – data access: public, private, protected, internal, protected internal + + 8 + 8 – base class, derived classes, abstract class, member classes, nested classes 9 + + + – final / sealed class – + + – scope resolution operator “: :” + – – – the class hierarchy common for all classes; the ultimate base class ”object” – + + 4 Overridden class methods: – statically and for the same class (overloading) + + + – dynamically and for the classes of different level of class hierarchy: – polymorphism (overriding); virtual functions; delegates + + 10 + – abstract classes 11; final methods; (див. також нижче) + + + 5 Methods of particular type or special purpose 12: – constructors ( see also above) + + + – destructor ( see also above) + – 5b + – property, indexer, event constructs – – + – final methods, i.e. can not be hidden or overridden; (див. – + + Інструментальні засоби та середовища програмування 89 Конструктор — це функція, яка не повертає ніякого значен- ня; вона також не може бути ви- кликана напряму з програми кори- стувача. Якщо клас використову- ється лише для абстракції та ор- ганізації агрегації даних, то немає великої необхідності ство- рювати конструктор. Проте він потрібен, якщо клас включає в себе динамічні дані. Клас може бути спроектова- ним таким чином, щоб заборонити створення екземплярів класу в будь-якій частині тексту програ- ми, що не входить в опис самого класу. У цьому випадку необхідно об’явити хоча б один конструк- тор, щоб запобігти створення не- явного конструктора, а також об’явити всю решту конструкторів з модифікатором private. Ініціалізація виконується для об’єктів класу, об’єктів- членів класу та (під-)об’єктів базового класу. 5a У Java безпосередньо не- має конструкції “static constructor”, але є механізм ініціалізації даних класу (саме класу, а не об’єкта класу), до множини яких входять члени кла- су, об’явлені з модифікатором static. Статичні ініціалізатори (static initializers) — це блоки коду, що використовуються, щоб допомогти проініціалізувати клас, коли він вперше завантажу- ється в пам’ять. 5b У Java безпосередньо не- має конструкції “destructor”, але є механізм finalize. 6 Зробимо деякі зауваження стосовно термінології. Для по- значення базового класу (base class) в Java вживається термін "super-class", на відміну від С++ та С#. Для позначення похід- ного класу (derived class) в Java вживається термін "subclass". Термін “subclass” в Java, на думку автора, доцільні- ше було б замінити на термін “supra-class”, тобто “надклас”. У той же час при утворенні похі- дного класу в Java використову- ється ключове слово “extended”, що правильно підкреслює відно- шення “включеності–належності” елементів базового класу до мно- жини елементів похідного класу. Зауважимо також, що C++ слідує об’єктно-орієнтованому підходу, введеному в мові Simula, а не Smalltalk. В Smalltalk весь набір методів об’єкта називають message protocol. Це вводить в терміно- логічне протиріччя із викорис- танням слова message в інших контекстах, наприклад при обміні повідомленнями між модулями опе- раційної системи і, як наслідок, при програмуванні у MS Visual C++ з використанням бібліотеки класів MFC. В той же час в про- грамах, написаних на ANSI C для Windows, використовується також термін клас, який так само ні якого відношення не має до того значення цого терміну, яке вико- ристовується в С++ при ООП. (Для більш детального знайомства з деякими особливостями ООП з ви- користанням С++, а також про мо- жливі пастки, що виникають при цьому, можна ознайомитися в ро- боті [25].) 7 Усі базові класи в Java та C# походять від системного класу object. 8 У Java ключове слово protected створює члени класу, які можуть бути доступні тільки для підкласів (sub-classes), що розташовані зовні даного пакету (package), а також з будь-якого місця, що знаходиться в середені даного пакету. В цьому відмін- ність protected членів в Java та C++. 9 На відміну від С++, де класовий тип є типом, об’явленим з global або file scope, в Java та C# клас може Інструментальні засоби та середовища програмування 90 бути об’явленим як global class, local class, static (sic!) class. Клас-член (member class) — це такий клас, декла- рація якого безпосередньо роз- ташована у даному класі. Вкла- дений клас (nested class) це такий клас, декларація якого розташована у будь-якому місті, включаючи підкласи даного кла- су. Нестатичні вкладені класи називають також внутрішніми (inner). Тобто опис member кла- сів розміщується в області де- кларації класу (в header-file у випадку C++), а опис nested класів може розміщуватися в ті- лі функцій-членів класу, чи у деякому місті базових класів. 10 Якщо два методи одного класу (неважливо при цьому, чи вони об’явлені в тому самому класі, чи в різних наслідуваних класах однієї класової ієрархії) мають однакове ім’я, але різну сигнатуру, такі методи назива- ються перевантаженими (overloaded). У випадку переван- таження (overloading) функції базового класу (base class) фун- кцією похідного класу (derived class), його називають доміную- чим перевантаженням (overriding). У Java, якщо клас декларує, наприклад, два методи з однаковим ім’ям і похідний клас (subclass) перевантажує (overrides) одну з них, похідний клас (subclass) також наслідує ще другу функцію. У цьому відно- шенні Java відрізняється від C++. Тобто похідний клас в Java буде мати дві функції, а в C++ — одну! (Хоча друга функція завжди може бути викликана через вказі- вник на об’єкт базового класу.) З поняттям overriding тісно пов’язане поняття поліморфізму (polymorphism), тобто динамічно- го зв’язування (dynamical binding) функцій, які є переван- таженими (overridden), та пере- дачі цих функції як параметрів в іншу функцію за рахунок викорис- тання вказівника на функцію. 11 Абстрактні методи — це функції, які об’явлені, але не реалізовані в даному класі. 12 Крім функції спеціального призначення в класах вводиться також спеціальна конструкція this. Ключове слово this є вка- зівником на область пам’яті, де розташовані дані об’єкта і на яку функції-члени класу мають область доступу. Цей вказівник завжди (невидимо) передається як параметр до функції. Він віді- грає таку саму роль, як і вказі- вник на структуру struct, що пе- редається параметром до функції. 13 Декларація інтерфейсу вводить новий посилальний тип; його членами є класи, інші ін- терфейси, константи та абстракт- ні методи. Інтерфейси можуть та- кож містити властивості, індек- сери та події. Інтерфейс може бути безпосереднім розширеням (extension) одного чи декількох інших інтерфейсів і таким чином наслідувати зміст інших інтер- фейсів. Всі члени інтерфейсу не- явно мають доступ public. Реалі- зація інтерфейсу проводиться в класі, в декларації якого вико- ристовується ключове слово implements, що указує далі на інтерфейс, який має бути реалі- зованим цим класом. Деякі деталі, не пов’язані з ООП-концепціями мов програмуван- ня, такі, наприклад, як конструк- ція native, synchronized тощо в мові Java, в даній статті не роз- глядаються, оскільки скоріше від- носяться до проблем, пов’язаних з організацією взаємодії прикладної програми з операційною системою та вирішенням інших проблем тако- го роду. 4. Критичний аналіз еволюції ба- зових конструкцій мов Як зазначалося вже вище (в п. 2), у сучасній літературі та Інструментальні засоби та середовища програмування 91 в Internet-джерелах починають наводитися порівняльні таблиці конструкцій для ряду нових мов, проте такі порівняння проводять- ся в основному з позицій огляду граматичних конструкцій мов і не упорядковане подання та аналіз системи концепцій та конструкцій мов. Систематизоване подання дозволяє провести аналіз еволю- ції базових конструкцій мов. Для проведення такого ана- лізу достатньо прослідкувати ко- жний рядок табл. 3, 3.1, 3.2 та 5, та побачити, чи еволюціонува- ла відповідна конструк- ція/концепція мови (представлена у рядку таблиці) від мови С до мови С++ і потім далі до Java та C#, а чи вона “відмерла” — її доцільність була заперечена практикою. Так, наприклад, можна поба- чити, що конструкція header files була відхилена як непотрі- бна в мовах Java та C#. Проте ми пам’ятаємо, що ця конструкція вважалась у свій час досить про- гресивною і однією з відмінних рис C та C++ у порівнянні їх, наприклад, з Pascal — свого роду конкурентом С на той час. Інший приклад — тип даних enum. Конструкція, яка була сво- го часу введена в С, а потім і в С++ та вважалась досить елегант- ним засобом мови, раптом була відкинута як непотрібна в мові Java. В той же час в мові C#, що є, як ми бачимо, дуже подібною до Java, тип даних enum знову отримав право на життя! Те саме можна сказати ще про пару конструкцій цих мов програмування — label та “опера- тор з поганою репутацією” goto. Іншою особливістю еволюцій мов, природно, є розширення на- бору їх концепцій та конструк- цій, а також “остаточне” позбав- лення від (наслідування) конс- трукцій, що були чи виявилися невдалими в мові С чи С++. Так, наприклад, типи даних union та bit field не підтримуються біль- ше ні в Java, ні в C#. Конструк- ція template була введена в C++ як ефективний засіб параметриза- ції класів та функцій, проте по- тім — в Java та C# — від неї відмовилися. Те саме стосується конструкції typedef — з введен- ням та розвитком концепції кла- сів в Java та C# потреба в typedef відпала повністю. Окремої уваги також заслу- говує поняття вказівника (pointer) в мові С та його пода- льша еволюція. В С pointers були чи не найвідмітнішою рисою мови. Вони надавали їй гнучкості та ефективності, що вплинуло на по- ширеність використання мови як потужного інструмента розробки не тільки системних, але і при- кладних задач. У той же час конструкція pointer мала певні недоліки. За словами відомого спеціаліста в області теорії мов програмування Ч. Хоара, “їх інт- родукція в мови програмування високого рівня була кроком на- зад, від якого ми можемо ніколи не отямитися” (1973). Невдалим в мові C також слід вважати синта- ксис для опису pointers: викори- стання символу “*” приводило до неоднозначності, оскільки він використовувався також для по- значення операції множення, тоб- то його вживання було контекстно залежним. Всі переваги та недо- ліки pointers були повністю збе- режені в мові С++. В той же час в нових мовах Java та C# конс- трукція pointers відсутня. (В C# дозволяється працювати з pointers у так званому “не не- безпечному режимі” — unsafe mode.) Ось такий яскравий при- клад “природного відбору” в ево- люції мов програмування. Інструментальні засоби та середовища програмування 92 Такі приклади можна продов- жувати. Читач запрошується про- робити досліди самостійно. Ще одним джерелом чи, так би мовити, рушійною силою про- гресу у розвитку мов програму- вання були проблеми програмної інженерії (software engineering) та, зокрема, технологій побудови програмних компонентів, які мож- на було б повторно використову- вати (reusable components) і які надавали б можливість їх взаємо- дії (component interoperability). Потреба у ви- рішенні такого типу проблем вре- шті-решт відобразилася в конс- трукціях нових мов програмуван- ня. Проте на шляху цієї еволюції була спочатку розробка так зва- ної моделі компонентних об’єктів — COM. Згідно COM, зокрема, для того щоб об’єкти могли взаємоді- яти один з одним, були компонен- тами один одного (компонентними об’єктами), всі вони повинні ма- ти деяку “спільну базу”, “спіль- ний набір правил взаємодії”. Та- ка спільна основа полягає в на- борі положень: – програмний об’єкт пови- нен бути об’єктом у розумінні об’єктно-орієнтованого програму- вання, тобто мати структуру да- них та набір методів, що визна- чають перелік того, що саме може робити об’єкт; – доступ до даних об’єкта повинен відбуватися тільки через його методи (наприклад, Say/Get); логічно пов’язані один з одним методи повинні утворюва- ти так званий інтерфейс (іншими словами, частина методів об’єкта об’єднується в групу і така гру- па називається інтерфейсом об’єкта); – можна розглядати інтерфейс як окремий абстрактний клас, у якого не має власних да- них і є лише набір чисто віртуальних функцій, що деклару- ють набір функцій методів-членів компонентного об’єкта, ре- алізація цих функцій знаходиться в тілі самого об’єкта; – з метою забезпечення можливості повторного викори- стання компонентів інтерфейси повинні мати механізм, подібний спадковості класів (так звані containment/delegation та agre- gation); – після того як інтерфейс був опублікований і почав десь працювати, його не можна змінювати, добавлення нової чи зміна існуючої функціональності потребує визначення повністю но- вого інтерфейсу (так розв’язується проблема керування новими версіями програмного про- дукту — versioning problem). Як бачимо, деякі з вимог COM знайшли своє відображення у нових конструкціях мов, таких, як інтерфейс (Java та C#), properties (C#) тощо. Висновок Проведений порівняльний аналіз базових концепцій сучас- них мов імперативного та об’єктно-орієнтованого програму- вання та їх еволюції може надати читачеві додаткову інформацію для кращого розуміння мов та пе- вну теоретичну підготовку до сприймання нових ідей з теорії мов програмування, що можуть з’явитися у майбутньому. Запро- поновані таблиці, крім, так би мовити, "теоретичної цінності", дають також практичну користь: вони можуть бути використані на практиці при вивченні мов про- грамування С, С++, Java 2 та C#. Для цього автор рекомендує, за його прикладом, створити певний репозитарій зразків (sample) програм на основі табл. 3–5. Та- кі програми мають бути невелич- кими за розміром і реалізовувати Інструментальні засоби та середовища програмування 93 лише одну або ряд споріднених концепцій із вказаного в табли- цях набору. Вивчення мови про- грамування за такою схемою при- дасть певної систематизації знань конкретної мови програму- вання, неминуче забезпечить їх повноту, що все разом покращить розуміння матеріалу і підвищить якість його знань. Табл. 3–5 мо- жуть бути також використані при формулюванні запитань для конт- ролю цих знань. 1. Blaauw G., Brooks F.P. Computer ar- chitecture: concepts and evolution. — Addison Wesley Longman, Inc., 1997. — 1213 p. 2. Knuth D.E., Pardo L.T. The early development of programming lan- guages // A history of computing in the twentieth Century: A collection of essays. — Academic Press. 1980. — P. 197–273. 3. Sammet J.E. Some approaches to, and illustrations of, programming lan- guage history // IEEE Annals of the History of Computing J. 1991. — Vol. 13. — N 1. — P. 33–50. 4. History of programming languages: Proc. of the History of programming languages Conference, Los Angeles, CA, June 1–3, 1978 / Ed. By Wexel- blat R.L. — Academic Press, 1981. — 758 p. 5. ADA: past, present, future; Jean Ichbiah // Commun. ACM. — 1984, 27, 10 Oct. — P. 990–997. 6. Wirth Niklaus. From programming language design to computer con- struction // Ibid. — 1985, 28, 2 Feb. — P. 160–164. 7. Sammet J.E. Why Ada is not just an- other programming language // Ibid. — 1986, 29, 9 Sep. — P. 722–732. 8. Cohen J. A view of the origins and development of Prolog // Ibid. — 1988, 31, 1 Jan. — P. 26–36. 9. Kowalski R.A. The early years of logic programming // Ibid. — 1988, 31, 1 Jan. — P. 38–43. 10. Robinson J.A. Logic and logic pro- gramming // Ibid. — 1992, 35, 3 Mar. — P. 40–65. 11. Tichy W.F. Programming-in-the- large: past, present, and future // Proc. of the 14th Intern. confer- ence on Software engineering, 1992. — P. 362–367. 12. Kay A.C. The early history of Smalltalk // The 2 ACM SIGPLAN conf. on History of programming languages, 1993. — P. 69–95. 13. Guy L.S., Gabriel R.P. The evolu- tion of Lisp // Ibid. — 1993. — P. 231–270. 14. Liskov B. A history of CLU // Ibid. — 1993. — P. 133–147. 15. Whitaker W.A. Ada — the project: the DoD high order language working group // Ibid. — 1993. — P. 299– 331. 16. Lindsey C.H. A history of ALGOL 68 // Ibid. — 1993. — P. 97–132. 17. Ritchie D.M. The development of the C language // Ibid. — 1993. — P. 201–208. 18. Stroustrup B. A history of C++: 1979-1991 // Ibid. — 1993. — P. 271–297. 19. Колодницький М.М. Технічне та про- грамне забезпечення комп’ютерних інформаційних технологій. — Жито- мир: ЖIТI, 1995. — 231 c. 20. Nicholls J.E. The structure and de- sign of programming languages. Reading, Mass. — Addison-Wesley, 1975. — 572 p. 21. Horowitz E. Fundamentals of pro- gramming languages. Rockville, Md.: 2nd ed. / Computer Science Press: 1984. — 446 p. 22. Pratt T. Programming languages: De- sign and implementation. — NJ: Prentice Hall, 1996. — 654 p. 23. Sethi R. Programming languages: Concepts and constructs. — Addison- Wesley, 1996. —640 p. 24. Sebesta R.W. Concepts of Programming Languages. — Addison Wesley, 2002. — 698 p. 25. Колодницький М.М. Аналіз парадигми ООП мовою С++. ("Що таке класи?") // Вісник ЖІТІ: Технічні науки. 2002. — № 21. — С. 120–124. 26. American national standard for in- formation systems: Programming lan- guage-C. ANSI 3.159-1989. Approved December 14, 1989 by the American National Standards Institute / Ed. by the Computer and Business Equip- ment Manufacturers Association, the Secretariat, and the American Na- tional Standards Institute. — New York: American National Standards Institute, 1990. — 119 p. 27. Kernighan B.W., Ritchie D.M. The C programming language: 2nd. ed. — N.J.: Prentice Hall, 1988. — 272 p. Інструментальні засоби та середовища програмування 94 28. Stroustrup B. The C++ programming language. Special ed. Reading, Mass. — Addison-Wesley, 2000. — 1019 p. 29. The Java™ Language Specification. Second Edition / James Gosling, Bill Joy, Guy Steele and Gilad Bracha. — Addison-Wesley. 1996. — 532 p. 30. C# Language Specification. Version 0.28, 5/7/2001. Отримано 27.05.04 Про автора Колодницький Микола Михайлович професор Місце роботи автора: Natural Interactive Systems Laboratory University of Southern Denmark Campusvej 55, DK-5230 Odense M Denmark
id nasplib_isofts_kiev_ua-123456789-1348
institution Digital Library of Periodicals of National Academy of Sciences of Ukraine
issn 1727-4907
language Ukrainian
last_indexed 2025-12-07T18:41:07Z
publishDate 2004
publisher Інститут програмних систем НАН України
record_format dspace
spelling Колодницький, М.М.
2008-07-25T16:10:15Z
2008-07-25T16:10:15Z
2004
Еволюція та "природний відбір" базових концепцій мов програмуван-ня: на прикладах мов C, C++, Java та C# / М.М. Колодницький // Проблеми програмування. — 2004. — N 4. — С. 63-94. — Бібліогр.: 30 назв. — укр.
1727-4907
https://nasplib.isofts.kiev.ua/handle/123456789/1348
681.3.06
Коротко нагадуються деякі важливі історичні події, що мали суттєвий вплив на формування концепцій сучасних мов програмування загального призначення. Розглядається набір фундаментальних конструкцій та концепцій, які є свого роду будівельними цеглинками вказаних у назві чотирьох мов. Пропонується систематизація такого набору, яка показує, як відображаються компоненти архітектури комп’ютера у відповідні концепції мов програмування. Дану систематизацію зручно взяти за основу для проведення порівняльного аналізу цих мов. Наводяться систематизовані порівняльні таблиці базових імперативних концепцій чотирьох мов, а також порівнюються реалізації об’єктно-орієнтованих конструкцій в мовах C++, Java 2 та C#. На основі таких матеріалів проводиться аналіз еволюції базових концепцій цих мов.
Кратко напоминаются некоторые важные исторические события, оказавшие существенное влияние на формирование концепций современных языков программирования общего назначения. Рассматривается набор фундаментальных конструкций и концепций, которые есть своего рода строительными блоками указанных в названии четырех языков. Предлагается систематизация такого набора, которая показывает, как отображаются компоненты архитектуры компьютера в соответствующие концепции языков программирования. Данную систематизацию удобно взять за основу для проведения сравнительного анализа этих языков. Приводятся систематизированные сравнительные таблицы базовых императивных концепций четырех языков, а также сравниваются реализации объектно-ориентированных конструкций в языках C++,
The paper starts with a brief reminder of those important milestones in the history of programming languages (PL), which had a significant impact on the modern concepts of general purpose PL. It is followed by the consideration of the fundamental constructions and concepts, which are sort of building blocks of the languages discussed. Along the consideration path, a systematic presentation of the concepts is introduced. The systematic presentation displays how the computer architecture constituents are being mapped into corresponding programming language concepts. The systematic presentation is, then, taken as a basis for the comparative study of the languages. The result of the study is presented in the imperative language fundamental concepts comparative tables for four languages along with the comparative analysis of object-oriented constructions implementation in C++, Java 2 and C#. The result presented is a kind of input for the evaluation of the evolution of the programming languages fundamental concepts performed in the last section of the paper.
uk
Інститут програмних систем НАН України
Інструментальні засоби і середовища програмування
Еволюція та "природний відбір" базових концепцій мов програмування: на прикладах мов C, C++, Java та C#
Эволюция и "естественный отбор" базо-вых концепций языков программирования: на примерах C, C++, JAVA 2 и C#
The Programming Languages Fundamental Concepts: an Evaluation of the Evolution on the C, C++, Java and C# Use Cases
Article
published earlier
spellingShingle Еволюція та "природний відбір" базових концепцій мов програмування: на прикладах мов C, C++, Java та C#
Колодницький, М.М.
Інструментальні засоби і середовища програмування
title Еволюція та "природний відбір" базових концепцій мов програмування: на прикладах мов C, C++, Java та C#
title_alt Эволюция и "естественный отбор" базо-вых концепций языков программирования: на примерах C, C++, JAVA 2 и C#
The Programming Languages Fundamental Concepts: an Evaluation of the Evolution on the C, C++, Java and C# Use Cases
title_full Еволюція та "природний відбір" базових концепцій мов програмування: на прикладах мов C, C++, Java та C#
title_fullStr Еволюція та "природний відбір" базових концепцій мов програмування: на прикладах мов C, C++, Java та C#
title_full_unstemmed Еволюція та "природний відбір" базових концепцій мов програмування: на прикладах мов C, C++, Java та C#
title_short Еволюція та "природний відбір" базових концепцій мов програмування: на прикладах мов C, C++, Java та C#
title_sort еволюція та "природний відбір" базових концепцій мов програмування: на прикладах мов c, c++, java та c#
topic Інструментальні засоби і середовища програмування
topic_facet Інструментальні засоби і середовища програмування
url https://nasplib.isofts.kiev.ua/handle/123456789/1348
work_keys_str_mv AT kolodnicʹkiimm evolûcíâtaprirodniivídbírbazovihkoncepcíimovprogramuvannânaprikladahmovccjavatac
AT kolodnicʹkiimm évolûciâiestestvennyiotborbazovyhkoncepciiâzykovprogrammirovaniânaprimerahccjava2ic
AT kolodnicʹkiimm theprogramminglanguagesfundamentalconceptsanevaluationoftheevolutionontheccjavaandcusecases