(Оригінал цієї статті знаходиться тут.)
1 грудня 2020 р. Москва, Росія.
Автор: Єгор Бугаєнко.
Як ви створюєте об’єкти у своїй об’єктно-орієнтованій мові? Можемо взяти звичні C++, Java або C#. Спочатку ви визначаєте клас, а тоді створюєте його примірник. Перший крок відомий як абстракція, другий — як інстанціація. Подібна пара дій є і в функціональному програмуванні: визначення функції є абстракцією, а виклик її з певними аргументами — застосуванням, аплікацією. Тоді таке запитання: чому ООП потребує класів і об’єктів, а ФП обходиться самими тільки функціями?
(Image :copyright: The Irishman (2019) by Martin Scorsese)
Таким є абстрактний об’єкт в EO:
[id db] > book
db.query > title
"SELECT title FROM book WHERE id=?"
id
Ім’я об’єкту — book
. Він має три атрибути: id
, db
і title
. Перші два є “вільними”. Вони поки що не прив’язані ні до яких об’єктів. Третій, title
, вже прив’язаний до копії об’єкту db.query
. Об’єкт book
є абстрактний, бо має вільні атрибути — він недостатньо конкретний, щоб відповідати якійсь конкретній сутності з реального світу.
Конструкція db.query
бере абстрактний об’єкт query
з об’єкту, прив’язаного до атрибуту db
і робить з нього копію, вказуючи два аргументи: рядок запиту SQL і id
. Процес копіювання абстрактного об’єкту називається “застосуванням”, оскільки він дуже подібний до застосування аргументів до функції в ФП.
Правильний спосіб використати абстрактний book
— це зробити його копію, вказавши аргументи:
book 42 mysql > b
Тут 42
є id
, mysql
є db
, а b
— новий об’єкт — копія об’єкту book
. У 𝜑-алгебрі, яка є основою мови програмування EO, це було б записано такою формулою:
b ↤ book(42, mysql)
Щоб отримати title
з b
і назвати його t
, просто пишемо:
b.title > t
А можна це все зробити в одному рядку:
(book 42 mysql).title > t
Можна застосувати до абстрактного об’єкту тільки деякі аргументи, а інші атрибути залишити вільними. Наприклад, це створило би інший абстрактний об’єкт з вимогою вказати id
, щоб стати закритим об’єктом:
book mysql:db > x
Суфікс :db
допомагає компілятору зрозуміти, котрий саме вільний атрибут буде прив’язаний до об’єкту mysql
. Пізніше x
буде скопійований знов, і буде створений закритий об’єкт b
:
x 42 > b
Хоч синтаксис EO дозволяє сказати book.title
, це призведе до помилки часу компіляції: заборонено зачіпати вільні атрибути абстрактного об’єкту або атрибути, залежні від інших вільних атрибутів. Але якщо ми додамо новий атрибут print
до book
і захочемо видати це на консоль, то для цього напишемо таке:
[id db] > book
stdout > print
sprintf
"The book ID is %d"
id
db.query > title
"SELECT title FROM book WHERE id=?"
id
Для атрибуту print
необов’язково, щоб атрибут db
був прив’язаний, бо він його не використовує. Можна скопіювати book
з самим id
і тоді викликати print
(якщо це відбувається в інтерактивній консолі EO):
$ book 42:id > x
x
$ x.print
The book ID is 42
До речі, чи відомі вам інші мови з абстрактними об’єктами, чи EO першим запроваджує цей дизайн?
(Будь ласка, підсвічуйте синтаксис у своїх коментарях, щоб їх було легше читати.)