Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Внизу у нас (в рамках примера с cloud) код, который работает с этой cloud file system, и знать про HTTP ничего не должен.
S>Конечно же должен. Потому что клаудная "FS" — это некий Web API. Который, естественно, отвечает нам HTTP-шными кодами. Например — 403 с подробностями "token expired", которые совершенно непонятны среднему слою, зато понятны верхнему — который знает, что нужно токен обновить и попробовать снова.
Так, давай по порядку.
До того, как мы добавили Cloud FS, все выглядело так
1. Верхний уровень. Получает от среднего (треш и угар) HTTPException, решает что в этом случае делать.
2. Средний уровень. Работает с HTTP, черт знает как, но работает. Иногда выбрасывает HttpException. Обращается к нижнему уровню для получения каких-то файлов.
3. Нижний уровень. Работает с ФС. Пока что у нас там или NTFS, или какая-то линуксовская ФС.
Откуда тут идут HTTPException ? Очевидно, только от среднего слоя. Не может нижний слой их генерировать. Никак не может.
Все так ?
Теперь вместо NTFS у нас некая CloudFS.
Ну если ты ФС, то будь добра вести себя как ФС. Собственно, даже не будь добра, а никуда не денешься. Потому что средний слой обращается к тебе как к ФС и не ждет от тебя никакого HTTP, равно как и FTP и т.д. Он работает по АПИ ФС, и только ошибки этого АПИ он может обрабатывать. Так что будь добра все свои HTTP/FTP проблемы решать сама, а в средний слой возвращать что-то связанное с ошибками файлов и потоков и тому подобным. IOException, например
Но не получилось. Иногда этот нижний слой выбрасывает XyzException, связанный с HTTP. Средний слой его не ждет и вообще-то обрабатывать не может. Поэтому они идет выше, в верхний слой, а это значит, что средний слой вообще-то потерпел неудачу — он вызвал нижний, а там необрабатываемая проблема. Значит, средний слой свое дело вообще не выполнил. Так что все верно, она попадает в верхний как неожиданное исключение. Просил средний слой какой-то файл ему дать, а в ответ — XyzException.
Короче, верхний слой должен ловить HttpException от среднего, именно там и идет работа с HTTP. А не от нижнего.
S>>>Нет. Никто там от С++ не наследовался. И подозревать причины нет — все ходы записаны, включая ход мысли отцов-основателей.
PD>>Допускаю. Равно как допускаю, что они неосознанно все же были под влиянием MSVC++. Не могли они его не знать.
S>Это очень странный ход рассуждений. Во-первых, с тем же успехом можно сказать, что они были под влиянием Pascal — ведь там тоже нет checked exceptions.
Ну в Pascal как он был вначале их нет вообще. Вроде как и в TurboPascal их не было, не помню точно. Вот в Delphi точно были.
>То есть наличие фичи откуда-то унаследовать можно; а вот унаследовать отсутствие фичи....
Вполне можно. Там ее не было, и тут не будет. Унаследовали отсутствие

А то, что она есть в параллельном проекте (Java) — нам не указ.
S>Во-вторых, в С++ исключения всё же входят в сигнатуру, хоть и не проверяются. В дотнете — нет, не входят. То есть "наследование" какое-то очень однобокое.
PD>>Тут будет, да. Но это особая ситуация. Произошло что-то непредвиденное.
S>Нет тут ничего особенного. Исключения и придуманы для "непредвиденных" ситуаций. Предвиденные неприятности принято обрабатывать явно.
checked exceptions и есть предвиденные неприятности, и их обрабатывают явно.
S>Вовсе не везде. В целом, конечно же, крайне полезно знать, что в некоторых местах NullPointerException возникнуть не может.
Если NPE может произойти, то оно произойдет. Если NPE произойти не может, оно все равно произойдет.
(C) моя перефразировка закона Мерфи.
S>Это всё работает только в плоских иерархиях вызовов. И совершенно никак не работает в коде на колбеках. Который, собственно, и является наиболее частоиспользуемым примером, когда мы контролируем "дно" и "крышу", а середину хотим куда-то делегировать.
Основная суть проблемы вот в чем. Ты доказываешь, что применение checked не панацея и приводишь примеры, когда они не очень успешно могут быть применимы. Я не спорю, не всегда все хорошо получится. Но зачем же, если нельзя обеспечить 100% успеха, заявлять, что это вообще никуда не годится ? Если во многих случаях это обеспечивает, что мы имеем меньше шансов забыть что-то важное, то почему этим не воспользоваться ? Пусть даже в других случаях это и не работает.
Вот тебе простой пример.
void read(char * filename){
FILE* f = fopen(filename, "rb");
// чтение
fclose(f);
}
написал и запустил . Работает как часы, пока файл есть. А если его вдруг не окажется, будет хоть и не исключение (это же С), но плохо будет. А я забыл проверку поставить.
void read(String filename) {
FileInputStream fis = new FileInputStream(new File(filename);
// чтение
close(fis);
}
Не компилируется. На FileInputStream диагностика unhandled exception FileNotFoundException. На close — IOException.
Иди-ка, автор, и подумай, что ты делаешь. А если файла нет ? А если закрытие не прошло почему-то ? Изволь подумать, что делать и код написать.
Ну и что тут плохого ? Бог с ними, с верхними и средними уровнями и колбеками, но тут-то что плохого ?