Чи є винятки концепцією ООП?


37

Прочитавши вчора допис, я зрозумів, що не знаю багато про походження винятків. Це лише концепція, пов'язана з ООП? Я схильний вважати це так, але знову є винятки з бази даних.


Я одного разу прочитав, що "містер Гуденуф" (або подібний) винайшов винятки у відповідь на "нічого, це Goodenuf, так!" стиль знущання. Я не можу зараз знайти посилання - можливо, хтось інший може. Було б цікаво дізнатися, до якої мови їх додали першими.
Steve314

7
У Haskell є винятки, і це зовсім не OOP
Daniel Gratzer

1
Хоча самі винятки не є суто об'єктно-орієнтованими, загальна практика визначення винятків як об'єктів та викидання та вилучення екземплярів цих об'єктів очевидно є дуже OOP.
Dougvj

Чим відрізняється виняток від GOTO, було б цікавим питанням.
Остін Генлі

2
@Austin - як щодо "хоча винятки, що виключають, порушують принцип єдиної точки виходу, що деякі найсуворіші учні структурованого програмування виступають за абсолют, вони не дозволяють безперешкодно керувати спагеті потоком так, як це gotoвідбувається. Зокрема, ціль кидок визначається контекстом, що ґрунтується на вкладенні блок-структур. Виключення навіть залежать від дещо менш суворої форми структурованого програмування, де принцип єдиного виходу приймається як орієнтир, але не є абсолютним ".
Steve314

Відповіді:


5

Винятки не є концепцією ООП.

Але вони не є абсолютно спорідненими ні в одній маленькій крихітній точці.

Як показали інші відповіді: Концепція винятків склала її у кількох мовах, що не належать до ОП. Ніщо в цій концепції нічого не вимагає від OOP.

Але будь-які, якщо не всі мови OOP, які сприймають OOP серйозно, вимагають винятку, оскільки інші методи керування помилками провалюються в одному конкретному пункті: Конструктор.

Одним із пунктів ООП є те, що об’єкт повинен повністю та послідовно інкапсулювати та керувати своїм внутрішнім станом. Це також означає, що в чистому OOP вам потрібна концепція створення нового об'єкта з послідовним станом "атомно" - все, від розподілу пам'яті (якщо потрібно), до ініціалізації до значущого стану (тобто простого нулювання пам'яті недостатньо) повинно бути робити в одному виразі. Отже конструктор потрібен:

Foo myFoo = Foo("foo", "bar", 42);

Але це означає, що конструктор також може вийти з ладу через певну помилку. Як поширити інформацію про помилки з конструктора без винятків?

  • Повернене значення? Збій, оскільки в деяких мовах newможе повертатися лише nullякась, але не будь-яка значуща інформація. В інших мовах (наприклад, C ++) myFooне є покажчиком. Ви не могли це перевірити null. Також ви не можете запитати myFooпро помилку - вона не ініціалізована і тому "не існує" в мисленні OOP.

  • Прапор глобальної помилки? Стільки про інкапсуляцію стану, а потім про якусь глобальну змінну? Ідіть до ч ... ;-)

  • Суміш? Ні в якому разі не краще.

  • ?

Отже, винятки є більш фундаментальною концепцією, ніж ООП, але ООП будує їх природним чином.


3
наскільки я можу сказати, єдине слово в цій "відповіді", яке стосується фактично заданого питання, - "ні". У іншому, здається, йдеться про винятки в ООП - при всій повазі до мене це звучить десь між неясно пов’язаними та абсолютно невідповідними - знову ж таки, в контексті поставленого запитання
гнат

@gnat: ТО також говорить, що не знає про походження винятків. Звідси невелике підґрунтя, чому винятки є скрізь на території OO для мене. YMMV
AH

1
@AH Я повинен погодитися з gnat, окрім початкового рядка, це дійсно не стосується питання. Ваша відповідь на gnat була "говорить, що він не знає про походження винятків", але ви насправді не вказали походження винятків, а лише випадкове використання винятків під час встановлення об'єктів.

Хлопці, серйозно? -1? Більшість інших відповідей теж не на 100% до речі. +1 від мене для компенсації. Ця відповідь дає хороші базові поради у світі розбитих дизайнів класів. (Поправка: Слід уникати багатоступеневих конструкторів)
Jo So

44

Це стосується лише OOP?

Ні. Винятки та ООП не пов'язані між собою.

Поводження з винятками - це механізм обробки помилок. Виняток обробляється шляхом збереження поточного стану виконання у заздалегідь визначеному місці та переключення виконання на певну підпрограму, відому як обробник винятків.

Якщо порівнювати C ( не насправді мова OOP , можливо якось імітувати винятки в C ) та C ++ (OOP, підтримує винятки), ніщо не заважає стандартному комітету C додати обробку винятків до C, вона все одно не зробить C мовою OOP.


2
Можна навіть стверджувати, що вже є якісь винятки, які підтримуються у звичайній ОС. Нехай ваша програма виходить з ладу (невловимий "виняток"), а з основним дамп і відладчиком ви навіть отримаєте слід стека.
бхаак

12
Навіть форми MS BASIC початку 80-х мали обробку виключень:ON ERROR GOTO xxxx
jwernerny

1
@bhaak Він також міг говорити про скидання пам’яті в Windows
JohnL

11
@jwernerny Помилка обробки? Звичайно. Але ніхто не назве це поводження з винятками. Насправді це звичайно протиставлялося (структурованому) обробці винятків.
Конрад Рудольф

1
@jwernerny не впевнений, що я слідую; обробка виключень, як я зрозумів, це дуже специфічний спосіб поводження з помилками. Коли я чую виняток, я завжди думаю про try catchконструкцію.
Енді

12

Винятком є, просто кажучи, виняткова ситуація, яка вимагає уваги і часто змінюється в потоці виконання програми. За цим визначенням обробка виключень та винятків не обмежується орієнтацією на об'єкти, а прості програмні помилки можна вважати формою винятку.

Об'єктно-орієнтовані мови зазвичай мають рідний клас виключення, і залежно від контексту слово "виняток" дійсно може посилатися на цей рідний клас замість загального поняття. Об'єктно-орієнтована обробка винятків є, як і більшість об'єктних орієнтацій, синтаксичним цукром, і їх можна легко імітувати в рішуче не об'єктно орієнтованих мовах. Ось приклад C із вікі-книги Програмування на C :

#include <stdio.h>
#include <setjmp.h>

jmp_buf test1;

void tryjump()
{
    longjmp(test1, 3);
}

int main (void)
{
    if (setjmp(test1)==0) {
        printf ("setjmp() returned 0.");
        tryjump();
    } else {
        printf ("setjmp returned from a longjmp function call.");
    }
}

6
Це не просто синтаксичний цукор. Відтворити повне розмотування стека та оброблювачів вилову на основі типу складно з setjmp. Крім того, компіляція винятків за спеціальностями призводить до переваг, які не можна імітувати setjmp.
edA-qa mort-ora-y

3
Я ненавиджу винятки з опису - виняткові ситуації. Я скоріше кажу, що винятки мають бути створені (викинуті), коли ситуацію з помилками неможливо вирішити з поточним контекстом, оскільки в поточному контексті недостатньо інформації, щоб правильно виправити помилку.
Мартін Йорк

+1 для setjmp.h
gnat

9

Відповідь - простий НІ.

Хороший приклад для мови, що не є ООС, за винятком - ADA.


4
Гм, чому ADA не є мовою ОО? Зазначається, що ADA83 не мав поліморфізму, але це все ще можна вважати об'єктом. Також з ADA95 мова повністю орієнтована на об'єкт.
янніс

Наскільки я знаю, обробка винятків є старшою за ADA83, тому ADA сама по собі є не OO з обробкою виключень.
Uwe Plonus

2
@YannisRizos: Ada83 має пакунки та загальні пакунки, але не об’єкти. Вони були представлені з Ada95.
mouviciel

2
@Yannis - Об'єкти без поліморфізму - це як структуроване програмування без вкладених блоків. Поліморфізм - одна з визначальних рис ООП. Навіть в Ada95 типи, які підтримують прив'язку часу виконання, називаються "тегами типів", а не "класами", хоча, звичайно, це просто написання. Ada 83 мав варіанти варіантів і різні інші типи, але жоден із цих типів не забезпечує функцій, специфічних для OOP. Ада 83 була модульною та структурованою, але не була орієнтована на об’єкти.
Steve314

3
@Yannis - в основному, деякі люди спільноти Ада (як і деякі прихильники більшості мов) не можуть прийняти, що функція може бути хорошою, але не реалізованою на своїй улюбленій мові, і складе всілякі виправдання для того, щоб повірити в інше. Однак це навіть не так, як для того, щоб гарна мова мала мати всі можливі хороші мовні особливості (хоча повірити дизайнерам Ада так). Я насправді не вірю в мінімалістичний підхід до дизайну мови, але і максималістичні мови не є ідеальними.
Steve314

7

Ось вже дуже хороші відповіді. Інші приклади для мов програмування, які не є ООП, мають винятки:

  • Oracle PL / SQL

  • класичний Visual Basic (V6 та нижче, "On Error Goto" - це IMHO - форма обробки винятків)

(Якщо бути охайним: ви знайдете деякі елементи OO в обох мовах, але виняток, який керує механікою, не використовує їх, я думаю, тому що концепція була введена за роки до того, як елементи OO були додані до цих мов).


Принаймні, пізніші версії QuickBASIC в DOS (які раніше були Visual Basic; QB 4.5 був 1988 за Вікіпедією, VB 1.0 1991) мали помилки при використанні ON ERROR GOTOсинтаксису. Навіть у QuickBASIC було кілька понять, подібних до OO (я думаю, що QB 4.5 навіть підтримував якісь класи), але вам важко назвати здебільшого традиційний BASIC правильною об'єктно-орієнтованою мовою. [Вікіпедія ]
CVn

5

Основна ідея винятків полягає в тому, щоб очистити потік програми, щоб програміст легше проходив "звичайний" шлях виконання. Розглянемо простий випадок відкриття файлу в C. Одразу після спроби відкрити файл, програмісту необхідно вивчити відповідь на виклик fopen () та вирішити, чи вдався виклик. Якщо дзвінок не вдався, програміст повинен відповісти належним чином. Наступний виклик у "звичайному" шляху виконання, можливо, виклик до fread () або fwrite (), з'явиться після обробки помилок або відмов. Це може бути на наступному екрані.

З мовою, яка надає винятки, еквівалентний виклик fopen () може негайно слідувати за допомогою fread () або fwrite (). Немає обробки помилок, яка приховує "наступний крок" "нормального" шляху виконання. Програміст може бачити більше нормального шляху на одному екрані, і тому може легше стежити за виконанням. Обробка помилок переміщена в іншу частину програми.

Винятки самі по собі не є концепцією ООП, але вони часто реалізуються за допомогою концепцій ООП, що робить їх більш зручними та потужними. Наприклад, винятки можуть бути визначені за допомогою ієрархії спадкування. Використовуючи наш уявний приклад відкриття та читання або запису файлу, кожен з цих викликів може створити різні винятки - FileClosedException, DeviceFullException, NoSuchFileException, InsufficFilePermissionsException тощо. Кожен з них може успадковувати файл FileException, який може успадкувати IOException успадковувати від GenericException.

Якщо програміст виконує швидку та брудну реалізацію для тестування концепції, він, можливо, ігнорує обробку виключень та просто реалізує один обробник для GenericException. Цей обробник буде обробляти GenericException і будь-який виняток, який успадковується від GenericException. Якщо він хоче однаково ставитися до будь-якого винятку, пов'язаного з файлами, він може написати обробник для FileException. Це буде викликано FileExceptions та будь-які винятки, які успадковуються від FileException. Якщо він хоче написати програму, яка по-різному реагуватиме на різні умови помилок, він може написати певний обробник для кожного конкретного винятку.


3

Інші справедливо відповіли "Ні" із прикладами мов. Я думав, що можу продовжити, додавши приклад того, як додавати винятки до мови, не залучаючи жодного разу OOP.

Я зроблю це у випадку, коли DSKL (Декларативна послідовна мова ядра) OZ , мова, яка добре підходить для подібних навчальних закладів. DSKL (або DKL) можна побачити тут (випадковий результат пошуку), частина Заяви та цінності. Точне визначення не є важливим, окрім того, що це дуже проста мова без змінних змінних (вони оголошуються та пізніше пов'язані), і немає вбудованого OOP.

OOP не можна навіть додати як мовну абстракцію до цієї мови ядра. Додаючи унікальні імена до мови ядра (NewName) та використовуючи локальний масштаб, можна досягти інкапсуляції. Або, додавши стан ядра до мови ядра (NewCell) та використовуючи місцевий масштабний OOP з інкапсуляцією, можна досягти. Але цього неможливо досягти лише за допомогою вказаної мови ядра.

Якщо тоді ми додамо винятки до мови ядра, у нас буде мова без підтримки OOP, але у нас є винятки. Дозвольте мені показати, як:

Визначаючи абстрактну машину зі стеком і сховищем, ми можемо визначити, що повинен робити кожен вислів нашою мовою ( семантика висловлювання). Наприклад, skipу стеку нічого не повинно бути, A = 3в стеку слід прив'язувати (/ уніфікувати) від A до (/ з) 3.

Почнемо з додавання синтаксису того, як слід визначити наші винятки. Ми робимо це, додаючи ще два пункти до <statement>DKL.

<statement>  ::== ... (old stuff)
                 | try <statement> catch <id> then <statement> end
                 | raise <id> end

Ось відомий спробу / ловіння та спосіб підняти / кинути винятки.

Ми визначаємо їх семантику , як вони повинні працювати на абстрактній машині:

Спробуйте
семантичний вислів: (try <statement1> catch <id> then <statement2> end)
Do:

  1. Висуньте на стек семантичний вислів (catch <id> then <statement2> end)
  2. Висуньте на стек семантичний вислів (<statement1>)

Зауважте, що оператор 1 опиниться на вершині стека і спробується виконати першим.

Підняти
Семантичний вислів: (raise <id> end)
Do:

  1. Якщо більше нічого не стоїть на стеці, зупиніться і повідомте про невловимий виняток.
  2. Інакше, вискакуй перший семантичний вислів із стека. Якщо це не заява про вилов, перейдіть до кроку 1.
  3. Ми дістали улов у формі " (catch <id> then <statement> end)
    Натисніть (<statement>)на стек".

Catch
Якщо ми бачимо заявку на вилов під час звичайного виконання, це означає, що все, що було всередині, виконується без підвищення винятків до цього рівня. Таким чином, ми просто вискакуємо catchстек і нічого не робимо.

QED, у нас мова з винятками та відсутність можливості OOP.

Я видалив частину середовища з абстрактної машини, щоб зробити її простішою.


1

Ні.

IIRC, винятки з'явилися перед першими мовами ОО. AFAIK, винятки були вперше підтримані ранніми впровадженнями LISP. Ранні структуровані мови (наприклад, ALGOL) та ранні мови OO (наприклад, SIMULA) не підтримували винятків.


ALGON 68, звичайно, мав винятки ("події"), але в ньому було і все інше. PL / У мене їх теж було ("умови ВКЛ"), і є література 1969 року, де описано їх використання.
Росс Паттерсон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.