checked exceptions и Java

bastii

Давайте пофлудим
Просто интересно, что народ думает о сабже.

Dasar

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

Marinavo_0507

я о сабже не думаю совсем
а что это?

bastii

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

void saveString(Writer writer, String string) throws IOException {
writer.write(string);
}
Компилятор выдаст ошибку, если не написать throws IOException. Эта "фича" в Java называется checked exceptions.
Проблема следующая. Если задуматься, то checked exceptions нарушают саму концепцию исключений. Они позволяют разделить уровень обрабатывающий исключения и уровень, который их генерирует. Уровень, который работает между этими двумя, не интересуется исключительными ситуациями, так как на этом уровне их все равно не понятно как обрабатывать.

Dasar

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

bastii

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

Изначально реализации DataResource предполагает, что данные хранятся в памяти, пусть реализовано в классе DataResourceMemoryImpl, т.е. схема такая: загружаем с диска в DataResourceMemoryImpl, затем выполняем алгоритм и потом сохраняем на диск.
Теперь у меня объем данных вырос, и сразу все данные грузить не целесообразно. Я пишу реализацию DataResource, которая предполагает непрерывный доступ к диску. Т.е. реализую "ленивую" загрузку. Теперь в любой методе DataResourceDiskConnectedImpl могут просходить IO операции. Мне нужно добавить в методы throws someExceptions, но тогда их нужно добавить и в исходный интерфейс DataResource. Следовательно нужно добавить в методы реализующие алгоритм, в том числе и в doSmthWithData. Потом появляется реализация DataResource, когда идет подзагрузка данных их БД. Появляются еще всякие SQLException исключения. А что если не я писал код алгоритма, и он идет как отдельный пакет. Я не могу внести все эти изменения. Да и зачем? Понятно, что исключительный ситуации в IO никак не связаны с алгоритмом. Я буду обрабытывать их на более высоком уровне кода. Получается единственный выход, это в реализациях DataResource прятать все исключения в RuntimeException (это класс исключении компилятор не требует вносить в секцию throws). Но это решение добавляет проблемы с фильтрацие исключений в моем коде на высоком уровне (где я и хочу их обрабатывать). Теперь везде, где я хочу отловить какое-то специфичесое исключения я должен ловить RuntimeException и смотреть, что за исключение спрятано подним. Если не то, что меня интересует, то делать "ресроу". Все это делает мой код грязным. Короче появляются проблемы, бороться с которыми и призван механизм исключений.

bastii

Ну да, на сколько я знаю, позиция разработчиков .NET, что это слишком спорная концепция, чтобы навязывет ее все.м Ведь она должна реализовываться на уровне виртуальной машины, значит все многочисленные языки под .NET должны будут ее поддерживать.
Ну, а что про Java? Может кто знает лучше способ, чтобы решеать проблемы, что я описал в предыдущем посте.

6yrop

в C# этого нет, значит отцы из Microsoft тоже считают это лишним, они скорее всего продумывали это

6yrop

все многочисленные языки под .NET должны будут ее поддерживать
это почему?

bastii

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

rosali

Ну, а что про Java? Может кто знает лучше способ, чтобы решеать проблемы
Насколько я знаю Яву, исключения, наследованные от Exception должны присутствовать в этом списке, а исключения, наследованные от Error, можно не указывать. Так что если ты будешь наследовать все свои исключения от Error, то и проблемы никакой не будет.

bastii

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

Marinavo_0507

> Потом появляется реализация DataResource, когда идет подзагрузка данных их БД. Появляются еще всякие SQLException исключения.
А вот подумай сам: какая польза будет пользователю интерфейса DataResource от этого SQLException?
Он ведь использует generic-интерфейс, и понятия не имеет, что у некоторой реализации внутри есть какой-то SQL.
Что он сможет сделать с SQLException, если вдруг получит его?
Только вывести на stderr, не иначе.
Я бы предложил следующий вариант: сразу определить DataResourceException, и все низкоуровневые ошибки запаковывать туда.
Так хотя бы при грамотном проектировании пользователь сможет как-нибудь более содержательно обработать ошибку.
Вообще, эмпирический факт: программы на языках, в которых есть исключения, по жизни срут ими в stderr.
Ненавижу! Они делают это, даже если автор - это я
В Java по крайней мере виден список возможных исключений, которые туда попадут.
> А что если не я писал код алгоритма, и он идет как отдельный пакет. Я не могу внести все эти изменения.
А вот эта претензия легко обобщается. И показывает на то, что имхо является охрененным неудобством
известных мне OO-языков в плане повторного использования кода.
А именно.
Пусть есть библиотека А, некоторые классы которой реализуют интерфейс IA.
И пусть есть библиотека B, которая умеет работать с объектами, реализующими некий интерфейс IB.
Интерфейсы IA и IB фунционально похожи, может быть даже эквивалентны.
Но авторы у библиотек разные, поэтому интерфейса два, просто дважды реализовали одно и то же.
Я хочу использовать библиотеку B для работы с классами из библиотеки A.
Для любого класса, реализующего IA, я легко определю потомка, реализующего IB, но
1) классов, реализующих IA, много, заимеешься для всех определять потомков
2) если у нас есть экземпляр такого класса, никакой силой его не заставить притвориться, что он умеет IB.
То есть, малой кровью заставить совместно работать две библиотеки не получится.
Или я отстал от жизни, и эта проблема уже решена в рамках ОО-подхода?

Dasar

> Или я отстал от жизни, и эта проблема уже решена в рамках ОО-подхода?
Сгенерировать адаптеры - можно даже в рантайме.

Marinavo_0507

Это как?

bastii

просто наследовать код можно не только через стандартный механизм наследования, но и с помощью делегирования (или как это правильно называется, агрегирование?)

bastii

так ты все правильно уловил с проблемой в checked exceptions

bastii


> А что если не я писал код алгоритма, и он идет как отдельный пакет. Я не могу внести все эти изменения.
А вот эта претензия легко обобщается. И показывает на то, что имхо является охрененным неудобством
известных мне OO-языков в плане повторного использования кода.
А именно.
Вообще-то не в этом суть была, мне не нравиться сама идея менять там код.
А так, в Java как раз очень несложно получить исходный код из классов (ну или внести в классы изменения). В сравнении с C и x86 например.

Dasar

> Или я отстал от жизни, и эта проблема уже решена в рамках ОО-подхода?
Вообще-то эта проблема есть во всех языках, в том числе и естественных, а не только в ООП-е.
И проблема скорее терминологическая и возникает - когда мы одно и то же называем разными словами.

Dasar

1. прописываешь отношение эквивалентности между IA и IB
2. фиксируешь/специфицируешь какой наследник IB какому наследнику IA соответствует
на основе вышеприведенных утверждений генерируешь код адаптеров.

Marinavo_0507

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

bastii

Тут проблемав том, что все реализации ООП предпочитают не подниматься до очень высокого уровня. Зачем вводить понятия, которые редко используются и могут быть выражены чрез уже имеющиеся.

Chupa

> На русском языке я напишу: "далее в тексте считаем IA и IB взаимозаменяемыми понятиями".
ещё ни один холивор так не завершился, хотя суть у них та же:
разная точка зрения на похожие объекты

Dasar

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

Marinavo_0507

"любой индус" скорее всего быстро напишет сотню обёрток, и получит премию за рекордное количество строк за месяц

Dasar

> На русском языке я напишу: "далее в тексте считаем IA и IB взаимозаменяемыми понятиями".
> Ну или чуть посложнее, если это не полностью одно и то же, а частично.
> Почти так же просто это записывается в функциональных языках, по крайней мере без внешнего генератора.
Подскажи, пожалуйста, где можно взять функциональное описание, которое описывает эквивалентность Posix-а и WinApi.

Marinavo_0507

winelib и cygwin
настолько же в функциональном стиле, насколько оригинальные API

Dasar

> настолько же в функциональном стиле, насколько оригинальные API
т.е. для ФЯ - это большая проблема, что и Posix, и WinApi - не ФЯ?
зы
другие концепции в этом плане обычно менее требовательны.

Chupa

> другие концепции в этом плане обычно менее требовательны.
тогда реши свою задачу в рамках ООП на Java

Dasar

> тогда реши свою задачу в рамках ООП на Java
Моя задача - это про Posix и WinApi?
в рамках ООП на .Net-е она уже решена.
но меня интересовало, как на ФЯ записывается сложная(нетривиальная) эквивалентность.

Marinavo_0507

> Моя задача - это про Posix и WinApi?
> в рамках ООП на .Net-е она уже решена.
Под .Net есть объектно-ориентированный fork, sigaction, poll?
Вопрос риторический: такого быть не может в силу недостаточной объектно-ориентированности Posix (и WinAPI).
> но меня интересовало, как на ФЯ записывается сложная(нетривиальная) эквивалентность
грубо говоря, библиотечная функция принимает операции в виде аргументов-функций
для описания эквивалентности (точнее, вложения) нужно реализовать требуемые операции на основе имеющихся
это в простом случае
в сложном, у библиотеки будет функториальный интерфейс, и нужно будет отобразить
один интерфейс в другой, написав функтор
как это сделать, сразу не скажу, ни разу не пользовался в практических задачах, поэтому забыл, что вычитал в книжках

gopnik1994

самое тупое - это исключения, которые тебе не нужны и мешают, catch'ить и перевозбуждать в виде RuntimeException с соотв. сообщением
К счастью, это стандартное исключение можно возбуждать без объявления.
Оставить комментарий
Имя или ник:
Комментарий: