sab123: (Default)
[personal profile] sab123
Зашла тут в http://plumqqz.livejournal.com/306627.html речь об исключениях. Что навело меня на размышления и формулировку того, чего мне не хватает для того, чтобы их нормально использовать. Нужны блоки типа таких:

exok {
// здесь всякие вызываемые функции могут бросаться исключениями
};

Вне таких блоков или все исключения должны молча (или опционально не молча, а с записью на stderr) посылаться нафиг, или же компилятор должен проверять, что никто не может ничего исключать (явный оператор throw - может). Вариант - те же блоки с явным указанием разрешенных типов исключений:

exok (ExcType1, ..., ExcTypeN) {
};

В-принципе, вместо exok можно нормально задействовать try. К которому опционально можно добавить catch-finally, а можно не добавлять, если все и без того нормально.

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

Date: 2012-08-28 10:20 pm (UTC)
From: [identity profile] vit-r.livejournal.com
Старая проблема молотка в руках ребёнка. Как только программисты получают в руки исключения, всё у них превращается в гвозди. Помнится, за исключения проповедовали, говоря, что программисты код возврата не проверяют. По мне, так канделябр значительно эффективнее.

все исключения должны молча (или опционально не молча, а с записью на stderr) посылаться нафиг,

Такой метод программирования называется Old maid (Schwarzer Peter - нем, или Акулина на русском). Все ошибки надёжно прячутся, а в дураках оказывается тот, кто не может их передать дальше. (Как правило, это пользователь)

Date: 2012-08-29 02:31 pm (UTC)
From: [identity profile] sab123.livejournal.com
Непойманное исключение - штука гораздо более страшная, чем непроверенный код ошибки. Если где-то что-то не сложилось в одном запросе, весь сервер не должен падать, или еще хуже, виснуть из-за поломанной синхронизации.

Date: 2012-08-29 05:15 pm (UTC)
From: [identity profile] vit-r.livejournal.com
Если сервер будет падать, то он упадёт один раз и на этапе тестирования.

Если сервер будет тихо под одеялом жрать говно, на костыли и подпорки уйдёт много человеколет.

Date: 2012-08-29 05:54 pm (UTC)
From: [identity profile] sab123.livejournal.com
Нет, конечно. Проблема с исключениями в том, что их невозможно внятно протестировать. Потому что неизвестно, какой где вызываемой фигне отчего вздумается бросить исключения. Поэтому падать оно будет в производственной обстановке и в самый неподходящий момент.

Date: 2012-08-29 08:07 pm (UTC)
From: [identity profile] vit-r.livejournal.com
Зависит от того, насколько правильно продумана вся система исключений.

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

Пардон, исключения для того и придуманы, чтобы подробно и чётко именно об этом и рапортовать.

Date: 2012-08-30 01:51 pm (UTC)
From: [identity profile] sab123.livejournal.com
На самом деле, нет. Хреново они рапортуют. И что хуже всего, если их в важные моменты не отлавливать, все портят.

Date: 2012-08-30 02:14 pm (UTC)
From: [identity profile] vit-r.livejournal.com
Хреново они рапортуют.

Где, кто и почему?

Date: 2012-08-30 02:58 pm (UTC)
From: [identity profile] sab123.livejournal.com
Ну так именно потому и хреново, что непонятно откуда. Вообще говоря, у приличного исключения есть три уровня, на которых оно рапортует:

1. Программе - это тип исключения.
2. Пользователю - это человеко-читаемое сообщение.
3. Программисту - это трассировка стека. Как вариант - вместо бросания исключения делать core dump, чтобы можно было искать подробности кривизны, которые теряются при раскручивании стека.

И с раскручиванием этой информации происходят всякие странные вещи. Ну, не говоря уже о том, что она может просто отсутствовать: например, в C++-ных исключениях трассировки стека нет (хотя с помощью glibc ее можно создать и поместить в текстовую часть).

При молчаливом раскручивании стека человеко-читаемая часть получается невнятной. Ну вот простой пример из реальности: открываем файл A.xml, и получаем сообщение, что не найден файл B.xsl. С каких, спрашивается хренов? При правильном подходе слой, ответственный за разбор файла, должен поймать это исключение, добавить к нему спереди сообщение "Файл A.xml содержит ссылку на файл DTD B.xsl," и отправить дальше.

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

На самом деле понятно, что все как в оригинальном посте по ссылке, не хотят с такими деталями возиться, и оставляют процесс на самотек, и он течет как говно.

Я тут, кстати, помаленьку экспериментирую на предмет как сделать такие вещи лучше. Вот например про добавление информации у меня есть идея примерно такая:

try ("File '%s' contains a link to DTD file '%s', failed to parse the DTD:", xmlfile, dtdfile) {
opendtd(dtdfile); ...
};

Чтобы значить эти сообщение при раскрутке стека автоматически собирались.

Date: 2012-08-30 04:10 pm (UTC)
From: [identity profile] vit-r.livejournal.com
 sub ASSERT() {
  my( $self, $condition, $error_msg ) = @_ ;

  unless( $condition ) {

    my  (   $package
          , $filename
          , $line
          , $subroutine
          ...
          ) =  caller(1) ;

    # NOTE: in graphical mode ....

    my $out = $self->get_out() ;

    my $disp_msg = "INTERNAL ERROR\n"
                   . "> " . $error_msg . "<\n"
                   . "\t\t in " . $line . " " . $package . "::" . $subroutine . "\n\n"
                   ; # 
    print $out  $disp_msg ;

    die  $disp_msg ;

  } # assert fails

} # ASSERT


$console->ASSERT( open (my $log_fh, ">$log_fl_name")   , "Cannot open a file \"" . $log_fl_name . "\"\n\t" . $!          ) ;
$console->ASSERT( -w $out_path                         , "Output path " . $out_path . " is not writeable."               ) ;
$console->ASSERT( not(defined(some_hash->{$mod_name})) , $some_name . " defined twice. Please remove the older version." ) ;
$console->ASSERT( $is_type_found                       , $header_str . "\n first string does not contain type."          ) ;

Date: 2012-08-30 04:20 pm (UTC)
From: [identity profile] sab123.livejournal.com
Не масштабируется на вложенные ошибки. Тут везде плоский один уровень, и каждый раз явная проверка ошибок, то есть то самое, чего пытаются избежать любители исключений. И вообще непонятно, чем оно лучше обычного "or confess()", который еще и стек оттрассирует.

Date: 2012-08-30 04:44 pm (UTC)
From: [identity profile] vit-r.livejournal.com
caller возвращает всё про стек. Другое дело, что в большинстве случаев это выводить не надо.

Ошибки нижнего уровня сидят в переменной $!
Но в большинстве случаев они тоже не нужны.

Вложенные ошибки не нужны, так как оно падает прямо там, где споткнулось.

Date: 2012-08-30 05:50 pm (UTC)
From: [identity profile] sab123.livejournal.com
> caller возвращает всё про стек. Другое дело, что в большинстве случаев это выводить не надо

Вообще говоря, из приведенного кода оно никак не следует. Видно, что caller() возвращает только последнюю точку вызова, а никак не стек. Или если оно что-то большее возвращает, то это большее выбрасывается.

Стек в большинстве случаев нужен для отслеживания ошибок в программе.

> Ошибки нижнего уровня сидят в переменной $!

Не про них речь. А про что-нибудь вроде

sub XXX {
...
$console->ASSERT( open (my $log_fh, ">$log_fl_name") , "Cannot open a file \"" . $log_fl_name . "\"\n\t" . $! ) ;
...
}
$console->ASSERT( &XXX() , "XXX failed") ;

Если файл не откроется, никто не будет знать, накой функции XXX понадобился этот файл.

> Вложенные ошибки не нужны, так как оно падает прямо там, где споткнулось.

В этом и недостаток по сравнению с исключениями. Исключения предполагают, что необязательно падать там, где споткнулось, а можно перехватить.

Date: 2012-08-30 08:13 pm (UTC)
From: [identity profile] vit-r.livejournal.com
Стек в большинстве случаев нужен для отслеживания ошибок в программе.


Если не знать, что это могут быть за ошибки.

Assert - это в чистом виде предположение, инвариант правильной работы.

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



Если файл не откроется, никто не будет знать, накой функции XXX понадобился этот файл.

Пардон. Если не открывается лог-файл, то это ситуация, когда программа делает харакири и администратор с программистом идут разбираться.

Стандартная ситуация, когда файл может не открыться - это просто проверка кода возврата и два варианта штатного выполнения.

Класс не найден - это исключение. Читали, нашли конец файла и начали бросаться исключениями - это порнография.

Исключения предполагают, что необязательно падать там, где споткнулось, а можно перехватить.

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

sub some_func() {
  ...
  my $some_structure = undef ;

  eval { 
       # тут дофига всего делается и с внешних ресурсов структура заполняется
  }; # eval

  if( $@ ) {
    $console->WARN( "ERRORS by reading некая структура в файле и куча чего ещё.\n"
                    . $@ # Тут будет сообщение от ASSERT со стеком и прочей нужной информацией
                    . "\n The некая структура " . $some_file_path ." is not processed"
                  );
    # REM die ... <- стандартно оно дохнет, но у нас есть стоящее ниже
    # REQ пустая структура - это уже проблемы пользователя. Отдаём как undef - пусть разбирается.
    
  } # if error

  return $some_structure ;

} # some_func()



И, если получатель результата начинает лезть в структуру, не проверив её на нуль, то это надо лечить канделябром.

Короче говоря, изначально в готовой программе все предположения валидируются через assert. Если при разборе ошибок оказывается, что это не исключение, а штатная ситуация, то код дополняется обработчиком этой ситуации и тестируется на эту обработку.

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

Date: 2012-08-31 06:05 pm (UTC)
From: [identity profile] sab123.livejournal.com
> Тут информация должна быть компактной и точной. В частности, данный вариант сообщает, в какой функции ошибка, вынимая минимальную и достаточную информацию из стека.

Этой информации достаточно только для очень примитивных программ. В программах сколько-нибудь заметного размера ее недостаточно. Ну вот в качестве простого примера, скажем есть у вас функция, которая получает имя файла как параметр, пытается открыть файл, и умирает при неудаче с сообщением "Can not open file '%$^&&*': no such file." Очевидно, что она получила кривое имя файла, но откуда и почему она его получила - без полного стека не разобраться.

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

>Класс не найден - это исключение. Читали, нашли конец файла и начали бросаться исключениями - это порнография.

Тут мы вроде согласились :-)

Вообще мой изначальный пост пытался выразить мысль, что бесконтрольно бросаться исключениями и надеяться, что они где-то правильно обработаются - безобразие.

Наука против магии

Date: 2012-08-31 07:15 pm (UTC)
From: [identity profile] vit-r.livejournal.com
Этой информации достаточно только для очень примитивных программ.

В наших подходах очень серьёзное отличие как раз в том, что я знаю, что нужно для правильного выполнения и проверяю инварианты.

То есть, вокруг всего стоят заборы, куда ошибка пройти не может.

В частности,

Для пользователя по-хорошему сообщения тоже должны раскрутиться как стек, и каждый фнукциональный уровень должен рассказать, что и почему он пытался делать, и в итоге каким образом ошибка произошла из действий пользователя.

Если пользователь задаёт файл на чтение - тут же идёт проверка того, что файл есть и чтение разрешено. Если нет, то не там где-то в глубине вывалится ошибка о невозможности открытия, а сразу уже в интерфейсе будет сказано, что файл не существует или нет прав доступа.

Абсолютно аналогично защищены функции внутри программы. Паранойя - наше всё.

Далее, если ошибка произошла, то это идёт в руки программисту и он первым делом делает предположения о возможных причинах. То есть он не гадает по стеку, а выдвигает гипотезу (о своей ошибке или не правильном предположении), после чего меняет программу, стоит новые заборы и пытается гипотезу проверить.

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

Последнее. Если программист где-то генерирует или получает имя файла, то assert будет стоять именно в том месте на том же уровне (может быть отлавливая ошибку в нижних и передавая её наверх). То есть, ошибка в лог уйдёт именно с того места, где известно, что это за файл и зачем он нужен.

Date: 2012-08-31 08:23 pm (UTC)
From: [identity profile] sab123.livejournal.com
У более настоящих коробочных программ программист не стоит за плечом у пользователя. А процесс проходит через местного сисадмина, человека или двух из поддержки, и только тогда попадает к программисту.

Date: 2012-08-31 08:41 pm (UTC)
From: [identity profile] vit-r.livejournal.com
1. Коробочные программы - это в наше время более исключения, чем правило.

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

3. Если программист не имеет понятия, почему его программа может упасть, гнать ссанными тапками из профессии.

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

Разъяснения

Date: 2012-08-30 08:45 pm (UTC)
From: [identity profile] vit-r.livejournal.com
0. Язык Perl

1. ASSERT - это не инструкция препроцессора и не функция, а метод класса с интерфейсом DiagnoseConsole

В данном случае он получает два параметра:
а) предположение программиста, на основании которого он пишет код
б) сообщение, необходимое для того, чтобы понять, почему это предположение не выполняется.


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

2. Интерфейс DiagnoseConsole может быть реализован любым удобным образом. В приведённом примере это вариант для консольного приложения. Для оконного или сервера действия могут быть совершенно другими.

Четыре примера использования, стоящие внизу, при этом не меняются. Просто в класс при создании передаётся другой объект $console. Или же объект подменяется в процессе выполнения. Скажем, консольное приложение открыло GUI и перенаправило диагностику в одно из окон.

Обычно я использую глобальный объект, просто чтоб не возиться. Но были проекты, где все (бизнес) классы реализовывали интерфейс DiagnoseConsoleUser

3. Объект $console может быть параметрируемым. То есть поведение метода ASSERT может меняться динамически. Это может быть также просто оболочка, куда реализация подсовывается динамически. Всё зависит от задач.

4. Строчка
die $disp_msg ;
- это вариант идеологически правильного поведения, позволяющего с наименьшей кровью получить правильно работающую программу.

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

Если ко мне приходит проджект менеджер со словами "Завтра сдавать клиенту, а нифига не работает! Нужно всё спрятать!", я молча ставлю впереди этой строчки решетку. В результате программа проскакивает мимо комментария и портится где-то внутри, не показывая ничего пользователю.

Если приходит Вася и говорит, что ASSERT валится в таком-то месте по неизвестной причине и разбираться с этим времени нет, я вставляю проверку на имя вызывающей функции и в этом особом случае вместо die и откидывания копыт, скажем, посылаю этому самому Васе мейл вместе с двумя мегабайтами хеша.

Идея в том, чтобы огородить "правильный путь", и получить ошибку сразу, если предположение, использованное при разработке программы оказалось не верным. Вот когда ошибка в рассуждениях и предположениях программиста выявлена (причём не закопана где-то в мегабайтах логов, а зримо выразилась в упавшей программе, можно принимать решение о том, исправлять ли ситуацию, игнорировать, оставить на потом или просто закрыть глаза.

Последнее: хотелось бы в журнале видеть стиль более вменяемый, чем стандартный.
Edited Date: 2012-08-30 08:55 pm (UTC)

Date: 2012-08-31 06:09 pm (UTC)
From: [identity profile] sab123.livejournal.com
1-3: я догадался :-)

4. confess() - это более правильный вариант die(). Который делает все то же самое, плюс выводит полный стек.

Стиль: самый вменяемый и есть. Причем вроде как нынче доступный только для исторических журналов, а в новых они дают только ужасные стили.

Date: 2012-08-31 07:23 pm (UTC)
From: [identity profile] vit-r.livejournal.com
confess() - это более правильный вариант die(). Который делает все то же самое, плюс выводит полный стек.

Жадность - плохое чувство, графомания - плохая привычка. Если информации слишком много, полезная содержательная часть утопает в мусоре.

По сути, в примере assert собирает всю нужную информацию, сохраняет её в предназначенном месте, после чего убивает испорченную часть. (Или не убивает, если у нас задача замести мусор под ковёр) Стек используется, но не весь, а только та часть, которая нужна. И очень-очень редко это полный стек до самых истоков.

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

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

Ещё одно добавление

Date: 2012-08-30 09:13 pm (UTC)
From: [identity profile] vit-r.livejournal.com
В mission critical исключения, как правило, запрещены. Потому как программа имеет право работать только правильно, а перекидывание туда-сюда исключений приводят к тенденции правильную работу только изображать.

Date: 2012-08-31 06:10 pm (UTC)
From: [identity profile] sab123.livejournal.com
Ну вот мой пост был как раз про то, что нужно делать с исключениями, чтобы сделать их пригодными для mission critical. Ибо польза-то в них фундаментально есть, но при бесконтрольном использовании вред перевешивает.

Date: 2012-08-29 09:02 am (UTC)
From: [identity profile] slonik-v-domene.livejournal.com
>Вне таких блоков или все исключения должны молча (или опционально не молча, а с записью на stderr)

Жесть какая. Вы представляете себе, что будет твориться с программой, которая при невозможности выделить ресурс будет тихо игнорировать этот факт продолжать работать дальше как-будто ничего не случилось?

>или же компилятор должен проверять,

Ну да, ну да. При наличии полиморфизма времени выполнения пытаться решить проблему во время компиляции. Да ради бога, собственно. Осталось совсем чуть-чуть: все без исключения методы должны иметь спецификацию исключений. О размере кода и количестве проблем при поддержке можно будет только гадать.
Edited Date: 2012-08-29 09:03 am (UTC)

Date: 2012-08-29 02:36 pm (UTC)
From: [identity profile] sab123.livejournal.com
> Вы представляете себе, что будет твориться с программой, которая при невозможности выделить ресурс будет тихо игнорировать этот факт продолжать работать дальше как-будто ничего не случилось?

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

>При наличии полиморфизма времени выполнения пытаться решить проблему во время компиляции.

От полиморфизма времени исполнения один вред.

>Осталось совсем чуть-чуть: все без исключения методы должны иметь спецификацию исключений.

В джаве - именно так. Поэтому в ней исключениями почти что можно пользоваться.

Date: 2012-08-29 02:45 pm (UTC)
From: [identity profile] slonik-v-domene.livejournal.com
>Ничего более худшего, чем от непойманного исключения. Как максимум - кору вывалит, которую потом можно будет изучить и найти, что и где не так.

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

>В то время, как от непойманного исключения программа молча загнется без коры.

Это откуда такая глупость?

>От полиморфизма времени исполнения один вред.

Предложите решение лучше полиморфизма времени исполнения.

>В джаве - именно так. Поэтому в ней исключениями почти что можно пользоваться.

Как раз в ней исключениями пользоваться практически невозможно. google -> "exception specification evil"

Date: 2012-08-29 03:03 pm (UTC)
From: [identity profile] sab123.livejournal.com
>Вы всерьез не вдупляете, что упасть программа может совсем не там, где исключение было тихо проигнорировано?

Может, конечно. Но обычно сразу.

>>В то время, как от непойманного исключения программа молча загнется без коры.
>Это откуда такая глупость?

Из практики.

>Предложите решение лучше полиморфизма времени исполнения.

Очевидно, что полиморфизм времени компиляции.

>Как раз в ней исключениями пользоваться практически невозможно. google -> "exception specification evil"

Зачем мне читать людей, у которых мозга нет?

Date: 2012-08-30 07:18 pm (UTC)
From: [identity profile] sab123.livejournal.com
Кстати, собрался и погуглил "exception specification evil". Оказывается, там люди говорят то же самое, что и я: что в C++ эти спецификации сделаны исключительно криво, без никакой пользы помимо вреда. А правильно они сделаны в джаве.

Date: 2012-08-30 03:35 pm (UTC)
From: [identity profile] vaddimka.livejournal.com
"посылать нафиг" - очень плохая идея, если брать сетевой сервис, то проще взять за правило, что любые асинхронные колбеки [от сетевой прослойки типа boost::asio] ничего никогда не кидают, у них всегда есть трай-кэтч блок и если что - они пишут в лог с FATAL что где-то что-то навернулось для такого-то клиента

заставить компилятор проверять код на отсутствие исключений - интереснее, но в реальной жизни даже банальное создание std::string это неизбежно один-два new
а каждый new может кинуть, поэтому в такой блок что ты хочешь засунуть можно будет только что-то весьма ограниченное

Date: 2012-08-30 04:14 pm (UTC)
From: [identity profile] sab123.livejournal.com
От неудачи new пусть все валится в кору. Тем более, что он кидает не собственно exception, а как его там, которое нужно перехватывать отдельно.

Вообще обрабатывать окончание памяти как исключение обычно бессмысленно. Единственное, что можно сделать - это запустить хитрый обработчик, который попытается поудалять всякие не очень нужные вещи, и потом продолжить как обычно. А так если память кончилась, то кончилась, все, пипец. Ну, теоретически можно порассуждать про "ах, память кончилась в результате попытки выполнения запроса, и вот сейчас мы этот запрос прервем, и все вернется в норму", но на практике так не бывает.

Date: 2012-08-30 05:00 pm (UTC)
From: [identity profile] vaddimka.livejournal.com
bad_allloc валится, он тоже унаследован от std::exception

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

Date: 2012-08-30 05:54 pm (UTC)
From: [identity profile] sab123.livejournal.com
Не, там еще есть отдельный обрабочик, который выдывается до того. И bad_alloc, если я правильно помню, идет не от exception, а от отдельного класса, у которого с exception общий предок - throwable. Как-то примерно так.

>nothrow отвечает только за код конкретной функции? вложенные функции его не интересут?

Это который пустой throw()? Вроде должен обещать, что и вложенные функции тоже не кидают.

Date: 2012-08-30 06:28 pm (UTC)
From: [identity profile] vaddimka.livejournal.com
в майкрософтовской как минимум реализации
class bad_alloc : public exception
т.е. от std::exception унаследован

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

Date: 2012-08-30 07:13 pm (UTC)
From: [identity profile] sab123.livejournal.com
Не может только пока нет требования явно объявлять все бросаемые исключения в декларации. А если такое требование добавить, как в жабе, то сможет.

С виртуальными функциями, кстати, вопрос уже решен: какой throw декларирован в родительском классе, такой и наследуется детьми. Они вроде его могут уменьшить, но не могут увеличивать.

January 2026

S M T W T F S
     12 3
45 6 7 8 9 10
11 12 13 14 151617
1819202122 23 24
25 262728293031

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 27th, 2026 01:47 pm
Powered by Dreamwidth Studios