Здравствуйте, Павел Кузнецов, Вы писали:
V>> Действиетльно. Ну, тебе виднее. Правда дотнетные и явовские приложение V>> которые с этой твоей точкой зрения не согласны наботают все же надежнее,
ПК>Надежнее, чем что? Если, чем C++ (делая догадки по остальным сообщениям ПК>в данной теме), то это просто неверно: они по определению не могут работать ПК>надежнее, чем их виртуальные машины, которые как раз на C++ и написаны.
Паша, извини, что вмешиваюсь, но а IT есть масса примеров построения надежных систем из ненадежных компонентов. Тебя же не удивляет reliability TCP, построенного поверх абсолютно unreliable IP?
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Cyberax,
C>> Явная спецификация исключений — это, ИМХО, большой плюс.
ПК>Как я понимаю, вопрос достаточно спорный... Это без труда обнаруживается простым запросом ПК>java checked exceptions, даже не содержащим ничего кроме самого ПК>термина:
Herb Sutter и Andrei Alexandrescu в книге C++ Coding Standards: 101 Rules, Guidelines, and Best Practices
пункт 75 Avoid exception specifications разделяют твой взгляд на вещи.
Sinclair,
V>>> Действиетльно. Ну, тебе виднее. Правда дотнетные и явовские приложение V>>> которые с этой твоей точкой зрения не согласны наботают все же V>>> надежнее,
ПК>> Надежнее, чем что? Если, чем C++ (делая догадки по остальным ПК>> сообщениям в данной теме), то это просто неверно: они по определению ПК>> не могут работать надежнее, чем их виртуальные машины, которые как раз ПК>> на C++ и написаны.
S> Паша, извини, что вмешиваюсь, но а IT есть масса примеров построения S> надежных систем из ненадежных компонентов. Тебя же не удивляет S> reliability TCP, построенного поверх абсолютно unreliable IP?
Good point. Значит, не по определению, а по факту.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, EvilChild, Вы писали:
EC>Здравствуйте, Павел Кузнецов, Вы писали:
ПК>>Cyberax,
C>>> Явная спецификация исключений — это, ИМХО, большой плюс.
ПК>>Как я понимаю, вопрос достаточно спорный... Это без труда обнаруживается простым запросом ПК>>java checked exceptions, даже не содержащим ничего кроме самого ПК>>термина:
EC>Herb Sutter и Andrei Alexandrescu в книге EC>C++ Coding Standards: 101 Rules, Guidelines, and Best Practices EC>пункт 75 Avoid exception specifications разделяют твой взгляд на вещи.
Есть большая разница между спецификаций исключений как в C++ и как в Java. В C++ исключения проверяются на этапе выполнения (в момент их возникновения), в Java -- на этапе компиляции.
Здравствуйте, dshe, Вы писали:
EC>>Herb Sutter и Andrei Alexandrescu в книге EC>>C++ Coding Standards: 101 Rules, Guidelines, and Best Practices EC>>пункт 75 Avoid exception specifications разделяют твой взгляд на вещи.
D>Есть большая разница между спецификаций исключений как в C++ и как в Java. В C++ исключения проверяются на этапе выполнения (в момент их возникновения), в Java -- на этапе компиляции.
В C++, вроде как, компилятор обязан обрамить вызов метода со спецификацией исключения try{}catch{}'ем.
Здравствуйте, eao197, Вы писали:
E>Поэтому в моем представлении приложение состоит из большого количества уровней. При выполнении какой-либо операции управление передается сверху вниз. При этом каждый уровень может: E>1) либо ожидать исключений чтобы предпринять попытку исправить ситуацию каким-либо иным образом (т.е. запустить другую последовательность транзакций); E>2) либо ожидать исключений чтобы очистить свои ресурсы, восстановить свое начальное/конечное/специальное состояние и отдать исключение наружу (т.е. предоставлять базовую гарантию по отношению к исключениям); E>3) либо ничего не ожидать и ничего не очищать (т.е. быть нейтральным по отношению к исключениям).
Очень хорошо. Я вот подумываю — возможно ли изобрести платформу, которая бы гарантировала поведение 2 встроенным образом? Пусть повышенные затраты — зато 100% уверенность в корректном результате.
Т.е. примерно вот так:
/// checked C# code samplestring s = "We are going to greet";
try
{
foreach(Person p in Holidayers)
{
s+= " " + p.Name + ","
}
}
catch
{
// перед входом в обработчик все объекты возвращаются в то состояние, которое они имели перед try.
s+= " everyone";
// поэтому теперь s = "We are going to greet everyone";
}
Console.WriteLn(s);
Насколько это реализуемо? Насколько это будет востребовано?
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Насколько это реализуемо?
В императивных языках с трудом. Причем с большим. Так как прийдется востаналивать не переменные, а состояние объектов. Для этого нужно или иметь автоматическое клонирование или вообще вести некий транзакционный механизм.
Дело бы упростилось бы если объекты были бы неизменяемыми. тогда достаточно было бы востановить ссылки как в тоем примере со строкой.
S>Насколько это будет востребовано?
Ну, это мечата очень многий. Декларативне тык-сызыть транзакции в коде. Это позволило бы писать очень устойчивый к сбоям код.
Вот только для этого нужно видимо язык специльно затачивать.
... << RSDN@Home 1.2.0 alpha rev. 591>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Sinclair wrote:
> Очень хорошо. Я вот подумываю — возможно ли изобрести платформу, > которая бы гарантировала поведение 2 встроенным образом? Пусть > повышенные затраты — зато 100% уверенность в корректном результате.
Встроенным — вряд ли. А вот обеспечить для программиста удобные методы
достижения этой цели — вполне.
Такое поведение называется strong exception guarantee в С++. Правда пока
за его соблюдением приходится следить руками, но сейчас комитет как раз
думает об усовершенствованиях в работе с исключениями.
Здравствуйте, Sinclair, Вы писали:
E>>2) либо ожидать исключений чтобы очистить свои ресурсы, восстановить свое начальное/конечное/специальное состояние и отдать исключение наружу (т.е. предоставлять базовую гарантию по отношению к исключениям);
S>Очень хорошо. Я вот подумываю — возможно ли изобрести платформу, которая бы гарантировала поведение 2 встроенным образом? Пусть повышенные затраты — зато 100% уверенность в корректном результате. S>Т.е. примерно вот так: S>
S>/// checked C# code sample
S>string s = "We are going to greet";
S>try
S>{
S> foreach(Person p in Holidayers)
S> {
S> s+= " " + p.Name + ","
S> }
S>}
S>catch
S>{
S> // перед входом в обработчик все объекты возвращаются в то состояние, которое они имели перед try.
S> s+= " everyone";
S> // поэтому теперь s = "We are going to greet everyone";
S>}
S>Console.WriteLn(s);
S>
S>Насколько это реализуемо?
Без особых проблем (на нормальных языках ), но чуточку многословно:
#include <iostream>
#include <string>
#include <stdexcept>
template< class T >
class value_guard_t
{
T & holder_;
T old_;
bool committed_;
public :
value_guard_t( T & holder )
: holder_( holder )
, old_( holder )
, committed_( false )
{}
~value_guard_t()
{
if( !committed_ )
holder_ = old_;
}
void
commit()
{
committed_ = true;
}
};
void
throwable_action( std::string & a )
{
a = "This is damaged content!";
throw std::runtime_error( "Something going wrong!" );
}
void
try_to_be_exception_safe()
{
std::string s( "We are going to greet" );
try
{
value_guard_t< std::string > s_guard( s );
throwable_action( s );
s_guard.commit();
}
catch( const std::exception & x )
{
std::cerr << "Oops! Exception: " << x.what() << std::endl;
s += " everyone";
}
std::cout << "And now: " << s << std::endl;
}
int
main()
{
try_to_be_exception_safe();
}
S> Насколько это будет востребовано?
Как я показал, в C++ такая возможность есть и она используется там, где это необходимо.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
VladD2 wrote:
> S>Насколько это будет востребовано? > Ну, это мечата очень многий. Декларативне тык-сызыть транзакции в > коде. Это позволило бы писать очень устойчивый к сбоям код. > Вот только для этого нужно видимо язык специльно затачивать.
Уже сделано два года назад в JBoss — там как раз есть декларативные
транзакции на графах объектов.
Здравствуйте, VladD2, Вы писали: VD>В императивных языках с трудом. Причем с большим. Так как прийдется востаналивать не переменные, а состояние объектов.
Совершенно верно. VD>Для этого нужно или иметь автоматическое клонирование или вообще вести некий транзакционный механизм.
Причем вроде как технологии-то сами по себе наработаны — в СУБД, к примеру, все это уже есть. Правда они ой как не любят частичных откатов. Написание кода типа моего примера должно было бы приводить к построению стека сэйвпоинтов. Впрочем, обработка исключений и сейчас штука небесплатная. VD>Дело бы упростилось бы если объекты были бы неизменяемыми. тогда достаточно было бы востановить ссылки как в тоем примере со строкой.
Не, так ничего полезного, скорее всего, не выйдет. Хотя мысль не лишена некоторой изящности. Я себе с трудом представляю систему, где все объекты immutable — тогда и ссылки-то восстанавливать будет негде VD>Ну, это мечата очень многий. Декларативне тык-сызыть транзакции в коде. Это позволило бы писать очень устойчивый к сбоям код. VD>Вот только для этого нужно видимо язык специльно затачивать.
Именно. Вот я и думаю, как это сделать . Что, собственно, нужно для такого языка? Грубо говоря, поддержка лога и трассировка всего подряд. С умным статическим анализом, который позволяет не хранить в лог лишнего в случае гарантии неотката...
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
E>void E>throwable_action( std::string & a ) E> { E> a = "This is damaged content!";
E> throw std::runtime_error( "Something going wrong!" ); E> }
E>void E>try_to_be_exception_safe() E> { E> std::string s( "We are going to greet" ); E> try E> { E> value_guard_t< std::string > s_guard( s );
E> throwable_action( s );
E> s_guard.commit(); E> } E> catch( const std::exception & x ) E> { E> std::cerr << "Oops! Exception: " << x.what() << std::endl; E> s += " everyone"; E> }
E> std::cout << "And now: " << s << std::endl; E> }
E>int E>main() E> { E> try_to_be_exception_safe(); E> } E>[/ccode]
S>> Насколько это будет востребовано?
E>Как я показал, в C++ такая возможность есть и она используется там, где это необходимо.
Эта возможность требует написания большого количества мусорного кода. Достаточно забыть сделать commit у одного гарда перед концом try-блока, как все сломается, причем плохо предсказуемым образом. Можно, конечно, привязять всех обороняемых к одному гарду, но это существенно усложнит жизнь всем. Кроме того, твой вариант полагается на корректное поведение конструктора копирования (я правильно понял?). Малейшая неточность в поведении этого конструктора — и мы неделями ловим причины сверхестественного поведения.
Не думаю, что нам так уж легко удастся написать универсальный guard для всех случаев.
Я-то думаю насчет встраивания такого паттерна в язык.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
E>>Как я показал, в C++ такая возможность есть и она используется там, где это необходимо. S>Эта возможность требует написания большого количества мусорного кода.
Надеюсь, под мусорным понимается не код самих guard-ов, а указание guard-ов внутри try/catch с последующим вызовом commit-а. Да, такое дело есть. Но, с другой стороны, это явное указание в коде того факта, что здесь мы пытаемся обеспечить гарантию безопасности по отношению к исключениями.
S> Достаточно забыть сделать commit у одного гарда перед концом try-блока, как все сломается,
Не думаю, что сломается.
S> причем плохо предсказуемым образом.
Наоборот, при первом же тестовом прогоне мы обнаружим у переменной неправильное (начальное) значение.
S> Можно, конечно, привязять всех обороняемых к одному гарду, но это существенно усложнит жизнь всем.
Не думаю. Можно сделать композитный guard. Что-то типа:
S> Кроме того, твой вариант полагается на корректное поведение конструктора копирования (я правильно понял?). Малейшая неточность в поведении этого конструктора — и мы неделями ловим причины сверхестественного поведения.
Именно так. Но я вообще слабо представляю себе попытку написать что-то сложное без предположения о корректности конструктора копирования.
S>Не думаю, что нам так уж легко удастся написать универсальный guard для всех случаев.
Имхо, это и не нужно. Для сложных случаев вполне можно использовать локальные классы:
S>Я-то думаю насчет встраивания такого паттерна в язык.
А я хотел показать, что такой паттерн, имхо, является одним из случаев паттерна RAII.
И при этом программист прекрасно понимает, какую цену он заплатит за обеспечение сильной гарантии. И если цена его не будет устраивать, он может выбрать иной путь работы в случае исключений. А вот если подобный паттерн встроить в язык, то не факт, что у разработчика подобный выбор будет вообще.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, EvilChild, Вы писали:
EC>Здравствуйте, dshe, Вы писали:
EC>>>Herb Sutter и Andrei Alexandrescu в книге EC>>>C++ Coding Standards: 101 Rules, Guidelines, and Best Practices EC>>>пункт 75 Avoid exception specifications разделяют твой взгляд на вещи.
D>>Есть большая разница между спецификаций исключений как в C++ и как в Java. В C++ исключения проверяются на этапе выполнения (в момент их возникновения), в Java -- на этапе компиляции.
EC>В C++, вроде как, компилятор обязан обрамить вызов метода со спецификацией исключения try{}catch{}'ем.
прекрасно откомпилится, но при вызове функции func2() программа благополучно скорится, поскольку исключение, возникшее в func1(), не может выйти за пределы func2(), так как она, объявлена как небросающая исключения в принципе. C++ компилятор не дает проверок на этапе компиляции, а генерит код, который делает проверки на этапе выполнения.
С другой стороны Java не позволяет скомпилировать такой код:
Здравствуйте, eao197, Вы писали: E>Надеюсь, под мусорным понимается не код самих guard-ов, а указание guard-ов внутри try/catch с последующим вызовом commit-а. Да, такое дело есть. Но, с другой стороны, это явное указание в коде того факта, что здесь мы пытаемся обеспечить гарантию безопасности по отношению к исключениями.
Конечно. Мы же рассматриваем прикладной код. S>> Достаточно забыть сделать commit у одного гарда перед концом try-блока, как все сломается, S>> причем плохо предсказуемым образом. E>Наоборот, при первом же тестовом прогоне мы обнаружим у переменной неправильное (начальное) значение.
Это только в том случае, если тестовый прогон действительно меняет значение переменной. И если мы действительно проверяем значение каждой переменной, а не только тех, которые попадают "наружу". Офф: У меня был великолепнейший случай бага с преобразованиями часовых поясов — пояс вычитался, вместо того, чтобы прибавляться. К сожалению, у нас GMT +6, и время получалось правильное. Только когда код стали тестировать при GMT +11 все и обнаружилось.
E>Не думаю. Можно сделать композитный guard. Что-то типа: E>
Именно это я и имел в виду.
E>Имхо, это и не нужно. Для сложных случаев вполне можно использовать локальные классы:
Ага. Ну то есть мусорный код, который еще и пишется в несимметричном основному коду месте. E>А я хотел показать, что такой паттерн, имхо, является одним из случаев паттерна RAII. E>И при этом программист прекрасно понимает, какую цену он заплатит за обеспечение сильной гарантии. И если цена его не будет устраивать, он может выбрать иной путь работы в случае исключений. А вот если подобный паттерн встроить в язык, то не факт, что у разработчика подобный выбор будет вообще.
А его и не надо. Этот выбор делается при выборе языка. Не знаю правда, что хуже — делать язык с уникальным синтаксисом, или наоборот — со строго совместимым. Во втором случае, программист может просто перекомпилировать куски своего кода с C# на "C##" и радоваться. Зато при этом есть риск запутаться — совершенно одинаковый код будет иметь различную семантику. Например, вот такое вот чудо на "C##" приведет совсем не к тому результату, который ожидался от C#:
public static void Fail()
{
string step = null;
try
{
a = "step1";
//blablabla
a = "step2";
throw new Exception("Shift happens");
}
catch(e)
{
Log.Trace(e, step);
throw;
}
}
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>>> Достаточно забыть сделать commit у одного гарда перед концом try-блока, как все сломается, S>>> причем плохо предсказуемым образом. E>>Наоборот, при первом же тестовом прогоне мы обнаружим у переменной неправильное (начальное) значение. S>Это только в том случае, если тестовый прогон действительно меняет значение переменной. И если мы действительно проверяем значение каждой переменной, а не только тех, которые попадают "наружу". Офф: У меня был великолепнейший случай бага с преобразованиями часовых поясов — пояс вычитался, вместо того, чтобы прибавляться. К сожалению, у нас GMT +6, и время получалось правильное. Только когда код стали тестировать при GMT +11 все и обнаружилось.
Твой аргумент ничего не доказывает. А наоборот, показывает необходимость тестирования в максимально приближенным к боевым условиям.
E>>Имхо, это и не нужно. Для сложных случаев вполне можно использовать локальные классы: S>Ага. Ну то есть мусорный код, который еще и пишется в несимметричном основному коду месте.
Так ведь локальный класс guard-а это уже предельный случай. А ведь можно пользоваться более удобными средствами, например: Change the Way You Write Exception-Safe Code — Forever
E>>А я хотел показать, что такой паттерн, имхо, является одним из случаев паттерна RAII. E>>И при этом программист прекрасно понимает, какую цену он заплатит за обеспечение сильной гарантии. И если цена его не будет устраивать, он может выбрать иной путь работы в случае исключений. А вот если подобный паттерн встроить в язык, то не факт, что у разработчика подобный выбор будет вообще. S>А его и не надо. Этот выбор делается при выборе языка.
Имхо, это слишком экстремальная точка зрения.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Sinclair, Вы писали:
S>Насколько это реализуемо? Насколько это будет востребовано?
ИМХО внутри одного метода это уже перебор, потому что не очень хорошо формализуемо. А вот на границах методов очень даже. Если внутри метода (помеченного атрибутом) произошло необработанное исключение, то нужно вернуть состояние нелокальных объектов обратно. Остается проблема неотслеживаемых автоматически изменений, но ее можно решить.
Здравствуйте, AndrewVK, Вы писали: AVK>ИМХО внутри одного метода это уже перебор, потому что не очень хорошо формализуемо. А вот на границах методов очень даже. Если внутри метода (помеченного атрибутом) произошло необработанное исключение, то нужно вернуть состояние нелокальных объектов обратно. Остается проблема неотслеживаемых автоматически изменений, но ее можно решить.
Об этом я тоже думал, хотя и не очень долго. Дело в том, чтобы писать как раз код первого типа (по приведенной выше классификации). Т.е. мы сначала пытаемся пойти по одной ветке, и в случае проблем откатываемся и пробуем другую.
Вот как раз попробование другой ветки (catch) требует некоторого предсказуемого состояния системы. Например, того, которое было до try. Поэтому у меня и появляется мысль сделать откат привязанным именно к try/catch.
Граница метода не очень хорошо в этом смысле подходит. Можно, конечно, использовать и ее, но тогда вместо
Здравствуйте, Sinclair, Вы писали:
S>Об этом я тоже думал, хотя и не очень долго. Дело в том, чтобы писать как раз код первого типа (по приведенной выше классификации). Т.е. мы сначала пытаемся пойти по одной ветке, и в случае проблем откатываемся и пробуем другую.
Можно, но во-первых это всегда можно оформить ввиде методов, а во-вторых управление транзакциями в таком случае лучше сделать явным.
S>Граница метода не очень хорошо в этом смысле подходит. Можно, конечно, использовать и ее, но тогда вместо
S>