Re[2]: Что вы предлагаете на замену эксепшенов?
От: c-smile Канада http://terrainformatica.com
Дата: 21.11.05 08:12
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Понимаю, что технических проблем здесь хватит, и вряд ли нынешние языки это потянут, но самам идея, ИМХО, имеет право на существование.


В VB есть нечто подобное

On Error Resume [Next]

http://www.magictree.com/vbcourse/11design/errors.htm
Re[2]: Что вы предлагаете на замену эксепшенов?
От: Cyberax Марс  
Дата: 21.11.05 08:30
Оценка:
Pavel Dvorkin wrote:

> Происходит исключение. Выбрасывется экземпляр класса исключения. Это

> экземпляр получает доступ к классу/методу, где произошло исключение,
> анализирует причину и изменяет состояние класса, после чего, возможно,
> повторяет операцию, вызвавшую исключение.

Такие идеи пробовались в 70-80х годах. Оказалось, что корректно
обрабатывать retry'и достаточно сложно, и почти никогда не нужно. А
когда все же действительно нужно, то проще явный while поставить.

У Страуструпа где-то об этом было неплохо написано.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[2]: Что вы предлагаете на замену эксепшенов?
От: Глеб Алексеев  
Дата: 21.11.05 08:39
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX> Чтобы проигнорировать код ошибки, ничего делать не нужно, именно поэтому в реальных ситуациях они часто и игнорируются. А вот чтобы проигнорировать исключение, нужны явные действия по их игнорированию.


Явные действия по игнорированию? Это вроде только в Java нужно, AFAIK. Во многих языках, и в С++ в том числе, спецификации исключений необязательны, и вызов функции, потенциально бросающей исключение, не генерирует ошибку компиляции. Так что этот аргумент принимается только в том случае, если coverage (степень покрытия?) тестов достаточный(ая).
Re[3]: Что вы предлагаете на замену эксепшенов?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 21.11.05 08:43
Оценка:
Здравствуйте, Глеб Алексеев, Вы писали:

CX>> Чтобы проигнорировать код ошибки, ничего делать не нужно, именно поэтому в реальных ситуациях они часто и игнорируются. А вот чтобы проигнорировать исключение, нужны явные действия по их игнорированию.


ГА>Явные действия по игнорированию? Это вроде только в Java нужно, AFAIK. Во многих языках, и в С++ в том числе, спецификации исключений необязательны, и вызов функции, потенциально бросающей исключение, не генерирует ошибку компиляции. Так что этот аргумент принимается только в том случае, если coverage (степень покрытия?) тестов достаточный(ая).


Спецификация исключений -- это только одна сторона медали.
Другая сторона -- это catch(...) или catch( const std::exception & ), ибо в противном случае игнорирования не получится -- исполнение прервется.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[3]: Что вы предлагаете на замену эксепшенов?
От: CrystaX Россия https://crystax.me/
Дата: 21.11.05 08:43
Оценка:
Здравствуйте, Глеб Алексеев, Вы писали:

CX>> Чтобы проигнорировать код ошибки, ничего делать не нужно, именно поэтому в реальных ситуациях они часто и игнорируются. А вот чтобы проигнорировать исключение, нужны явные действия по их игнорированию.


ГА>Явные действия по игнорированию? Это вроде только в Java нужно, AFAIK. Во многих языках, и в С++ в том числе, спецификации исключений необязательны, и вызов функции, потенциально бросающей исключение, не генерирует ошибку компиляции. Так что этот аргумент принимается только в том случае, если coverage (степень покрытия?) тестов достаточный(ая).


Нет, я говорил вот о чем:
try
{
    do_something();
}
catch(some_specific_exception &)
{
    // Ignore it
}


Для того, чтобы проигнорировать some_specific_exception, понадобилось писать блок try/catch. В ином случае оно обязательно вылетело бы где-нибудь выше. А вот с кодами ошибок ситуация другая — чтобы не забыть ее обработать, нужен доп. код.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[2]: Что вы предлагаете на замену эксепшенов?
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 21.11.05 09:39
Оценка:
Здравствуйте, Nickolay Ch, Вы писали:

NC>Посыл неверный.


Не верный относительно чего?

NC>Пример: некий оффлайн клиент. Пользователь отредактировал документ и хочет его скинуть на сервер. Сервер недоступен. Какая это ошибка в вашей терминологии? На 1ую непохоже, а во втором случае надо завершить программу? И все, что было создано пропадет?

NC>Аналогично с сохранением файла на носитель, на котором кончилось место. По идее надо дать возможность сменить носитель и т.д., а не молча закрыть прогу.
NC>Опять возвращаемся к кодам ошибок или исключениям.

Сервер недоступен или место на жестком диске кончилось — это не ошибки вовсе. Программист с самого начала проектирования программы знает, что серверы могут быть не доступными, а жесткие диски не резиновые. Программа должна уметь корректно работать и в этих случаях. Это не то что не ошибки, это даже не исключительные ситуации, а самые обычные рядовые — штатные варианты работы.

То же мне выдумали, этот вариант работы значит штатный, а вот этот вариант работы уже значит не штатный. Да любой известный заранее вариант работы — штатный. Прилетел из космоса микрометеорит и пробил в блоке памяти дырку — исключительная ситуация? Для космических кораблей — не исключительная, а рядовая, штатная; для домашнего компьютера — исключение, ошибка, что надо сделать с домашним компьютером? — Выключить и поменять блок памяти вручную.
Re[3]: Что вы предлагаете на замену эксепшенов?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 21.11.05 09:45
Оценка: +1 :)
Здравствуйте, Сергей Губанов, Вы писали:

СГ>для домашнего компьютера — исключение, ошибка, что надо сделать с домашним компьютером? — Выключить и поменять блок памяти вручную.


А что программе-то делать в этих условиях?
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[4]: Что вы предлагаете на замену эксепшенов?
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 21.11.05 10:34
Оценка: +1 -2 :)
Здравствуйте, eao197, Вы писали:

E>А что программе-то делать в этих условиях?


Странный вопрос. Что в техническом задании на программу для этого случая написано, то и делать.

Если, например, в ТЗ написано, что при недостаточном месте на диске надо предложить пользователю:
а) очистить диск, потом повторить операцию сохранения;
б) предложить сохранить на floppy/CD-RW/и т.д.
в) предложить отправить по электронной почте...
то это и делать.
Re[2]: Плагины = компоненты системы
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 21.11.05 10:47
Оценка: :)
Здравствуйте, Andy77, Вы писали:

A>Например, разрабатывая расширяемую плагинами систему, не будешь же ты полататься на непогрешимость сторонних разработчиков?


Да, Вы правы. Я упустил этот вариант. Прошу прощения. Разумеется в этом случае системные ловушки (trap) обязательны.

Попытаюсь объяснить почему я упустил этот вариант из виду. Дело в том, что программирование в компонентных системах (скажем, таких как Оберон-системы) это уже есть де-факто написание плагинов для уже готовой системы времени исполнения. Каждый модуль (компонент системы) — фактически и есть плагин. Разумеется, если цель состоит в написании своей собственной системы времени исполнения, то, повторяюсь, системные ловушки обязательны. Но даже это еще не повод включать механизм исключений в язык. Проблема решается на уровне библиотек. Прекрасный пример — BlackBox, там системные trap-ы есть (на уровне модуля Kernel), но в самом языке Component Pascal, на котором написано ядро = система времени исполнения, механизма исключений нет.
Re[3]: Что вы предлагаете на замену эксепшенов?
От: GlebZ Россия  
Дата: 21.11.05 10:53
Оценка: +1
Здравствуйте, Andrei N.Sobchuck, Вы писали:

ANS>Это так называемые "продолжаемые исключения". Работает в языках, не разрушающих стек во время поиска обработчика. Например в ST, CLOS.

Честно говоря такое есть и в C. Только не везде реализовано, зависит от платформы и очень тормозно. Но благодаря таким возвратам можно управлять виртуальными страницами.

С уважением, Gleb.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Что вы предлагаете на замену эксепшенов?
От: Sinclair Россия https://github.com/evilguest/
Дата: 21.11.05 11:35
Оценка: 193 (25) +10
Здравствуйте, Сергей Губанов, Вы писали:
СГ>то это и делать.
Сергей, ваши представления о программировании все еще катастрофически далеки от реальности.
Вы, судя по вашему ответу, считаете, что
а) программа должна трактовать все случаи как равновероятные
б) вся информация для принятия решения доступна ровно там, где выполняется действие.
И то и другое — заблуждения.
Начнем с последнего. Как правило, с неожиданной ситуацией сталкивается код самого нижнего уровня. Что значит "неожиданная ситуация"? Это выражение означает "невозможно выполнить запрошенное действие". Например, мы пытаемся записать килобайт данных в TCP сокет. Упс! Сокет закрылся — например, оборвали кабель, или другая сторона явно разорвала соединение. Внешнему коду, который позвал метод send, вообще ничего не известно про состояние сети. И не может быть известно в силу инкапсуляции — он пишет в какой-то поток, не более того. Это может быть файл, сокет, или блоб-поле в базе данных.
Даже если клиент умен, и предварительно спросил у сокета, можно ли посылать, вовсе не факт, что проблема не возникнет в процессе работы метода:
if(s.IsConnected)
{
  s.Send(myData); /// ошибка где-то в середине передачи
}

Что делать? Ага, проверим код результата:
if(s.IsConnected)
{
  switch(s.Send(myData))
    {
      case SOCKET_DISCONNECTED: ...
        case BUFFER_OVERFLOW: ...
        case ...: ...
        else: // уфф, пронесло, все в порядке.
    }
}

Все здорово до тех пор, пока у нас действительно достаточно информации. Но ведь этот клиентский код, в свою очередь, может быть всего лишь низкоуровневой оберткой над отправкой данных. Что ему делать? По ТЗ надо отсылать письмо. Прекрасно. У нас код нижнего уровня должен знать адрес администратора и уметь отправлять почту.
Чудно. Если же мы оставляем эту работу более высокоуровневому коду, то ему надо откуда-то узнать, что именно случилось. Или же все кончается методом
bool SaveChangesToDbAndSendNotifications()

В случае возврата false надо отправить письмо — и пусть админ гадает, что же там упало. То ли с базой связаться не удалось, то ли нотификации не уехали.
Вообще, вас уже отправили читать Страуструпа — не упрямьтесь, поверьте — он про все это лучше меня написал. И уже давно.

Второй момент — вы предлагаете трактовать все, оговоренное в ТЗ как штатную ситуацию. Оставим пока за бортом вопрос полноты ТЗ. Решим пока, что все неописанные случаи могут приводить к undefined behavior (вообще в наши дни софт с UB — это моветон, если что).

С вашей точки зрения, если проектировщик догадался спросить, не нужна ли реакция софта на падение метеорита, и ему сказали что нужна, то код должен быть устроен так:
if(метеорит_упал)
{
  выполняем_запасные_действия();
}
else
{
  идем_по_основной_ветке();
}

Во-первых, такой код тяжело читать. Он намекает на 50% вероятность попадания метеорита; он содержит ветку основной логики как редкий частный случай и затрудняет понимание собственно решаемой задачи.
Кроме того, зачастую реакция на очень большое количество разнообразных ситуаций более-менее одна. К примеру, асп.нет банально перезапускает повисшее приложение, не вдаваясь в детали — метеорит там, деление на ноль, бесконечный цикл или моль дырку проела. В коде, который действует по методу блондинки, надо предусмотреть реакцию как на отсутствие динозавра, так и на его присутствие.

Во-вторых, это банально влияет на производительность. Если у нас есть частая ветка, то она должна исполняться максимально быстро. Особенно это характерно для исключений — если произошел какой-то сбой, не так уж важно быстро его обработать. Тут бы не совсем не упасть — и то хорошо. Вот, к примеру, процессоры так и делают — предсказывают ветвления и стараются ускорить выполнение частой ветки, в ущерб выполнению редкой, которое приводит к дорогостоящему сбросу конвеера. Но у процессора близорукость сильная, его предсказалка в пределах махоньких циклов хорошо работает. А для более крупных блоков он не поможет.
Код, работающий пессимистично, должен, к примеру, перед снятием денег со счета проверить, а хватит ли их там. Ну и пойти либо снимать деньги, либо писать пользователю отмазку. А поскольку стоимость проверки количества денег примерно такая же, что и стоимость съема денег, мы получаем просад производительности минимум в два раза только за счет пессимизма. (На самом деле все еще намного хуже из-за блокировок и прочих эффектов второго порядка). А вот оптимистичный код пытается выполнить все, как будто все хорошо. И только если вдруг оказалось, что что-то не вышло, выполняется дорогой код раскрутки стека, отката транзакции и т.п.

Вот вам и отличие штатной от нештатной — нештатная ситуация редка, и не позволяет довести начатое до конца. Академизм здесь вреден — не все ситуации равноправны.
Да, использовать исключения для штатной работы — глупо:
// Бросает исключение OopsItsTailsAgainException в 50% случаев
void ThrowCoinAndCheckHeads() 

enum CoinSides { Heads, Tails};
...

CoinSides ThrowCoin()
{
  try
    {
       ThrowCOinAndCheckHeads();
         return CoinSides.Heads;
    catch(OopsItsTailsAgainException)
    {
        return CoinSides.Tails;
    }
}

Но это никак не подрывает саму идею исключений как механизма отделения логики обработки нештатных ситуаций от основной логики.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Что вы предлагаете на замену эксепшенов?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 21.11.05 11:42
Оценка: +5
Здравствуйте, Сергей Губанов, Вы писали:

E>>А что программе-то делать в этих условиях?


СГ>Странный вопрос. Что в техническом задании на программу для этого случая написано, то и делать.


Знаешь, Сергей, этот ответ напоминает замечательное требование, которое выдвигают заказчики: "Программа должна делать то, что нужно. И должа делать это так, как нужно". Не умея при это объяснить что такое "что нужно" и что такое "как нужно".

Вернемся к выходу из строя модуля памяти. Есть OS (например, HP NonStop Kernel) которые прекрасно справляются с выходом из строя практически всех модулей памяти (за исколючением хотя бы одного). Но что это означает для программы? А означает это то (утрируя), что следующий код:
My_Object * o = new My_Object();

// Вот в этой точке приведет к обращению по недоступному адресу.
o->set_some_param( 13 );

хотя само выделение памяти произошло успешно. И как в данном случае бороться с ошибками? Неужели нужно писать:
My_Object * o = new My_Object();

// Вот в этой точке приведет к обращению по недоступному адресу.
o->set_some_param( 13 );
if( errno )
    // Ба, да ведь запись у нас не прошла. Что у нас в ТЗ записано?
    do_something_from_tz();
else
    // Работаем дальше...


Во что же тогда программирование превратиться?

СГ>Если, например, в ТЗ написано, что при недостаточном месте на диске надо предложить пользователю:

СГ>а) очистить диск, потом повторить операцию сохранения;
СГ>б) предложить сохранить на floppy/CD-RW/и т.д.
СГ>в) предложить отправить по электронной почте...
СГ>то это и делать.

Вопрос "Что делать?" должен быть понятен еще до написания кода (просто по определению). Меня интересует, как это делать. При наличии исключений я могу просто написать последовательность действий:
try
    {
        db_transaction_t trx( db_stream );
        db_stream << header << description << footer;
        trx.commit();
        
        // При возникновении исключения trx сам откатит транзакцию в своем деструкторе.
    }
catch( const db_exception & x )
    {
        // Обработка различных ситуаций: нет места, защита от записи, нет прав, отмонтированное устройство...
        process_db_exception( x );
    }


А что мне предлагается делать без исключений?
db_trx_id_t trx_id = db_stream.start_trx();
if( !errno )
    {
        db_stream << header;
        if( !errno )
            {
                db_stream << description;
                if( !errno )
                    {
                        db_stream << footer;
                        if( !errno )
                            {
                                db_stream.commit_trx( trx_id );
                                if( !errno )
                                    return 0;
                            }
                    }
            }
        
        int old_errno = errno;
        db_stream.rollback_trx( trx_id );
        errno = old_errno;
    }

process_db_error();


Речь идет об этом?
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[4]: Что вы предлагаете на замену эксепшенов?
От: Глеб Алексеев  
Дата: 21.11.05 12:08
Оценка: 4 (1)
Здравствуйте, eao197, Вы писали:

E>Спецификация исключений -- это только одна сторона медали.

E>Другая сторона -- это catch(...) или catch( const std::exception & ), ибо в противном случае игнорирования не получится -- исполнение прервется.
Исполнение прервется, если исключение будет брошено. В этом случае непойманные исключения действительно проявляются заметнее проигнорированных кодов возврата. Проблема в тех исключениях, которые не будут брошены при тестировании.

Я, видимо, недостаточно ясно сформулировал. Имелось в виду следующее:


///foo.cpp
void foo() {
  if ( judgement_day_has_come() ) {
    throw std::runtime_error("Приехали...");
  }
}

///bar.cpp
void bar() {
  foo(); // автор bar() плохо читал документацию/документации не было/забыл/ваш вариант,
         // но обработки исключения нет. Код компилируется и будет работать до самого Судного дня.
         // Как видим, игнорировать исключения очень даже можно, по-крайней мере, в С++
}

// а теперь то же самое с кодами возврата
enum status {
  status_ok,
  status_failure
};
status foo() {
  if ( judgement_day_has_come() ) {
    return status_failure;
  }
  return status_ok;
}

///bar.cpp
void bar() {
  foo(); // чем отличается клиентский код в случае игнорирования ошибки? ничем. 
}


К чему я веду? Что исключения очень полезны для отделения "нормального" кода от кода обработки ошибок, а также для передачи управления на несколько уровней выше при невозможности обработать ошибку в точке возникновения, но никак не заменитель головы программиста. Внимательность никто не отменял и видимо еще долго не отменит.
Re[4]: Что вы предлагаете на замену эксепшенов?
От: Глеб Алексеев  
Дата: 21.11.05 12:21
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>Нет, я говорил вот о чем:

А я — вот
Автор: Глеб Алексеев
Дата: 21.11.05
о чем .
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Что вы предлагаете на замену эксепшенов?
От: CrystaX Россия https://crystax.me/
Дата: 21.11.05 12:31
Оценка:
Здравствуйте, Глеб Алексеев, Вы писали:

ГА>Исполнение прервется, если исключение будет брошено. В этом случае непойманные исключения действительно проявляются заметнее проигнорированных кодов возврата. Проблема в тех исключениях, которые не будут брошены при тестировании.


Мы говорим, похоже, о разных вещах. Ты можешь игнорировать и исключение, и код ошибки, но только до того момента, пока она (ошибка) не произойдет. Но если ошибка все-таки произошла, то исключение ты "случайно" не пропустишь — только предприняв для этого явные действия. А вот код ошибки — запросто.

ГА>К чему я веду? Что исключения очень полезны для отделения "нормального" кода от кода обработки ошибок, а также для передачи управления на несколько уровней выше при невозможности обработать ошибку в точке возникновения, но никак не заменитель головы программиста. Внимательность никто не отменял и видимо еще долго не отменит.


Я с этим и не спорил.

На этом, думаю, взаимные объяснения можно считать завершенными.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[5]: Что вы предлагаете на замену эксепшенов?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 21.11.05 12:37
Оценка:
Здравствуйте, Глеб Алексеев

Теперь твоя точка зрения стала понятна. В Java как раз попытались побороться с игнорированием исключений, но, имхо, получили не меньше проблем, чем от которых избавились. Серьезное обсуждение этой темы здесь было: Checked exceptions... зло или добро?
Автор: mishaa
Дата: 16.07.05
.

ГА>К чему я веду? Что исключения очень полезны для отделения "нормального" кода от кода обработки ошибок, а также для передачи управления на несколько уровней выше при невозможности обработать ошибку в точке возникновения, но никак не заменитель головы программиста. Внимательность никто не отменял и видимо еще долго не отменит.


Ну дык...
В программировании без головы вообще делать не чего. Хотя, если брать, скажем, индусов...

А вот по поводу безопасности исключений если задуматься, то вообще голова кругом пойдет. Мне, например, интересно. В C++ много говорится о гарантиях безопасности (ну там базовая гарантия, сильная гарантия). А в других языках с исключениями (в том же Ruby, к примеру) от этом не упоминают. Из-за чего, спрашивается? В языках с GC нет таких пагубных последствий от исключений? Или просто их community еще до таких серьезных вопросов не доросло?
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[6]: Что вы предлагаете на замену эксепшенов?
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 21.11.05 12:56
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Что значит "неожиданная ситуация"? Это выражение означает "невозможно выполнить запрошенное действие".


Ничего неожиданного в этом нет. С самого начала известно, что соединение может разорваться в любой момент, да и денег на счете может быть меньше чем запрошено.
Re[6]: Что вы предлагаете на замену эксепшенов?
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 21.11.05 13:00
Оценка: -2 :)
Здравствуйте, eao197, Вы писали:

E>Во что же тогда программирование превратиться?


А Вы подумайте.

Если верить рекламе языков (Java, C#), то "программирование — это лёгкое и непринуждённое занятие". Обманыевает эта реклама, хотя бы пять процентов головного мозга напрягать всё-равно надо.
Re[6]: Что вы предлагаете на замену эксепшенов?
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 21.11.05 13:07
Оценка:
Здравствуйте, eao197, Вы писали:

E> В языках с GC нет таких пагубных последствий от исключений?


Единственное правильное использование ловли исключений — это чтобы в случае чего грамотно прибрать за собой.
При наличии автоматической сборки мусора, прибрать за собой — гораздо менее актуальная задача.
Re[2]: Что вы предлагаете на замену эксепшенов?
От: Шахтер Интернет  
Дата: 21.11.05 13:08
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, Сергей Губанов, Вы писали:


PD>Я не собираюсь предлагать что-то вместо эксепшн, но вот идею их я бы расширил. Сейчас — это просто уведомление о чем-то. Я бы добавил в них возможность исправления, если, конечно, возможно.


Это возможно на SEH-овских исключениях.
SEH поддерживает возобновление исполнения для некоторых типов исключений.
Весьма редко используемая фича.
Можно разреженные контейнеры делать, например, в которых память выделяется только по обращению к соотвествующей странице памяти.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.