Являются ли исключения концепцией ООП?

37

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

Джон V
источник
Однажды я прочитал, что «мистер Гуденуф» (или что-то подобное) изобрел исключения в ответ на «не важно, это Гуденуф, а! стиль издевательства. Я не могу найти ссылку сейчас - может быть, кто-то другой может. Было бы интересно узнать, на каком языке они были добавлены в первую очередь.
Steve314
7
У Haskell есть исключения, и это совсем не ООП
Даниэль Гратцер
1
Хотя сами исключения не являются строго объектно-ориентированными, обычная практика определения исключений как объектов и создания и перехвата экземпляров этих объектов явно очень ООП.
Dougvj
Какая разница между исключением и GOTO будет интересным вопросом.
Остин Хенли
2
@Austin - как насчет «хотя броски исключений нарушают принцип единой точки выхода, который некоторые из самых строгих учеников структурированного программирования отстаивают как абсолют, они не допускают беспрепятственный поток управления спагетти, как это gotoпроисходит. В частности, цель бросок определяется контекстом, основанным на вложенности блочных структур. Таким образом, исключения даже зависят от чуть менее строгой формы структурированного программирования, где принцип единого выхода принимается за руководство, а не как абсолют ».
Steve314

Ответы:

5

Исключения не являются концепцией ООП.

Но они не совсем не связаны ни с одной маленькой точкой.

Как показали другие ответы: концепция исключений сделана на нескольких не-ООП языках. Ничто в этой концепции не требует чего-то от ООП.

Но любой, если не все языки ООП, которые серьезно относятся к ООП, требуют исключений, потому что другие методы обработки ошибок терпят неудачу в одной конкретной точке: конструкторе.

Одна из точек ООП заключается в том, что объект должен полностью и последовательно инкапсулировать и управлять своим внутренним состоянием. Это также означает, что в чистом ООП вам нужна концепция для создания нового объекта с согласованным состоянием «атомарно» - все, от выделения памяти (если требуется) до инициализации до значимого состояния (т. Е. Простого обнуления памяти недостаточно) быть сделано в одном выражении. Следовательно, требуется конструктор :

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

Но это означает, что конструктор также может потерпеть неудачу из-за некоторой ошибки. Как распространять информацию об ошибках из конструктора без исключений?

  • Возвращаемое значение? Сбои, поскольку в некоторых языках newможет возвращаться только, nullно не вся значимая информация. На других языках (например, C ++) myFooнет указателя. Вы не могли проверить это против null. Также вы не можете спросить myFooоб ошибке - она ​​не инициализируется и, следовательно, «не существует» в ООП-мышлении.

  • Флаг глобальной ошибки? Так много о инкапсуляции состояния, а затем какой-то глобальной переменной? Перейти к ч ... ;-)

  • Смесь? Ни в коем случае не лучше.

  • ?

Таким образом, исключения являются более фундаментальной концепцией, чем ООП, но ООП строится на них естественным образом.

AH
источник
3
Насколько я могу судить, единственное слово в этом «ответе», которое отвечает на фактически заданный вопрос, - «нет». Остальное, похоже, относится к исключениям в ООП - при всем моем уважении это читается где-то между смутно родственными и совершенно неактуальными - опять же, в контексте
заданного
@gnat: TO также говорит, что он не знает о происхождении исключений. Отсюда и небольшая предыстория, почему исключения повсюду в ОО-земле, похоже, мне подходят. YMMV
AH
1
@ А, я должен согласиться с Гнат, кроме первой строки, это действительно не решает вопрос. Ваш ответ gnat был «говорит, что он не знает о происхождении исключений», но вы на самом деле не указали источник исключений, просто случайное использование исключений во время создания объекта.
Ребята, серьезно? -1? Большинство других ответов тоже не на 100%. +1 от меня, чтобы компенсировать. Этот ответ дает хороший базовый совет в мире ломаных дизайнов классов. (Поправка: следует избегать упоминания многошаговых конструкторов)
Jo So
44

Это ООП связано только?

Нет. Исключения и ООП не связаны.

Обработка исключений - это механизм обработки ошибок. Исключение обрабатывается путем сохранения текущего состояния выполнения в заранее определенном месте и переключения выполнения на определенную подпрограмму, известную как обработчик исключения.

Сравнивая C ( не совсем ООП-язык , можно каким-то образом эмулировать исключения в C ) и C ++ (ООП, поддерживает исключения), ничто не мешает стандартному комитету C добавить обработку исключений в C, но все равно не сделает C языком OOP.

BЈовић
источник
2
Можно даже утверждать, что уже есть какие-то исключения, поддерживаемые в обычной ОС. Позвольте вашей программе завершиться сбоем (неперехваченное «исключение») и с дампом ядра и отладчиком вы даже получите трассировку стека.
Бхак
12
Даже MS BASIC с начала 80-х имела обработку исключений:ON ERROR GOTO xxxx
jwernerny
1
@bhaak Он мог бы также говорить о
дампах
11
@jwernerny Обработка ошибок? Конечно. Но никто не назвал бы эту обработку исключений. Фактически, это обычно противопоставлялось (структурированной) обработке исключений.
Конрад Рудольф
1
@jwernerny не уверен, что я следую; обработка исключений, как я понял, это очень специфический способ обработки ошибок. Когда я слышу исключение, я всегда думаю о try catchконструкции.
Энди
12

Проще говоря, исключение представляет собой исключительную ситуацию, требующую внимания и часто изменения в потоке выполнения программы. По этому определению исключения и обработка исключений не ограничиваются ориентацией объекта, и простые программные ошибки могут рассматриваться как форма исключения.

Объектно-ориентированные языки обычно имеют собственный класс исключений, и в зависимости от контекста слово «исключение» может действительно ссылаться на этот собственный класс вместо общего понятия. Обработка объектно-ориентированных исключений, как и большая часть объектной ориентации, является синтаксическим сахаром и может быть легко эмулирована в решительно не объектно-ориентированных языках. Вот пример C, из викибука C Programming :

#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
комар
9

Ответ прост: НЕТ.

Хорошим примером для языка без OO с исключениями является ADA.

Уве Плонус
источник
4
Хм, почему ADA не является языком OO? Конечно, в ADA83 отсутствовал полиморфизм, но его все еще можно было считать объектным. Также начиная с ADA95 язык полностью объектно-ориентирован.
Яннис
Насколько я знаю, обработка исключений старше, чем ADA83, поэтому ADA сам по себе не является OO с обработкой исключений.
Уве Плонус
2
@YannisRizos: Ada83 имеет пакеты и универсальные пакеты, но не объекты. Они были введены с Ada95.
Mouviciel
2
@Yannis - Объекты без полиморфизма похожи на структурированное программирование без вложенных блоков. Полиморфизм является одной из определяющих черт ООП. Даже в Ada95 типы, которые поддерживают привязку во время выполнения, называются «теговыми типами», а не «классами», хотя, конечно, это просто орфография. Ада 83 имела различные записи и другие типы, но ни один из этих типов не предоставляет функции, специфичные для ООП. Ада 83 была модульной и структурированной, но она не была объектно-ориентированной.
Steve314
3
@Yannis - в основном, некоторые люди в сообществе Ада (например, некоторые сторонники большинства языков) не могут смириться с тем, что функция может быть хорошей, но не реализованной на их любимом языке, и создаст всевозможные оправдания для веры в обратное. Тем не менее, даже не так, чтобы хороший язык нуждался во всех возможных хороших языковых возможностях (хотя легко поверить, что так думали дизайнеры Ada). Я не очень верю в минималистский подход к языковому дизайну, но максималистские языки тоже не идеальны.
Steve314
7

Здесь уже есть несколько очень хороших ответов. Другие примеры для языков программирования не-ООП, имеющих исключения:

  • Oracle PL / SQL

  • классический Visual Basic (V6 и ниже, «При ошибке Перейти к» ИМХО является формой обработки исключений)

(Проще говоря, вы найдете некоторые элементы ОО в обоих языках, но механика обработки исключений не использует их, я полагаю, потому что концепция была введена за годы до того, как элементы ОО были добавлены в эти языки).

Док Браун
источник
По крайней мере, более поздние версии QuickBASIC в DOS (которые предшествовали Visual Basic; QB 4.5 был 1988 г. согласно Wikipedia, VB 1.0 1991) имели обработку ошибок с использованием ON ERROR GOTOсинтаксиса. Даже в QuickBASIC было несколько OO-подобных концепций (я думаю, что QB 4.5 даже поддерживал классы какого-то рода), но вам было бы трудно назвать в основном традиционный BASIC правильным объектно-ориентированным языком. [Википедия ]
CV
5

Основная идея исключений состоит в том, чтобы очистить поток программы, чтобы программист мог легче следовать «нормальному» пути выполнения. Рассмотрим простой случай открытия файла на языке C. Сразу после попытки открыть файл программист должен изучить ответ на вызов fopen () и решить, был ли вызов успешным. Если вызов не удался, программист должен ответить соответствующим образом. Следующий вызов в «нормальном» пути выполнения, возможно вызов fread () или fwrite (), появится после того, как будут обработаны условия ошибки или сбоя. Это может быть на следующем экране.

С языком, который предоставляет исключения, эквивалентный вызов fopen () может сразу же сопровождаться fread () или fwrite (). Нет обработки ошибок, которая скрывает «следующий шаг» «нормального» пути выполнения. Программист может видеть больше обычного пути на одном экране и, таким образом, легче следить за выполнением. Обработка ошибок перенесена в другую часть программы.

Сами исключения не являются концепцией ООП, но они часто реализуются с использованием концепций ООП, которые делают их более удобными и мощными. Например, исключения могут быть определены с иерархией наследования. Используя наш условный пример открытия и чтения или записи файла, каждый из этих вызовов может генерировать различные исключения - FileClosedException, DeviceFullException, NoSuchFileException, InsufficientFilePermissionsException и т. Д. Каждый из них может наследоваться от FileException, который может наследоваться от IOException, что может наследовать от GenericException.

Если программист делает быструю и грязную реализацию для проверки концепции, он может в основном игнорировать обработку исключений и просто реализовать один обработчик для GenericException. Этот обработчик будет обрабатывать GenericException и любое исключение, которое наследуется от GenericException. Если он хочет обрабатывать любое исключение, связанное с файлом, таким же образом, он может написать обработчик для FileException. Это будет вызываться для FileExceptions и любых исключений, которые наследуются от FileException. Если он хочет написать программу, которая будет по-разному реагировать на различные ошибки, он может написать конкретный обработчик для каждого конкретного исключения.

MikeD
источник
3

Другие справедливо ответили «Нет» примерами языков. Я подумал, что могу расширить, добавив пример того, как добавлять исключения к языку, не вовлекая ООП.

Я сделаю это в случае с DSKL (декларативным последовательным языком ядра) OZ , языка, хорошо подходящего для подобных вещей. DSKL (или DKL) можно увидеть здесь (результат случайного поиска), заявления и Values часть. Точное определение не имеет значения, за исключением того, что это очень простой язык без изменяемых переменных (они объявляются и привязываются позже), а также не встроен ООП.

ООП нельзя даже добавить в качестве лингвистической абстракции к этому языку ядра. Добавляя уникальные имена к языку ядра (NewName) и используя локальную область видимости, можно добиться инкапсуляции. Или добавляя изменяемое состояние к языку ядра (NewCell) и используя локальную область видимости, можно достичь правильного ООП с инкапсуляцией. Но это не может быть достигнуто только с указанным языком ядра.

Если затем мы добавим исключения к языку ядра, у нас будет язык без поддержки ООП, но есть исключения. Позвольте мне показать, как:

Определив абстрактную машину со стеком и хранилищем, мы можем определить, что должен делать каждый оператор в нашем языке ( семантика оператора). Например, skipв стеке ничего не нужно делать, A = 3в стеке следует связать (/ unify) A с (/ with) 3.

Мы начнем с добавления синтаксиса того, как должны быть определены наши исключения. Мы делаем это, добавляя еще два предложения <statement>в DKL.

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

Вот известный try / catch и способ поднять / выбросить исключения.

Мы определяем их семантику по тому, как они должны работать на абстрактной машине:

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

  1. Вставьте в стек семантическое утверждение (catch <id> then <statement2> end)
  2. Вставьте в стек семантическое утверждение (<statement1>)

Обратите внимание, что оператор 1 будет на вершине стека, и попытается выполнить сначала.

Поднять
Семантическое утверждение: (raise <id> end)
Do:

  1. Если в стеке больше ничего нет, остановитесь и сообщите о необработанном исключении.
  2. Иначе, вытолкните первое семантическое утверждение из стека. Если это не оператор catch, перейдите к шагу 1.
  3. Мы получили подвох в форме (catch <id> then <statement> end)
    Push (<statement>)на стек.

Catch
Если мы видим выражение catch во время обычного выполнения, это означает, что все, что было внутри, было выполнено без возведения исключений до этого уровня. Таким образом, мы просто выталкиваем catchстек и ничего не делаем.

КЭД, у нас есть язык с исключениями и нет возможности ООП.

Я удалил часть среды из абстрактной машины, чтобы сделать ее проще.

Matsemann
источник
1

Нет.

IIRC, исключения появились до первых ОО языков. AFAIK, исключения были впервые поддержаны ранними реализациями LISP. Ранние структурированные языки (например, ALGOL) и ранние ОО-языки (например, SIMULA) не поддерживали исключения.

Кевин Клайн
источник
У ALGON 68, конечно, были исключения («события»), но было и все остальное. У PL / I они тоже были («ON условия»), и есть литература 1969 года, описывающая их использование.
Росс Паттерсон