Re[8]: Result objects - все-таки победили Exceptions?
От: Pavel Dvorkin Россия  
Дата: 10.01.25 05:47
Оценка:
Здравствуйте, 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.
Иди-ка, автор, и подумай, что ты делаешь. А если файла нет ? А если закрытие не прошло почему-то ? Изволь подумать, что делать и код написать.

Ну и что тут плохого ? Бог с ними, с верхними и средними уровнями и колбеками, но тут-то что плохого ?
With best regards
Pavel Dvorkin
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.