Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2007.12.23;
Скачать: [xml.tar.bz2];

Вниз

Похоливарим еще? (java, checked exceptions)   Найти похожие ветки 

 
Юрий Зотов ©   (2007-11-16 07:05) [0]

Итак, известно, что ежели метод может выбросить исключение класса RuntimeException (что по дефолту предполагается для всех методов), то компилятор не потребует ни throws в заголовке метода, ни обязательного try-catch внутри него. Обрабатывать такое исключение внутри метода, или пропустить его выше - это решение отдается на откуп программисту.

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

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

Как уже отмечалось, та же стратегия принята и в джаве, но только для исключений, принадлежащих семейству RuntimeException. Для прочих же исключений дело обстоит несколько иначе. Мы не можем просто так написать следующее:
public void method() {
 ...
 throw new Exception("Ошибка"); // Возбуждение исключения
 ...
}

потому что компилятор тут же потребует одно из двух:
- либо чтобы возбужденное нами же исключение было обработано тут же внутри метода;
- либо чтобы в заголовок метода была добавлена фраза throws Exception (которая информирует, что этот метод может возбуждать исключения семейства Exception).

Рассмотрим оба варианта подробнее.

Вариант первый - обработка возбужденного мною же исключения тут же внутри метода. В общем-то, это чушь. Уж если я сам возбуждаю исключение, то вполне понятно, что я умышленно хочу именно передать его наверх и обрабатывать его здесь же мне не нужно (хотя Игорь вчера приводил код какого-то хитрого алгоритмизатора, который использовал raise фактически как goto, но мы таких суперпрограммистов рассматривать не будем, ограничимся нормальными).

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

Вариант логичный. Но неудобный. Представим себе сторонний класс (или интерфейс), в котором объявлен какой-то метод. Я в своем классе этот метод перекрываю (или реализую). Изменить объявление метода, добавив туда throws, конечно, нельзя. Поэтому, если в моем коде мне по каким то причинам нужно возбудить исключение, то я обязан тут же его и обработать, а передать его наверх у меня нет никакой возможности, хотя именно это мне и нужно! И тогда весь смысл собственноручного возбуждения исключения пропадает полностью!

Теперь вопрос - а на фига так сделано? Ну почему было не оставить нормальную концепцию обработки исключений - как RuntimeException, как в Delphi? Зачем потребовался такой выпендреж? Ради строгости языка? Чтобы подстраховать неумелого программера, заодно подрезав и всех остальных? То есть - мыши плакали, кололись, но продолжали есть кактусы?

Или я чего-то не понимаю?


 
Канадец   (2007-11-16 08:03) [1]

Понятно, что вариант "сам выбросил, сам поймал" это не то, что имели ввиду имплементаторы данной концепции. Т.е. остаётся второй вариант...

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


> Представим себе сторонний класс (или интерфейс), в котором
> объявлен какой-то метод. Я в своем классе этот метод перекрываю
> (или реализую). Изменить объявление метода, добавив туда
> throws, конечно, нельзя. Поэтому, если в моем коде мне по
> каким то причинам нужно возбудить исключение, то я обязан
> тут же его и обработать, а передать его наверх у меня нет
> никакой возможности, хотя именно это мне и нужно! И тогда
> весь смысл собственноручного возбуждения исключения пропадает
> полностью!


А теперь посмотрим на эту проблему с другой стороны.
Пользователь стороннего класса (или интерфеса) при вызове данного метода должен чётко предствлять, что в произойдёт в результате. Результатов возможно два (краш приложения рассматривать не будем, оставим это китайцам:) ):  метод либо выполнится, либо в результате работы метода возникнет исключение. С первым вариантом всё хорошо. А вот со вторым... Хорошо, когда мы имеем дело с задокументированной .NET Framework библиотекой. Пошёл себе на MSDN, а там this method throws the following exceptions. Всё чётко и понятно. А что делать с нерадивыми товарищами, которые эксепшионы плюют, а упоминать про них в документации забывают?

Дальше больше.... допустим идеальный вариант. Есть некий, хорошо задокуменированый класс с виртуальным методом, который чётко в документации указывает исключения какого рода он может порадить. Дальше следуя Вашему второму варианту появляется некто, кто пишет наследника, переопределяет данный метод и плюёт исключение, которое нигде не упоминается в описании базового класса. Вопрос: я, как пользователь базового класса, какие исключения должен ожидать от этого метода?

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


 
Kolan ©   (2007-11-16 08:46) [2]


> а упоминать про них в документации забывают?

Смотреть в код. Это вообще не аргумент имхо, если нормальный производитель класса, то документация будет...


 
Юрий Зотов ©   (2007-11-16 08:49) [3]

> Канадец   (16.11.07 08:03) [1]

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

Вот Вы говорите: "А что делать с нерадивыми товарищами, которые эксепшионы плюют, а упоминать про них в документации забывают"?

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

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

А знаете, что тогда делает этот товаришч? А он берет - и выбрасывает задокументировнный эксепшн. Но с совершенно другим смыслом. И этот новый смысл тоже не документирует. А компилер он обманул.

И что получается? Если бы этот товаришч не был вынужден пороть такую фигню, а имел возможность выкидывать произвольные исключения, то по смыслу своей ошибки он бы выбросил исключение наиболее подходящего класса. Ну, например, ConvertException ("Ошибка преобразования Васи в Петю"). И для Вас, как для его пользователя, все было бы информативно и понятно.

А поскольку товаришч вынужден-таки фигню пороть, то Вы получаете что-то типа ClassNotFoundException("Ошибка преобразования Васи в Петю"). И начинаете судорожно соображать, какое же отношения имеет ненайденный класс к преобразованию Васи в Петю? Лезете в документацию - да, такой эксепшн есть, все нормально. Но при чем тут Вася с Петей - загадка.

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


 
Однокамушкин   (2007-11-16 09:12) [4]


> Канадец   (16.11.07 08:03) [1]
> Дальше больше.... допустим идеальный вариант. Есть некий,
>  хорошо задокуменированый класс с виртуальным методом, который
> чётко в документации указывает исключения какого рода он
> может порадить. Дальше следуя Вашему второму варианту появляется
> некто, кто пишет наследника, переопределяет данный метод
> и плюёт исключение, которое нигде не упоминается в описании
> базового класса. Вопрос: я, как пользователь базового класса,
>  какие исключения должен ожидать от этого метода?

Нехорошо, конечно... Но, с другой стороны: есть у меня, например, базовый класс TStream для потока... От него порождены TFileStream, TResourceStream и TSocketStream, которые, понятно, работают совершенно с разными источниками данных и поэтому сталкиваются с совершенно разными ошибками... Ну и что, методы базового класса должны учитывать все возможные исключения, что ли? А если появится новый источник данных с новыми типом исключений? Или надо предусмотреть одно исключение на все случаи жизни? Но тогда обработка этих исключений будет сильно затруднена... В общем, я согласен с Юрием


 
Bishop   (2007-11-16 09:25) [5]

Юрий Зотов ©   (16.11.07 07:05)

В головах она разруха то, а не в клозетах. Зачем на клозет сетуете по чем зря?


 
Юрий Зотов ©   (2007-11-16 09:28) [6]

> Bishop   (16.11.07 09:25) [5]

Спасибо за очень полезное, информативное и хорошо обоснованное мнение.


 
mephasm   (2007-11-16 09:40) [7]


> Представим себе сторонний класс (или интерфейс), в котором
> объявлен какой-то метод. Я в своем классе этот метод перекрываю
> (или реализую). Изменить объявление метода, добавив туда
> throws, конечно, нельзя. Поэтому, если в моем коде мне по
> каким то причинам нужно возбудить исключение, то я обязан
> тут же его и обработать, а передать его наверх у меня нет
> никакой возможности, хотя именно это мне и нужно! И тогда
> весь смысл собственноручного возбуждения исключения пропадает
> полностью!


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


 
mephasm   (2007-11-16 09:48) [8]

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


 
Юрий Зотов ©   (2007-11-16 09:53) [9]

> mephasm   (16.11.07 09:40) [7]

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


В самом деле? А если не объявлен?
"Как правило" - это, конечно, сказано сильно. Но только сказано.

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

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

========================

Более сильные и разумные аргументы имеются, господин Бишоп?


 
Anatoly Podgoretsky ©   (2007-11-16 09:55) [10]

> Юрий Зотов  (16.11.2007 09:53:09)  [9]

В корзину, но на всех идиотов корзин не хватит.


 
mephasm   (2007-11-16 10:00) [11]

Юрий Зотов ©   (16.11.07 09:53) [9]

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


 
Юрий Зотов ©   (2007-11-16 10:09) [12]

> mephasm   (16.11.07 10:00) [11]

А можно без болтологии? И без "как правило". И без голословных заявлений?

Вы говорите, она у меня есть - ну так или покажите ее, или помолчите.


 
Romkin ©   (2007-11-16 10:13) [13]

Стоп. Разве нельзя действительно объявить потомка и выбрасывать его?
Или выбросить потомка RuntimeException?


 
mephasm   (2007-11-16 10:31) [14]

Юрий Зотов ©   (16.11.07 10:09) [12]
Пожалуйста.

Посмотрите, как это реализовано, к примеру, в JAXP. JAXP, это интерфейс, который реализуют различные XML парсеры.
Метод parse SAX парсера выбрасывает SAXException.
Это может быть SAXParseExcepiton, в случае когда анализируемый XML не валиден и какой-либо другой эксепшн, связанный например с неправильной конфигурацией парсера (покопайтесь в исходниках парсера xerces, они открыты).
Если мы только проверяем XML на валидность, мы можем явно написать
            try
            {
             parser.parse(inputXML, handler);
            }
            catch(SAXParseException e)
            {
             // report error
            }

Все остальные исключения перебрасываются дальше.
И это будет работать. Не понимаю в чем вы видите проблему.


 
Юрий Зотов ©   (2007-11-16 10:35) [15]

> Romkin ©   (16.11.07 10:13) [13]

Приведу пример, чтоб все стало ясно. Есть метод:
public void method()  {
...
}

Тут не задекларировано ничего, поэтому при перекрытии этого метода можно выбросить только RuntimeException (или потомка RuntimeException). Допустим, перекрытый метод работает с файлом - то есть, возможно IOException. Его и надо выбрасывать - но нельзя. Все, что тут можно сделать, это переопределить исключение:

public void method()  {
 try {
   ...
 } catch (IOException e) {
  throw new MyRuntimeException(...)
 }
}

Согласись, что подмена исключения - это кривовато как-то. За уши притянуто - лишь бы только обойти ограничение компилятора.

Второй вариант. Пусть перекрываемый метод что-то декларирует:
public void method() throws SomeException {
 ...
}

В этом случае можно выбросить SomeException (либо его потомка) или RuntimeException (либо его потомка). А у меня, как уже говорилось, возникает IOException - и я снова вынужден подменять исключение. Снова кривизна, снова притягивание за уши.

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


 
Юрий Зотов ©   (2007-11-16 10:40) [16]

> mephasm   (16.11.07 10:31) [14]

> Не понимаю в чем вы видите проблему.

Напишите потомка парсера, перекройте его метод parse и попробуйте выбросить из него... ну, к примеру, SQLException. Увидите.


 
Сусл ©   (2007-11-16 10:41) [17]


>  [13] Romkin ©   (16.11.07 10:13)
> Стоп. Разве нельзя действительно объявить потомка и выбрасывать
> его?
> Или выбросить потомка RuntimeException?

+1
присоединяюсь к вопросу.

------------
2ЮЗ. По теме.
Я думаю, что то, как сделано в java очень хорошо. Мне этого очень не хватает в delphi.

Почему?
1. throws - это инструмент документирования. По моему мнению throws ничем не отличается по вкладу в документацию от списка параметров, скажем.
2. Это выводит на чистую воду ленивых кодеров. Сравни 2 сценария. Ты делаешь стат. тестирование (просматриваешь код) за Ваней, и выщишь примерно ткой вызов (синтаксис точный не помню):

 
SomeMethodCodedByYoryZotov();


Твоя мысль: а все ли Ваня учел? Где обработка исключений? Здесь, выше? Вот же ведь лапух, забыл. Ага ну давай теперь пользователю выводить сообщение о том, что в каком-то там классе хибернейта, что-то там глюкнолось. Ан нет, выше он обработал, молодец. Стоп! А где же я остановился? О! Я остановился на мысле о пиве! Пора домой!

try {
  f();
}
catch() {
обработка
}


Смотришь на такой код и видишь (вернее точно знаешь!) сразу, что Ваня не может не обработать искючение!

Резюм - контроль за кодом выше при существовании сабжевой фичи.


 
Romkin ©   (2007-11-16 10:47) [18]

Юрий Зотов ©   (16.11.07 10:35) [15] Угу. Идею понял.
Но подозреваю, что когда пишешь конкретного предка, ты все-таки предполагаешь, что будет, и пишешь нужный тип.
То есть, тут явно пытаются заставить тебя делать так, чтобы твоя иерархия классов возбуждала исключения только твоего типа, если, конечно, ты не предусмотрел орлиным взором иное.
Вопрос в том, почему, когда перекрываешь метод, нельзя определить исключения?


 
Romkin ©   (2007-11-16 10:47) [19]


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

Мда. Глупый вопрос...


 
Romkin ©   (2007-11-16 10:50) [20]


> Смотришь на такой код и видишь (вернее точно знаешь!) сразу,
>  что Ваня не может не обработать искючение!

Угу. Смотришь код Васи, и видишь обработку вроде такой:
try {
 f();
}
catch() {}

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


 
Сусл ©   (2007-11-16 10:54) [21]

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

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

Есть еще агрегация. Да мало ли чего. Вот я тебе очень советую почитать GoF "Паттерны проектирования". Я знаю, что многие относятся к паттернам отрицательно - типа я и сам все знаю, и вообще паттерны - это мантра, а мы сами думать умеем. В чем-то я даже могу согласиться с таким мнением, но далеко не во всем. Паттерны нужно знать, чтобы мыслить шире, а не только наследованием.

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


 
Сусл ©   (2007-11-16 10:55) [22]


>  [20] Romkin ©   (16.11.07 10:50)
> Что-то мне все больше кажется, что java рассчитывает на
> программистов, мягко сказать, крайне невысокой квалификации
> :(


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


 
Юрий Зотов ©   (2007-11-16 10:57) [23]

> Romkin ©   (16.11.07 10:47) [18]

> когда пишешь конкретного предка, ты все-таки предполагаешь,
> что будет, и пишешь нужный тип.

Однокамушкин приводил пример. Пишу я Stream. Потомков у него может быть вагон и каждый работает со своим хранилищем данных.
FileStream - это IOException
BlobStream - это SQLException
SocketStream - это какой-нибудь ConnectException.

И т.д. Непредсказуемо. И что мне тогда писать в своем стриме-предке? Остается только одно - общий Exception, больше делать нечего. Конкретика исчезла.

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


 
Сусл ©   (2007-11-16 11:00) [24]


> [23] Юрий Зотов ©   (16.11.07 10:57)
> > Romkin ©   (16.11.07 10:47) [18]
>
> > когда пишешь конкретного предка, ты все-таки предполагаешь,
> > что будет, и пишешь нужный тип.
>
> Однокамушкин приводил пример. Пишу я Stream. Потомков у
> него может быть вагон и каждый работает со своим хранилищем
> данных.
> FileStream - это IOException
> BlobStream - это SQLException
> SocketStream - это какой-нибудь ConnectException.
>
> И т.д. Непредсказуемо. И что мне тогда писать в своем стриме-предке?
> Остается только одно - общий Exception, больше делать нечего.
> Конкретика исчезла.
>
> А если б было можно, я бы не писал ничего. И пусть потомки
> возбуждают, что им угодно.

Э... а как прикажешь вести себя классу, который использует конкретных потомков Stream через интерфейс Stream? Т.е. путь живет в состоянии неизвестности - какое там ичключение может быть, что ему делать?


 
Romkin ©   (2007-11-16 11:01) [25]


> Возможно, Роман, ты и прав. И в этом нет ничего постыдного
> для программиста java. Задача любого программиста писать
> быстро, качественно и выдавать решения, соответствующие
> задачи. И любые методы, которые этому способствуют приемлемы.
>

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


 
Игорь Шевченко ©   (2007-11-16 11:01) [26]


> Однокамушкин приводил пример. Пишу я Stream. Потомков у
> него может быть вагон и каждый работает со своим хранилищем
> данных.
> FileStream - это IOException
> BlobStream - это SQLException
> SocketStream - это какой-нибудь ConnectException.


Эта..я Java плохо знаю, в связи с чем вопрос - а что, в throws можно объявлять только явные типы исключений, то есть, общего предка типа MyStreamException объявить нельзя ? Или исключения не наследуются ?


 
Сусл ©   (2007-11-16 11:02) [27]


> То есть уровень вхождения в язык довольно низок, а вот чтобы
> написать нечто существенное...

да так в любом языке :)


 
Romkin ©   (2007-11-16 11:02) [28]


> Э... а как прикажешь вести себя классу, который использует
> конкретных потомков Stream через интерфейс Stream? Т.е.
> путь живет в состоянии неизвестности - какое там ичключение
> может быть, что ему делать?

А что ты делаешь в Delphi? Я - обычно ничего :)


 
Сусл ©   (2007-11-16 11:02) [29]


>
> Эта..я Java плохо знаю, в связи с чем вопрос - а что, в
> throws можно объявлять только явные типы исключений, то
> есть, общего предка типа MyStreamException объявить нельзя
> ? Или исключения не наследуются ?

я тоже плохо знаю, но предка обявить можно :)


 
Сусл ©   (2007-11-16 11:02) [30]


> А что ты делаешь в Delphi? Я - обычно ничего :)

Ну это ты :)


 
Romkin ©   (2007-11-16 11:08) [31]


> Ну это ты :)

А ты перехватываешь? Я обычно пользователю показываю :) Если в потомке Stream случилось что-то - это, скорее всего, требует вмешательства извне.
Вопрос в том, что и эксепшен я не объявляю... Нафига?
Тут ведь идея какая: либо ты знаешь, что тебе нужно перехватить исключение, либо нет. Если знаешь - перехватываешь, если нет - все все равно будет работать.


 
Romkin ©   (2007-11-16 11:12) [32]

Игорь Шевченко ©   (16.11.07 11:01) [26]

> Эта..я Java плохо знаю, в связи с чем вопрос - а что, в
> throws можно объявлять только явные типы исключений, то
> есть, общего предка типа MyStreamException объявить нельзя
> ? Или исключения не наследуются ?

Можно. И потомок будет вынужден перехватывать, например, IOException и возбуждать вместо него потомка MyStreamException. Я об этом уже замечание написал, обрати внимание.
Вопрос еще в том, что надо не упустить, и предусмотреть в предке этот MyStreamException, а это требует хорошего планирования, можно сказать, сразу всей иерархии.
Так что на мой взгляд, такой подход действительно делает построение иерархических структур в java более сложным делом, чем в Delphi, например.
И Сусл в [21] правильно заметил, что, повидимому, должен быть другой подход (подозреваю, что через интерфейсы).


 
Игорь Шевченко ©   (2007-11-16 11:14) [33]

Romkin ©   (16.11.07 11:12) [32]


> Можно. И потомок будет вынужден перехватывать, например,
>  IOException и возбуждать вместо него потомка MyStreamException


Это как-то противоречит принципам ООП о скрытии деталей реализации ?


 
Игорь Шевченко ©   (2007-11-16 11:20) [34]

Кстати, об ООП - не могу удержаться, чтобы не привести цитату:

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

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

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


 
Сусл ©   (2007-11-16 11:22) [35]


> [34] Игорь Шевченко ©   (16.11.07 11:20)

+1


 
@!!ex ©   (2007-11-16 11:23) [36]

> [34] Игорь Шевченко ©   (16.11.07 11:20)

+1

Однако примеры Юрия не подразумевают сложную иерархию.
Тот же TStream имеет всего пару уровней наследования, однако проблему это не решает.


 
Игорь Шевченко ©   (2007-11-16 11:27) [37]

@!!ex ©   (16.11.07 11:23) [36]


> Однако примеры Юрия не подразумевают сложную иерархию.
> Тот же TStream имеет всего пару уровней наследования, однако
> проблему это не решает.


А скажи мне пожалуйста, за каким бесом пользователю Stream надо знать, что произошло исключение связанное с поведением конкретного наследника Stream ?
Полиморфизм в чистом виде, что ли ? :)


 
mephasm   (2007-11-16 12:10) [38]

Про nested exceptions слышали?

public void startElement (String name, AttributeList attrs)
throws SAXException {
try
{
 if (name.equals("SCHEDULE"))
 {
  this.ParseStartSchedule(attrs);
  return;
 }

 return;
}
catch (IOException e)
{
 throw new SAXException("I/O error: " + e.toString(), e);
}
catch (ScheduleParseException e)
{
 throw new SAXException("ScheduleParseError" + e.toString(), e);
}
}


 
mephasm   (2007-11-16 12:11) [39]

mephasm   (16.11.07 12:10) [38]

Это к
Юрий Зотов ©   (16.11.07 10:40) [16]


 
mephasm   (2007-11-16 12:14) [40]

отлов соответственно такой
catch (SAXException e)
{
 //...
}
catch (IOException e)
{
 //...
}


 
Romkin ©   (2007-11-16 12:27) [41]

mephasm   (16.11.07 12:14) [40]
Это что, способ нае... компилятора? То есть объявлено у тебя в заголовке SAXException, порождаешь ты именно его, а перехватывать надо IOException? Та вторая, я вижу, как SAXException не перехватится?
Прикольно :)


 
Юрий Зотов ©   (2007-11-16 12:50) [42]

> Сусл ©   (16.11.07 10:54) [21]

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

Нет , Дима, обозначенная мною проблема (невозможность выбросить исключение иного типа в потомке) является прямым следствием другого - ограничений, существующих в языке (причем ограничений, ИМХО, искусственных). Не будь этих ограничений - не было бы и никаких проблем. Хоть наследуйся, хоть агрегируйся, хоть еще что хошь делай. Пример - хоть та же Delphi.

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

Что бы я хотел видеть? Вот что.

1. Соглашение о том, что любой метод может выбросить любое исключение.

2. Требование компилятора о том, что все реально выбрасываемые методом исключения должны декларироваться в его заголовке (как оно сейчас и есть).

3. При замещении метода его заголовок наследуется, но кроме списка реально выбрасываемых исключений (который в потомке имеет право быть и таким же, и другим, но в любом случае должен удовлетворять п.2).

И все проблемы сняты. И с документированностью тоже все ОК. Чем плохо?


 
Игорь Шевченко ©   (2007-11-16 12:52) [43]


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


Юра, тебе не кажется, что две части этой фразы противоречат друг другу ?


 
Romkin ©   (2007-11-16 12:53) [44]


> 3. При замещении метода его заголовок наследуется, но кроме
> списка реально выбрасываемых исключений (который в потомке
> имеет право быть и таким же, и другим, но в любом случае
> должен удовлетворять п.2). И все проблемы сняты. И с документированностью
> тоже все ОК. Чем плохо?

Хм. Вот пользуешь ты где-то предка, метод его вызываешь, исключения перехватываешь. А вместо него приходит потомок, с другим списком исключений. И куда деваться?


 
Юрий Зотов ©   (2007-11-16 13:07) [45]

> mephasm   (16.11.07 12:10) [38]

>...
>catch (IOException e)
>{
> throw new SAXException("I/O error: " + e.toString(), e);
>}

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

Однако же, задачу Вы не решили, даже и с костылями. Я не просил Вас перехватывать IOException, это задачка для младшего ясельного возраста. Я просил выкинуть IOException из перекрытого метода parse. Хоть c nested, хоть как угодно. А уж потом говорить о том, кому остается плакать.

Или не говорить совсем. А сразу начинать плакать.


 
Mystic ©   (2007-11-16 13:08) [46]

> Игорь Шевченко ©   (16.11.07 11:20) [34]

Автор = ?


 
Игорь Шевченко ©   (2007-11-16 13:10) [47]

Mystic ©   (16.11.07 13:08) [46]

Автор - Эрик Рэймонд, "Искусство программирования для Unix"


 
Юрий Зотов ©   (2007-11-16 13:14) [48]

> Romkin ©   (16.11.07 12:53) [44]

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

Хм... девствит-но... значит надо изменить формулировку: список исключений методом-потомком тоже наследуется, но может им расширяться.


 
Игорь Шевченко ©   (2007-11-16 13:16) [49]

Юрий Зотов ©   (16.11.07 13:14) [48]


> значит надо изменить формулировку: список исключений методом-
> потомком тоже наследуется, но может им расширяться.


То есть, работать с классом, как с предком, не имея представления о том, каким по счету потомком он является, в таком аксепте не выйдет ?


 
mephasm   (2007-11-16 13:25) [50]

Юрий Зотов ©   (16.11.07 13:07) [45]

Возможно вы немного меня не поняли.
Посмотрите повнимательнее откуда выбрасывается IOException.
Этот метод реализует SAXHandler, который выбрасывает SAXException.

public void startElement (String name, AttributeList attrs)
throws SAXException {

Если вы выбросите из него NestedException то оно пролетит через метод parse.
Даже не нужно ничего перегружать.


 
Romkin ©   (2007-11-16 13:43) [51]

Юрий Зотов ©   (16.11.07 13:14) [48]

> Хм... девствит-но... значит надо изменить формулировку:
> список исключений методом-потомком тоже наследуется, но
> может им расширяться

А разница-то какая? Ну появилось новое исключение, что, там, где вызывается метод предка, его знать будут?


 
Romkin ©   (2007-11-16 13:45) [52]


> public void startElement (String name, AttributeList attrs)throws
> SAXException {Если вы выбросите из него NestedException
> то оно пролетит через метод parse.Даже не нужно ничего перегружать.
>

То есть, получается, как в Delphi. Вопрос: зачем тогда java требует писать список эксепшенов, если все равно можно сделать "пролет"?


 
Petr V. Abramov ©   (2007-11-16 13:46) [53]

> Юрий Зотов ©   (16.11.07 13:14) [48]
> список исключений методом-потомком тоже наследуется, но может им расширяться.
а если я в наследнике какое-то исключение глушу, то может и сужаться.


 
mephasm   (2007-11-16 13:59) [54]

Romkin ©   (16.11.07 13:45) [52]

>То есть, получается, как в Delphi. Вопрос: зачем тогда java требует писать список эксепшенов, если все равно можно сделать "пролет"?

Вопрос был в том, можно ли это сделать в принципе или нет.
Видимо, декларации требуются для красоты.

Any Exception that can be thrown by a method is part of the method"s public programming interface. Those who call a method must know about the exceptions that a method can throw so that they can decide what to do about them. These exceptions are as much a part of that method"s programming interface as its parameters and return value.

Но если вы делаете пролет, то ведь вы знаете, что пролетит, правда?


 
Сусл ©   (2007-11-16 14:15) [55]


> These exceptions are as much a part of that method"s programming
> interface as its parameters and return value.

офигеть, я в посте [17] почти тоже самое сказал :)

По моему мнению throws ничем не отличается по вкладу в документацию от списка параметров, скажем.

да... как будто я java придумал! :)


 
Romkin ©   (2007-11-16 14:21) [56]

mephasm   (16.11.07 13:59) [54]

> Вопрос был в том, можно ли это сделать в принципе или нет.
> Видимо, декларации требуются для красоты.

Да не может такого быть, чтобы для красоты!
Сам же указываешь: Those who call a method must know about the exceptions that a method can throw so that they can decide what to do about them.
А тут, если я не ошибся, ты показал, что метод легко может выбросить под видом описанного исключения другое. И перехват, как я понял, надо делать именно этого другого исключения, как объявленное оно не перехватиться, я правильно понял?
Но тогда, получается, что тот, кто вызывает метод, может получить информацию о том, какие именно исключения выбрасываются, не из заголовка метода, но только каким-то другим способом, из документации, исходников этого метода, вербально от создателя?

То есть, правильно ли я понял, что в твоем варианте в [38], если будет переопределено IOException:
catch (IOException e)
{
throw new SAXException("I/O error: " + e.toString(), e);
}
то в [40] оно поймается именно как IOException, в блоке
catch (IOException e)
{
//...
}

но не выше, где catch SAXException?


 
mephasm   (2007-11-16 14:25) [57]

Romkin ©   (16.11.07 14:21) [56]

Угу. Только вы сами создаете Handler и сами выбрасываете из него IOExcepiton.
Парсер ничего об этом не знает. Все под контролем.
Если вы написали хандлер, а исключения поручили перехватывать другому программисту, то да, остается тихо умереть в сторонке.


 
Romkin ©   (2007-11-16 14:30) [58]


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

Перефразирую... Если я написал потомка, в его методе сделал этот хандлер, а другой программист юзает предка либо опирается на объявление моего класса (а я забыл сказать, например, что я это сделал), и у него нет catch IOException, то что случится в случае его возникновения?


 
mephasm   (2007-11-16 14:37) [59]

Romkin ©   (16.11.07 14:30) [58]

Не совсем ясно, что вы имеете в виду.
Если вы написали потомка парсера, то ему должно быть безразлично, что выбрасывает SAXHandler. Так как метод parse выбрасывает общий SAXException, то к этому методу нет ни каких претензий. Вы в переопределенной версии этого метода можете конечно перехватывать IOException, но это будет только сужение набора выбрасываемых исключений, а никак не расширение.

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


 
Romkin ©   (2007-11-16 14:49) [60]

mephasm   (16.11.07 14:37) [59]

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

А, в логе. Это я и спрашивал. Что будет, если исключение не перехватить. То есть, оно мирно всплывает на самый верх.
Правда, маленькое замечание: править придется то место, где используется родитель, добавив перехват исключения. Похоже, на подобное и намекал Зотов, затевая топик.
То есть, если есть какой-то код, использующий предка, а я пишу потомка, перекрывая метод, то использовать nested exception я не могу, поскольку точно знаю, что не перехватят, так ведь?


 
kaif ©   (2007-11-16 14:52) [61]

Я считаю, что любое принуждение приводит рано или поздно к одному - к обману. Требование обработать исключение приводит к тому, что нерадивый программист его в большинстве случаев просто подавляет, что еще хуже, чем если бы он его вообще никак не обработал - тогда его бы поймал обработчик верхнего уровня (как это сделано в Delphi), а пользователь вместо того чтобы недоумевать и гадать, "а что произошло с моей попыткой, например, соединиться с базой данных?" увидел бы хоть какое-то сообщение об ошибке, говорящее хотя бы о том, что ошибка все же здесь произошла.
Дело даже не в наследовании классов.
Вообще такой подход наводит меня на мысль о том, что у Джавы есть проблемы с архитектурой, скорее всего в части сборки мусора. Не удивлюсь, если выяснится, что сие сомнительное благо было лишь не очень изящным способом решить собственные архитектурные недочеты в идеологии Джава-машины.


 
Romkin ©   (2007-11-16 15:00) [62]


> Я считаю, что любое принуждение приводит рано или поздно
> к одному - к обману.

Ну нет. Ограничения и принуждения нужны. Они полезны и позволяют избежать ошибок.
Вот только:
1. Они должны быть разумными, и не ограничивать возможности
2. Из них не должно быть исключений.
Например, принуждение к тому, чтобы каждое имя было описано и объявлено до использования. Разумно же? И не ограничивает в использовании: только опиши.
А тут - вроде нельзя выбросить необъявленное исключение, но если очень хочется...


 
mephasm   (2007-11-16 15:03) [63]

Romkin ©   (16.11.07 14:49) [60]

А вы знаете какой-то подход, которым можно решить эту проблему в принципе?


 
Petr V. Abramov ©   (2007-11-16 15:04) [64]

> kaif ©   (16.11.07 14:52) [61]
с архитектурой машины все нормально.
а указанная проблема, я думаю, возникла как и большинство других в этом мире: хотели, как лучше (задокументировать поднимаемые исключения), а получилось, как всегда (см. [0])


 
Petr V. Abramov ©   (2007-11-16 15:07) [65]

> mephasm   (16.11.07 15:03) [63]
достаточно у наследника разрешить менять throws


 
mephasm   (2007-11-16 15:07) [66]

Petr V. Abramov ©   (16.11.07 15:07) [65]

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


 
Petr V. Abramov ©   (2007-11-16 15:12) [67]

> mephasm   (16.11.07 15:07) [66]
где? суть не понял


 
Romkin ©   (2007-11-16 15:16) [68]

Petr V. Abramov ©   (16.11.07 15:07) [65]

> достаточно у наследника разрешить менять throws

Еще один. в [38] и [40] тебе показали, фактически, как возбуждать исключение, которого нет в заголовке метода.
А смысл? Тот, кто юзает предка, ничего нафиг о потомке не знал. И не перехватывает он их!

mephasm   (16.11.07 15:03) [63]

> А вы знаете какой-то подход, которым можно решить эту проблему
> в принципе?

Сначала нужно установить, есть ли здесь проблема :)
Сейчас я понял только, что требование "Any Exception that can be thrown by a method is part of the method"s public programming interface. Those who call a method must know about the exceptions that a method can throw so that they can decide what to do about them." можно обойти довольно легко и легитимно, с помощью механизма nested exception.
Но все дело в том, что, например, Delphi вполне нормально существует и без этого требования.
А что мешает в java просто перехватывать все все сообщения на самом верхнем уровне?


 
mephasm   (2007-11-16 15:18) [69]

Petr V. Abramov ©   (16.11.07 15:12) [67]

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


 
mephasm   (2007-11-16 15:23) [70]

Romkin ©   (16.11.07 15:16) [68]

>А что мешает в java просто перехватывать все все сообщения на самом верхнем уровне?

Ничто. Вы можете написать контейнер, который будет это делать.


 
Romkin ©   (2007-11-16 15:36) [71]

mephasm   (16.11.07 15:23) [70]

> Ничто. Вы можете написать контейнер, который будет это делать.

Тогда почему бы не предположить следующее: переводим требование об объявлении exception в заголовке метода в рекомендацию, пусть варнинг выдается, а не ошибка.
Тогда и никаких nested exception не понадобиться, и переопределять exception не надо.
Фактически, все эксепшены будут работать как рантайм, которые уже есть.
Какие здесь подводные камни?


 
Petr V. Abramov ©   (2007-11-16 15:38) [72]

> mephasm   (16.11.07 15:23) [70]

Romkin ©   (16.11.07 15:16) [68]
> А смысл? Тот, кто юзает предка, ничего нафиг о потомке не знал.
ну и что? Смысл throws - задокументировать исключения или какой другой? Throws предка несет информацию о том, что ПРЕДОК возбуждает такие-то исключения, а потомки - что угодно. В чем проблема?

> mephasm   (16.11.07 15:23) [70]
> Вы можете написать контейнер, который будет это делать.
как их поднять-то в наследниках, чтоб до контейнера дошли?


 
mephasm   (2007-11-16 15:44) [73]

Romkin ©   (16.11.07 15:36) [71]

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

Petr V. Abramov ©   (16.11.07 15:38) [72]
>как их поднять-то в наследниках, чтоб до контейнера дошли?
Использовать базовый Exception в декларации throw всех ваших методов.


 
Romkin ©   (2007-11-16 15:46) [74]


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

Да и не надо, ее нет :) Delphi же живет с этим, и ничего. Или особенности есть?


 
mephasm   (2007-11-16 15:51) [75]

Ну вот, похоливарили :)


 
Romkin ©   (2007-11-16 15:53) [76]

Да уж :)))


 
Petr V. Abramov ©   (2007-11-16 15:57) [77]

> Использовать базовый Exception в декларации throw всех ваших методов.
и получить орден от индусского правительства за такое кол-во дополнительных строк кода :)


 
Romkin ©   (2007-11-16 16:01) [78]


> > Использовать базовый Exception в декларации throw всех
> ваших методов.и получить орден от индусского правительства
> за такое кол-во дополнительных строк кода :)

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


 
iZEN ©   (2007-11-16 20:20) [79]


> Romkin ©   (16.11.07 16:01) [78]
>
>
> > > Использовать базовый Exception в декларации throw всех
> > ваших методов.и получить орден от индусского правительства
> > за такое кол-во дополнительных строк кода :)
>
> Да не надо ничего использовать. Показали же уже, что ограничение
> на исключения в заголове метода легко обходится. Оно просто
> не действует, было бы желание.


public class A {
  public void startElement(String name, AttributeList attrs) throws SAXException {
       try {
           if (name.equals("SCHEDULE")) {
               this.ParseStartSchedule(attrs);
               return;
           }
           return;
       } catch (IOException e) {
           throw new SAXException("I/O error: " + e.toString(), e);
       } catch (ScheduleParseException e) {
           throw new SAXException("ScheduleParseError" + e.toString(), e);
       }
   }
...
}


Это не "обход". Проверяемое исключение SAXException всё же бросается. Компилятор пропустит этот код как валидный — контракт базового класса соблюдён.

А что было бы, если бы метод startElement был перегружен в потомке и в него долбавили бы throws IOException:

public class B extends A {
  public void startElement(String name, AttributeList attrs) throws SAXException, IOException {
     ...
  }
...
}

Тогда ранее написанный класс, использующий объект базового класса A, не смог бы вызвать полиморфно метод объекта класса B только из-за того, что сигнатуры методов РАЗНЫЕ. (Компилятор включает в сигнатуру методов информацию  о checked exceptions). Вообще же, javac выдаст ошибку при компиляции класса B:

/path/to/B.java:29: parseString(java.lang.String, AttributeList) in B cannot override parseString(java.lang.String, AttributeList) in A; overridden method does not throw java.io.IOException.

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

Чтобы "добавить" ещё одно проверяемое исключение программисту класса B, ему можно идти двумя путями:

1) Объявить потомка класса SAXException, например, IOSAXException и бросать экземпляр потомка:
throw new IOSAXException();

либо

2) "Завернуть" IOException в SAXException и бросить:
throw new SAXException("I/O error: " + e.toString(), e);
как уже было показано выше.

Контракт на полиморфные вызовы не нарушен. Программисты могут спать спокойно.


 
iZEN ©   (2007-11-16 20:22) [80]

Извиняюсь

/path/to/B.java:29: parseString(java.lang.String, AttributeList) in B cannot override parseString(java.lang.String, AttributeList) in A; overridden method does not throw java.io.IOException.

следует читать как:

/path/to/B.java:29: startElement(java.lang.String, AttributeList) in B cannot override parseString(java.lang.String, AttributeList) in A; overridden method does not throw java.io.IOException.


 
iZEN ©   (2007-11-16 20:25) [81]

> Romkin ©   (16.11.07 16:01) [78]
>
>
> > > Использовать базовый Exception в декларации throw всех
> > ваших методов.и получить орден от индусского правительства
> > за такое кол-во дополнительных строк кода :)
>
> Да не надо ничего использовать. Показали же уже, что ограничение
> на исключения в заголове метода легко обходится. Оно просто
> не действует, было бы желание.


public class A {
 public void startElement(String name, AttributeList attrs) throws SAXException {
      try {
          if (name.equals("SCHEDULE")) {
              this.ParseStartSchedule(attrs);
              return;
          }
          return;
      } catch (IOException e) {
          throw new SAXException("I/O error: " + e.toString(), e);
      } catch (ScheduleParseException e) {
          throw new SAXException("ScheduleParseError" + e.toString(), e);
      }
  }
...
}


Это не "обход". Проверяемое исключение SAXException всё же бросается. Компилятор пропустит этот код как валидный — контракт базового класса соблюдён.

А что было бы, если бы метод startElement был перегружен в потомке и в него долбавили бы throws IOException:

public class B extends A {
 public void startElement(String name, AttributeList attrs) throws SAXException, IOException {
    ...
 }
...
}

Тогда ранее написанный класс, использующий объект базового класса A, не смог бы вызвать полиморфно метод объекта класса B только из-за того, что сигнатуры методов РАЗНЫЕ. (Компилятор включает в сигнатуру методов информацию  о checked exceptions). Вообще же, javac выдаст ошибку при компиляции класса B:

/path/to/B.java:29: startElement(java.lang.String, AttributeList) in B cannot override startElement(java.lang.String, AttributeList) in A; overridden method does not throw java.io.IOException.

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

Чтобы "добавить" ещё одно проверяемое исключение программисту класса B, ему можно идти двумя путями:

1) Объявить потомка класса SAXException, например, IOSAXException и бросать экземпляр потомка:
throw new IOSAXException();

либо

2) "Завернуть" IOException в SAXException и бросить:
throw new SAXException("I/O error: " + e.toString(), e);
как уже было показано выше.

Контракт на полиморфные вызовы не нарушен. Программисты могут спать спокойно.


 
Romkin ©   (2007-11-16 20:30) [82]


> 2) "Завернуть" IOException в SAXException и бросить:throw
> new SAXException("I/O error: " + e.toString(), e);как уже
> было показано выше.Контракт на полиморфные вызовы не нарушен.
>  Программисты могут спать спокойно.

Все верно, я все так и понял. А теперь скажи, нафига вообще нужен этот контракт на объявление всех исключений, если он вот так вот легко обходится? Чтобы было? Почему просто не сделали его рекомендательным?
Почему его вообще не убрать?
И почему программисты могут спать спокойно, если он во втором случае просто не работает?


 
Romkin ©   (2007-11-16 20:33) [83]

Точнее, что мне помешает объявить в заголовке метода свой тип, например, RomkinException, а внутри метода тупо оборачивать им все остальные?
Какой вообще смысл в этой стенке?


 
iZEN ©   (2007-11-16 21:05) [84]


> Romkin ©   (16.11.07 20:33) [83]
> Точнее, что мне помешает объявить в заголовке метода свой
> тип, например, RomkinException, а внутри метода тупо оборачивать
> им все остальные?


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


> Romkin ©   (16.11.07 20:33) [83]
> Какой вообще смысл в этой стенке?


Смысл в этой стенке такой: чтобы в будущем не ломалась логика вызовов ВСЕХ полиморфных методов ПОТОМКОВ. Чтобы не позволить бросать новые проверяемый исключения, которые не входят в иерархию уже определённых в методах БАЗОВЫХ классов, иначе весь смысл использования проверяемых исключений теряется. Смысл как раз в том, чтобы обеспечить проверку операций позднего связывания рантайма ещё на этапе компиляции.

Не нравится — пользуйтесь RuntimeException"s как в Delphi и .Net.


 
iZEN ©   (2007-11-16 21:15) [85]


> Romkin ©   (16.11.07 20:30) [82]
>
>
> > 2) "Завернуть" IOException в SAXException и бросить:throw
> > new SAXException("I/O error: " + e.toString(), e);как
> уже
> > было показано выше.Контракт на полиморфные вызовы не нарушен.
>
> >  Программисты могут спать спокойно.
>
> Все верно, я все так и понял. А теперь скажи, нафига вообще
> нужен этот контракт на объявление всех исключений, если
> он вот так вот легко обходится? Чтобы было?

Он и не обходится. Он всё же реализуется, но именно так, как разработчик считает нужным.


> Romkin ©   (16.11.07 20:30) [82]
> Почему просто
> не сделали его рекомендательным?


Тогда это бы не отличалось от использования RuntimeException"s — на то они и checked exceptions, чтобы проверяться на этапе компиляции, а не во время выполнения, когда проверять уже поздно, пользователь видит "AV". 50% ошибок программистов в этом плане компилятор не допустит.


> Romkin ©   (16.11.07 20:30) [82]
> Почему его вообще не убрать?
> И почему программисты могут спать спокойно, если он во втором
> случае просто не работает?


Что "не работает"? Как раз-таки работает. Исключение SAXException("I/O error: " + e.toString(), e); будет поймано вызывающим методом и обработано надлежащим образом. Строка ""I/O error: " + e.toString()" — это просто детали, которые дополняют исключение e. В вызывающем методе можно проанализировать исключение e, если это сочтёт важным сделать программист-пользователь этого класса. Информация достаточно полна и не потеряна.


 
Romkin ©   (2007-11-16 21:21) [86]


> Тогда это бы не отличалось от использования RuntimeException"s
> — на то они и checked exceptions, чтобы проверяться на этапе
> компиляции, а не во время выполнения, когда проверять уже
> поздно, пользователь видит "AV". 50% ошибок программистов
> в этом плане компилятор не допустит.

Э. Так и так не отличается, мне только лишние телодвижения делать надо, оборачивать исключение в уже объявленное.
Вообще-то речь не об AV, не об ошибках RunTime, они-то, как я понял, идут по факту. А, например, об IOError. Пусть видит, что он файл удалил, или у него сетка отвалилась. :)
Если мне надо - я посмотрю на заголовок, и перехвачу нужное. А так-то зачем? Зачем мне перехватывать и оборачивать своим типом известие о том, что место на диске кончилось? Или что пользователь ввел неправильную дату?


 
Romkin ©   (2007-11-16 21:25) [87]

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


 
vpbar ©   (2007-11-16 23:07) [88]

читал, вспоминал яву. И вот какой вопрос возник. С какой основной целью было сделано это checked exceptions?
1. С целью документировать возможные исключения метода.
2. С целью ограничить возможные исключения метода.
3. Что бы гарантировать, что метод может бросить только определенные исключения. С тем чтобы можно было работать с методом базового класса, полагая, что он может кинуть только данные исключения, несмотря на то что за ним может скрываться какойнить дочерний класс.

Из всех вариантов я могу понять только последний. Ибо докуменировать можно иными средствами. Просто так ограничиать - вообще непонятно зачем надо.
Остается только одно. Возможность работать с тем же TStream, и иметь гарантию, что он может вызвать только исключения, например типа IOException. Не смотря на то, что за ним скрывается TFileStream или TMemStream. В принципе в этом есть некоторый смысл.
И можно найти (контр)аргументы для следующих  заявлений:


>
> Но, с другой стороны: есть у меня, например, базовый класс
> TStream для потока... От него порождены TFileStream, TResourceStream
> и TSocketStream, которые, понятно, работают совершенно с
> разными источниками данных и поэтому сталкиваются с совершенно
> разными ошибками... Ну и что, методы базового класса должны
> учитывать все возможные исключения, что ли? А если появится
> новый источник данных с новыми типом исключений? Или надо
> предусмотреть одно исключение на все случаи жизни?


При работе с  TStream вы можете ожидать IOExcaption, но ни как не все варианты типа FileWriteExcaption, ConnectExcaption и т.п. Т.е. вызывая в базовом методе TStream.CopyFrom  полиморфный read вам абсолютно не нужно знать из-за чего конкретно возникнет ошибка чтения. И если при этом конкретная реализация возбудит ConnectExcaption то вы не сможете ее тут обработать (если конечно заранее не будете знать всех возможных предков их исключения). Т.е. спецефичные исключения нужны только в методах спецефичных для потомка. Для того же TSocketStream это может быть метод Conect.
С другой стороны checked exceptions это сильное ограничение и того же можно достичь просто опеределяя потомков IOExcaption и возбуждая только их. Но если нужно можно возбуждать другие исключения.

Вообщем интересно было бы, если обсуждение было продолжено и высказаны конкретные примеры, когда нужно возбудить исключение в переопределенном методе, которое не было объявлено в базовом. И кто его будет обрабатывать.
Это к Представим себе сторонний класс (или интерфейс), в котором объявлен какой-то метод.
из [0]


 
iZEN ©   (2007-11-16 23:19) [89]


> Romkin ©   (16.11.07 21:25) [87]
>
> Или ты хочешь сказать, что все это затеяно только для одного,
>  чтобы я сказал компилятору, что да, млин, видел я, что
> тут может быть это исключение?

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

Если в приложении предусмотрена действительно хорошая обработка ошибок, то это очень качественное подспорье в таком деле. Как я уже сказал, 50% граблей с обработкой исключений берёт на себя компилятор. И только лишь за счёт применения (заметь, я не говорил "правильного" или "неправильного") проверяемых исключений! Это с одной стороны дисциплинирует программиста (навязывает стратегию контракта базового класса), а с другой стороны заставляет разработать собственную стратегию обработки исключений. Не ставить же везде "...} catch (Exception e) {}"! (хотя встречаются случаи, когда можно/нужно "гасить" проверяемое исключение, не обрабатывая и не пробрасывая его вверх по стэку вызовов).


 
iZEN ©   (2007-11-16 23:34) [90]


> vpbar ©   (16.11.07 23:07) [88]
>
> читал, вспоминал яву. И вот какой вопрос возник. С какой
> основной целью было сделано это checked exceptions?
> 1. С целью документировать возможные исключения метода.


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


> vpbar ©   (16.11.07 23:07) [88]
> 2. С целью ограничить возможные исключения метода.
> 3. Что бы гарантировать, что метод может бросить только
> определенные исключения. С тем чтобы можно было работать
> с методом базового класса, полагая, что он может кинуть
> только данные исключения, несмотря на то что за ним может
> скрываться какойнить дочерний класс.


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


> vpbar ©   (16.11.07 23:07) [88]
> Из всех вариантов я могу понять только последний. Ибо докуменировать
> можно иными средствами. Просто так ограничиать - вообще
> непонятно зачем надо.
> Остается только одно. Возможность работать с тем же TStream,
>  и иметь гарантию, что он может вызвать только исключения,
>  например типа IOException. Не смотря на то, что за ним
> скрывается TFileStream или TMemStream. В принципе в этом
> есть некоторый смысл.


Во всём есть смысл, если есть желание его найти. ;)


 
Alex Konshin ©   (2007-11-17 00:47) [91]

> Однокамушкин   (16.11.07 09:12) [4]
> > Канадец   (16.11.07 08:03) [1]
> > Дальше больше.... допустим идеальный вариант. Есть некий,
> >  хорошо задокуменированый класс с виртуальным методом,  который
> > чётко в документации указывает исключения какого рода  он
> > может порадить. Дальше следуя Вашему второму варианту появляется
> > некто, кто пишет наследника, переопределяет данный метод
> > и плюёт исключение, которое нигде не упоминается в описании
> > базового класса. Вопрос: я, как пользователь базового класса,
> >  какие исключения должен ожидать от этого метода?
>
> Нехорошо, конечно... Но, с другой стороны: есть у меня,
> например, базовый класс TStream для потока... От него порождены
> TFileStream, TResourceStream и TSocketStream, которые, понятно,
>  работают совершенно с разными источниками данных и поэтому
> сталкиваются с совершенно разными ошибками... Ну и что,
> методы базового класса должны учитывать все возможные исключения,
>  что ли? А если появится новый источник данных с новыми
> типом исключений? Или надо предусмотреть одно исключение
> на все случаи жизни? Но тогда обработка этих исключений
> будет сильно затруднена... В общем, я согласен с Юрием

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

В Java нечто новое не может кидать новые эксепшп просто потому, что компилятор не допустит. А кидать что ни попадя вообще дурная практика в любом языке. Вот, допустим, какой мне толк от самой ошибки чтения файла который кидает тот же TStream? Или, ещё более показательный пример: в каком-нибудь парсере получаем ошибку преобразования строки в число. Это мне практически ничего не даёт для нахождения причины ошибки. Мне-то нужно имя файла и номер строки, а ещё неплохо и позицию в строке, где это произошло.
Поэтому нужно оборачивать эксепшены в эксепшены более высокого уровня, а тот старый эксепшн указывать как cause. Тогда вы в распечатке стека этого исключения увидите что, где и когда случилось.

И это нужно делать не только в Java, а в Delphi тоже. Но, кстати, в Delphi в Exception нет поля cause, поэтому нужно делать свой класс, да и распечатку эксепшена приходится делать самому.
Кстати, в Delphi вообще плохо дело обстоит с поиском причин эксепшн. Нет печати стека вызовов при эксепшн.


 
Petr V. Abramov ©   (2007-11-17 01:05) [92]

> Alex Konshin ©   (17.11.07 00:47) [91]
> поля cause,
можно попдробнее? жабу не знаю и знать не хочу :) но теологически интересно

> в Delphi вообще плохо дело обстоит с поиском причин эксепшн.
так в интерпретаторе-то проще по-любому, пусть p-code


 
Германн ©   (2007-11-17 01:12) [93]


> Кстати, в Delphi вообще плохо дело обстоит с поиском причин
> эксепшн. Нет печати стека вызовов при эксепшн.

<offtop>
Ну это у кого как.
</offtop>
:)


 
Petr V. Abramov ©   (2007-11-17 01:15) [94]

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


 
Petr V. Abramov ©   (2007-11-17 01:16) [95]

+ Petr V. Abramov ©   (17.11.07 01:15) [94]
а может, и не в catch


 
iZEN ©   (2007-11-17 08:17) [96]

Petr V. Abramov, вот тут посмотрите:

http://java.sun.com/docs/books/jls/third_edition/html/exceptions.html


 
Alex Konshin ©   (2007-11-18 00:30) [97]

> Германн ©   (17.11.07 01:12) [93]
> > Кстати, в Delphi вообще плохо дело обстоит с поиском причин
> > эксепшн. Нет печати стека вызовов при эксепшн.
> <offtop>
> Ну это у кого как.
> </offtop>
> :)

У меня тоже есть и когда-то делился здесь своим кодом для этого.
Но в любом случае это сложно, ненадёжно и информация ограничена.
В Java же всё есть в комплекте и ничего изобретать не нужно.


 
Petr V. Abramov ©   (2007-11-18 00:41) [98]

> iZEN ©   (17.11.07 08:17) [96]
многа букаффф :)
за ссылку спасибо, сохранил, когда будет надо глубоко вопросом заняться, почитаю.
на [94] - [95] не могли бы в двух-трех строках ответить, они подразумевают протой ответ  - "Да" - "нет"
ссылка  [96] будет большим подспорьем для анализа краткого ответа.


 
iZEN ©   (2007-11-18 14:36) [99]


> Petr V. Abramov ©   (18.11.07 00:41) [98]

Отвечаю.

> Petr V. Abramov ©   (17.11.07 01:15) [94]
>
> кстати, такой вопрос
> вот я в наследнике в catch вызываю ф-цию, которая тоже может
> поднять исключение, может, ф-ция своего класса, а может,
>  другого. Исключения, которые поднимает вызываемая ф-ция,
>  тоже в thows должны быть описаны или нет?

Да, должна быть описана в throws. Но можно перехватить в отдельном try/catch.


 
iZEN ©   (2007-11-18 14:37) [100]

JLS в разых форматах: http://java.sun.com/docs/books/jls/


 
Юрий Зотов ©   (2007-11-18 20:54) [101]

Что ж, ветка сползает вниз - значит, интерес к ней утрачен и можно, видимо, подводить итоги.

ИМХО, в целом провокация (а это, признаюсь, была все же провокация) более-менее удалась. Очень хорошо, что высказались люди, гораздо более сведующие в сабже, чем я и другие дельфисты. Надеюсь, почитать их посты всем нам было полезно - а еще полезнее, возможно, окажутся те ссылки, которые они привели. Спасибо, как говорится, за участие, да и за науку.

> mephasm

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

:о)


 
Petr V. Abramov ©   (2007-11-18 23:21) [102]

> Юрий Зотов ©   (18.11.07 20:54) [101]
а все равно наши победили :)


 
Alex Konshin ©   (2007-11-19 01:04) [103]

> Petr V. Abramov ©   (18.11.07 23:21) [102]
> > Юрий Зотов ©   (18.11.07 20:54) [101]
> а все равно наши победили :)

В корне не согласен!


 
Petr V. Abramov ©   (2007-11-19 01:18) [104]

> Alex Konshin ©   (19.11.07 01:04) [103]

> > Petr V. Abramov ©   (18.11.07 00:41) [98]
>
> Отвечаю.
>
> > Petr V. Abramov ©   (17.11.07 01:15) [94]
> >
> > кстати, такой вопрос
> > вот я в наследнике в catch вызываю ф-цию, которая тоже
> может
> > поднять исключение, может, ф-ция своего класса, а может,
>
> >  другого. Исключения, которые поднимает вызываемая ф-ция,
>
> >  тоже в thows должны быть описаны или нет?
>
> Да, должна быть описана в throws. Но можно перехватить в
> отдельном try/catch.


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


 
Petr V. Abramov ©   (2007-11-19 01:24) [105]

> Petr V. Abramov ©   (19.11.07 01:18) [104]
> подымать exception жаба методе нельзя, если он не виртуальный
без НЕ ессно


 
Petr V. Abramov ©   (2007-11-19 01:32) [106]

> Petr V. Abramov ©   (19.11.07 01:18) [104]
шкуру индийскго тигра, сосуд с водой из реки Ганг, и трехъядерный ноутбук в полной камасутрой в электронном виде с видеопособием :)


 
Германн ©   (2007-11-19 01:41) [107]


> Petr V. Abramov ©   (19.11.07 01:32) [106]

Петя. Остановись. Успокойся и пойди спать.


 
Petr V. Abramov ©   (2007-11-19 01:46) [108]

> Германн ©   (19.11.07 01:41) [107]
как-нибудь так и  сделаю.
а по суи?


 
Германн ©   (2007-11-19 01:57) [109]


> а по суи?

Китайский язык не знаю ( а также и японский, вьетнамский и т.д.). Ты уж извини. :(


 
J_f_S   (2007-11-19 01:58) [110]


Petr V. Abramov ©   (19.11.07 01:46) [108]
> Германн ©   (19.11.07 01:41) [107]
как-нибудь так и  сделаю.
а по суи?

Нутром чую, что опечатка. Но где? ;)


 
Petr V. Abramov ©   (2007-11-19 02:11) [111]

>  где? ;)
ты ж программер, чужой код читать умеешь, сразу суть понимая :)))


 
Германн ©   (2007-11-19 02:17) [112]


> Petr V. Abramov ©   (19.11.07 02:11) [111]
>
> >  где? ;)
> ты ж программер, чужой код читать умеешь, сразу суть понимая
> :)))
>

Он СИ-шник. Он так сразу не поймёт :)


 
iZEN ©   (2007-11-19 02:24) [113]


> Petr V. Abramov ©   (19.11.07 01:18) [104]
>
> > > Petr V. Abramov ©   (17.11.07 01:15) [94]
> > >
> > > кстати, такой вопрос
> > > вот я в наследнике в catch вызываю ф-цию, которая тоже
> > может
> > > поднять исключение, может, ф-ция своего класса, а может,
>
> >
> > >  другого. Исключения, которые поднимает вызываемая ф-
> ция,
> >
> > >  тоже в thows должны быть описаны или нет?
> >
> > Да, должна быть описана в throws. Но можно перехватить
> в
> > отдельном try/catch.
>
>
> подымать exception жаба методе нельзя, если он <s>не</s> виртуальный.
>  А если написать популярную библиотеку (opensorce ессно)
> и в другой ее версии поднять  другой exception, хотя бы
> из соображений изменившегося многополярного мира - гарантирован
> орден от индусского правительства, чьи подданные будут за
> деньги переделывать заголовки миллионов методов

Работающий пример можно?


 
J_f_S   (2007-11-19 02:36) [114]


> Германн ©   (19.11.07 02:17) [112]
> > Petr V. Abramov ©   (19.11.07 02:11) [111]> > >  где?
> ;)> ты ж программер, чужой код читать умеешь, сразу суть
> понимая > :)))
> Он СИ-шник. Он так сразу не поймёт :)

Немного иначе:
Он СИ-шник. Он сразу не так поймёт ;)


 
Alex Konshin ©   (2007-11-19 07:51) [115]

> Petr V. Abramov ©   (19.11.07 01:18) [104]
> подымать exception жаба методе нельзя, если он не виртуальный.
>  А если написать популярную библиотеку (opensorce ессно)
> и в другой ее версии поднять  другой exception, хотя бы
> из соображений изменившегося многополярного мира - гарантирован
> орден от индусского правительства, чьи подданные будут за
> деньги переделывать заголовки миллионов методов

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


 
Petr V. Abramov ©   (2007-11-19 11:48) [116]

> Alex Konshin ©   (19.11.07 07:51) [115]
еще раз по полкам, интересно все ж, что в мире творится

есть метод А, который throws E1.

и есть метод B, который вызывает А.
у В throws E1 прописано должно быть?


 
Romkin ©   (2007-11-19 11:57) [117]


> у В throws E1 прописано должно быть?

НАсколько я понял, либо прописываешь, либо внутре его перехватываешь.


 
Petr V. Abramov ©   (2007-11-19 12:02) [118]

> Romkin ©   (19.11.07 11:57) [117]
вот, теперь в новой версии операционки в методе А может появляться исключение E2. Что делать со всеми методами, которые используют А?


 
Zeqfreed ©   (2007-11-19 12:02) [119]

> Romkin ©   (19.11.07 11:57) [117]

Так и есть.


 
Romkin ©   (2007-11-19 12:40) [120]


> вот, теперь в новой версии операционки в методе А может
> появляться исключение E2. Что делать со всеми методами,
> которые используют А?

Тебе же сказали: так писать нельзя :)))
Что значит "может появляться"? Ты просто так не напишешь, не скомпилируется


 
Petr V. Abramov ©   (2007-11-19 12:44) [121]

> Romkin ©   (19.11.07 12:40) [120]
вот и получается, что exception надо либо гасить, либо выдавать его за что-то описанное.
Так и рождаются программы с сообщениями "ошибка ввода-вывода. позовите сисадмина, желаем ему всего хорошего"


 
Romkin ©   (2007-11-19 12:56) [122]


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

Ты не понимаешь, это и называется "Думать на Яве"! :)


 
Petr V. Abramov ©   (2007-11-19 12:58) [123]

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


 
Romkin ©   (2007-11-19 13:00) [124]

Я, например, так и не могу представить, зачем мне может понадобиться проверять путь прохода исключения. И чтобы компилятор мне в этом помогал.
Это к iZEN ©   (16.11.07 23:19) [89]


 
Petr V. Abramov ©   (2007-11-19 13:07) [125]

в общем гадость эта java Ж)
http://top.rbc.ru/wildworld/16/11/2007/126059.shtml
:)


 
DiamondShark ©   (2007-11-19 13:21) [126]


> Юрий Зотов ©   (16.11.07 10:40) [16]
> > mephasm   (16.11.07 10:31) [14]
>
> > Не понимаю в чем вы видите проблему.
>
> Напишите потомка парсера, перекройте его метод parse и попробуйте
> выбросить из него... ну, к примеру, SQLException. Увидите.

А нафига пользователю XML парсера какие-то SQLException? Он и слов-то таких не знает.


 
Romkin ©   (2007-11-19 13:34) [127]


> А нафига пользователю XML парсера какие-то SQLException?
>  Он и слов-то таких не знает.

Во-во. Точно. Заглушить, чтобы и не знал!


 
Anatoly Podgoretsky ©   (2007-11-19 13:36) [128]

> Petr V. Abramov  (19.11.2007 13:07:05)  [125]

Она для другого уровня программистов, с другими мозгами.


 
Petr V. Abramov ©   (2007-11-19 13:37) [129]

> DiamondShark ©   (19.11.07 13:21) [126]
а он этот XML может читать из потока, а поток из blob.
и юзер получает сообщение "парсер не парсит" вместо "database connection failed"


 
Petr V. Abramov ©   (2007-11-19 13:47) [130]

смысл уловить, конечно, можно - если он парсер, то и должен по-правильному поднимать EParseException. Только вот таких правильных проектировщиков - да на саппорт посадить бы.


 
Сусл ©   (2007-11-19 14:21) [131]

Петр, ты про агрегацию слышал?


 
Petr V. Abramov ©   (2007-11-19 14:27) [132]

> Сусл ©   (19.11.07 14:21) [131]
слово умное. наверняка слышал, только не знал, что это агрегация. А что? :)


 
euru ©   (2007-11-19 14:58) [133]


> Petr V. Abramov ©   (19.11.07 12:58) [123]

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

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


 
Petr V. Abramov ©   (2007-11-19 15:15) [134]

> euru ©   (19.11.07 14:58) [133]
никак не быть, жить с этим :)
но это заголовок, который слабо влияет на то, как реализована эта функция.
Ф-ция базвого класса может быть вообще абстрактной. А что throws абстрактная ф-ция? Да что угодно.


 
kaif ©   (2007-11-19 15:56) [135]

Предлагаю в Джаву добавить еще один модификтор метода: depricated или obsolete.
:)


 
Petr V. Abramov ©   (2007-11-19 15:59) [136]

фактически определение ф-ци (параметры, типы и т.д) - это контракт на то, ЧТО будет делать ф-ция.
А throws - неявный контракт на то, КАК она это будет делать, что абослютно противоречит идее ООП.


 
euru ©   (2007-11-19 16:14) [137]


> Petr V. Abramov ©   (19.11.07 15:15) [134]



> никак не быть, жить с этим :)
А что мешает так же относиться к исключениям?


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


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


 
Petr V. Abramov ©   (2007-11-19 16:21) [138]

> euru ©   (19.11.07 16:14) [137]
> А что мешает так же относиться к исключениям?
да ничто не мешает, можно и мух с котлетами с одну кучу свалить.

> А в потомке нужно вернуть значение, не совпадающее по смыслу со списком значений этого типа. Что делать?
Не нужно, т.к. нарушение контракта "что делать".

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


 
euru ©   (2007-11-19 16:28) [139]


> Petr V. Abramov ©   (19.11.07 15:59) [136]
Определение функции декларирует какие параметры будут на входе и какие на выходе функции. А что она будет делать и как именно она будет делать, зависит от реализации функции и может не совпадать с первоначально планируемым смыслом.

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


 
Petr V. Abramov ©   (2007-11-19 16:30) [140]

вот есть у меня базовый класс с методом "нарисуй собачку"
метод можно хоть через OpenGL реализовать, хоть через движок Doom. Там и там exception`ы разные.
Выходов 2:
- везде подымать EDogError с сообщением "не будет тебе собачки, почему - сам догадайся"
- потратить уйму времени на обезьянью работу - перехват EDoom и преращение его в EDog, притом что от этого он реально в EDog не превращается.


 
euru ©   (2007-11-19 16:44) [141]


> Petr V. Abramov ©   (19.11.07 16:30) [140]
А можно в общих чертах сценарий, как бы это реализовывалось в Delphi? Особенно при вызове этого метода.


 
Petr V. Abramov ©   (2007-11-19 16:53) [142]

> euru ©   (19.11.07 16:44) [141]
что знаю - обрабатываю, что не знаю - raise.
Нельзя и не надо обрабатывать ВСЕ, как правило, с низких уровней идут довольно информативные сообщения, которые помогут если не юзеру, то для диагностики.

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

P.S. всем до вечера


 
iZEN ©   (2007-11-19 20:32) [143]


> Petr V. Abramov ©   (19.11.07 12:02) [118]
>
> > Romkin ©   (19.11.07 11:57) [117]
> вот, теперь в новой версии операционки в методе А может
> появляться исключение E2. Что делать со всеми методами,
> которые используют А?

Переписывать.


 
Сусл ©   (2007-11-19 21:04) [144]

2ПетрАбрамов.

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

Я был бы очень ращ, если бы компилятор меня заставил отреагировать на новый побочный эффект. Вот возьми он и скажи  "Слыш программист, я знаю, что вот эта функция может вести теперь иначе, причем я знаю даже как - может выдать новое исключение! Что делать то будем? Куда ставить то (с)".

Ты будешь просто вынужден подумать над ситуацией, что само по себе не плохо.

А думать оно всегда полезно, Петр.
(с) ИШ :р

Да тут повышается ответственность разработчика библиотеки. Может оно и неплохо? Как там - семь раз отмерь...


 
Mystic ©   (2007-11-19 21:32) [145]

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


Ну и что? Такое случается раз в год, два раза на пасху. Вообще, в Delphi блоки try...except были у меня скорее экзотикой. Исключение пролетает весь стек вызова функций, чтобы преобразоваться на самом верху в красивый диалог об ошибке либо в возвращаемый код ошибки и ее описание.

Схема, когда исключительные ситуации используются как средство управления в программе обычно рождают спагетти, сравнимые с goto в Fortran-е :)

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


 
Сусл ©   (2007-11-19 23:48) [146]


> Mystic ©   (19.11.07 21:32) [145]

вот скажи - ты аккуратно пишешь комментарии к коммитам в своем репозитарии (ну там suversion, cvs, vss, starteam - что юзаешь, не знаю)?


 
Petr V. Abramov ©   (2007-11-20 00:19) [147]

> Сусл ©   (19.11.07 21:04) [144]
> А думать оно всегда полезно, Петр.
И мне полезно, и тебе полезно, и (с) полезно и ИШ полезно и :р полезно :)
недодумали. или пока думали, путч случился.
исправить ничего нельзя

потомоу что
> iZEN ©   (19.11.07 20:32) [143]
> Переписывать

или остаться с своем уме, или разойтись по домам, или
> Petr V. Abramov ©   (19.11.07 01:18) [104]
шкуру индийскго тигра, сосуд с водой из реки Ганг, и трехъядерный ноутбук в полной камасутрой в электронном виде с видеопособием :)


 
Petr V. Abramov ©   (2007-11-20 00:51) [148]


> euru ©   (19.11.07 16:28) [139]
>
> > Petr V. Abramov ©   (19.11.07 15:59) [136]
> Определение функции декларирует какие параметры будут на
> входе и какие на выходе функции. А что она будет делать
> и как именно она будет делать, зависит от реализации функции
> и может не совпадать с первоначально планируемым смыслом.
>
>
> Точно так же список исключений декларирует всего лишь, какие
> исключения может выбросить функция. Не более.


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

> Точно так же список исключений декларирует всего лишь, какие исключения может выбросить функция. Не более.
только ограничивает, КАК функция будет "рисовать"

Вот у меня есть класс

TAnyThingDBLoader
 function LoadSomeThingFromDB: pointer // :)
 function GetPass: string;

function LoadSomeThingFromDB: pointer; // :)
begin
 apass := GetPass  ;
 try
   Connection.Connect(pass);
 except
   on E: EDBError do
     case E.DBErrCode of:
       -1017: raise EInvalidPassword;
       -2808: raise EPasswordExpired;
      else raise;
   end
 end;
 // загрузить someThing
end;

продолжение следует


 
Petr V. Abramov ©   (2007-11-20 00:55) [149]

допустим, в данном случае GetPass запрашивает пароль у юзера и оборабатывает все исключения.
А в следующем проекте мне понадобилось пароль брать из ini-файла. А у меня есть класс TIniFileReader, купленный, стыренный, самонаписанный, главное, хороший, и сграмотной обработкой исключений.
Вроде бы имеет смысл его использовать для доставания пароля из ini-файла.
Но нифига: он поднимает TIniFileException.
Что делать? Загадка: на C начинается на paste кончается


 
Petr V. Abramov ©   (2007-11-20 01:02) [150]

может, конечно, есть какой нечереззадный механизм, кроме
iZEN ©   (19.11.07 20:32) [143]
мне ж просто интересно


 
Romkin ©   (2007-11-20 09:48) [151]

Mystic ©   (19.11.07 21:32) [145] +10! Разумеется. except в Delphi - экзотика.
Тем более удивительно, что в java, это, похоже, стиль жизни...


 
Mystic ©   (2007-11-20 12:07) [152]

> вот скажи - ты аккуратно пишешь комментарии к коммитам в
> своем репозитарии


Как того требует соглашения по проекту. Если я один, то обычно и так помню что к чему :)


 
DiamondShark ©   (2007-11-20 12:57) [153]


> Разумеется. except в Delphi - экзотика.

Потому что дядя постарался и написал:

procedure TWinControl.MainWndProc(var Message: TMessage);
begin
 try
   try
     WindowProc(Message);
   finally
     FreeDeviceContexts;
     FreeMemoryContexts;
   end;
 except
   Application.HandleException(Self);
 end;
end;

кстати, посчитайте try..except в модулях Forms и Controls. это к вопросу о стиле жизни.


 
Romkin ©   (2007-11-20 13:07) [154]

Да, дядя постарался и сделал перехват там, где надо. На верхнем уровне. Теперь практически и не делаю :)
А экзотика - по сравнению с finally. Их явно побольше будет


 
kaif ©   (2007-11-20 13:52) [155]

Мне кажется, что создатели Java вкладывают несколько иной смысл в понятие Exception, нежели создатели Delphi.

В Delphi Exception - это именно "исключительная ситуация". Какую ситуацию считать исключительной, решает разработчик приложения или компонента.

А в Java это ближе к понятию "потенциальная ошибка" или "потенциальный сбой ресурса". Поэтому в Delphi искючительная ситуация зачастую обретает свой смысл лишь в контексте всего приложения, а в Java обречена интерпретироваться локально, в контексте вызывающего класса.

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

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

Фактически в Java мне пришлось бы на уровне вызова SQL-команды породить исключение нового типа (осмысленного для пользоваателя), хотя в этом контексте такая интерпретация пока еще совершенно абсурдна. Или ввести целую иерархию интерпретаций разного уровня, каждый раз порождая новый тип исключительной ситуации. К чему столько мучений?

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


 
kaif ©   (2007-11-20 14:32) [156]

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

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

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

И он видит в этом принуждение, а не просто требование.

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

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

А призваны они служить упрощению повторного использования.

И если понятно, что имеется в виду под повторным использованием поведения, то не всегда это понятно, что иметь в виду под повторным использованием интерпретации.

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


 
Сусл ©   (2007-11-20 17:19) [157]


> [152] Mystic ©   (20.11.07 12:07)
> > вот скажи - ты аккуратно пишешь комментарии к коммитам
> в
> > своем репозитарии
>
> Как того требует соглашения по проекту. Если я один, то
> обычно и так помню что к чему :)

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


 
Petr V. Abramov ©   (2007-11-20 17:35) [158]

> Сусл ©   (20.11.07 17:19) [157]
> которое приводит к повышению контроля за кодом есть гуд,
в богоугодном деле - главное лоб не расшибить.
если качества становится больше на 10%, а гимра - на 100, ну его нафик такое средство


 
Mystic ©   (2007-11-20 17:48) [159]

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


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

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


 
Сусл ©   (2007-11-20 17:58) [160]


>  [159] Mystic ©   (20.11.07 17:48)

А вот возражу я. И вот чем.

1. Для начала опишу ситуацию. У меня есть некий фреймворк. Писан на Дельфи. Активно его использую. В настоящий момент я еще не сделал то, о чем сейчас скажу, но обязательнос сделаю.
У меня будут обязательными все три звездочки из твоего поста! Плюс еще много других будет ограничений и деклараций. Не вижу ничего в этом плохого, т.к. фреймворк узко специализирован, причем он скорее не ООП парадигмы, а АОП придерживается. Т.е. специфичный, удобный с своей области язык (фреймворк).

2. Вот давай теперь посмотрим на java. Конечно, java не сколько узко заточена под задачу как мой фреймворк. Безусловно JAVA имеет более широкую область применения. Но в тоже время область применения JAVA в текущее время в большнстве своем (имхо, конечно) можно описать как server-side внутри фреймворков (коих до фига, насколько я знаю). Все же JAVA уже, чем общий язык. Ну не придет же в голову писать аркаду на java?

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

select count(*) from delphiusage group by(area)

выдаст большее число, чем аналогичный запрос для JAVA.

РЕЗЮМЕ
А резюме простое. JAVA занимает промежуточное положение между языками общего назначения и узкоспециализированными фреймворками. Посему JAVA не свойственнена такая зажатость, как у узкоспециализированных фреймворков, но в тоже время на нее наложены более строгие ограничения, чем на язык общего назначения.

ЗЫ Про j2me не говорю, имхо отдельная тема.


 
Petr V. Abramov ©   (2007-11-20 18:20) [161]

> Сусл ©   (20.11.07 17:58) [160]
а какой положительный РЕЗУЛЬТАТ мы в сухом остатке имеем благодаря этим ограничениям? Где-то в метеданых появляются сведения обо всех exception, которые метод может поднять? Вообще-то это можно было и на компилятор возложить, а не заставлять руками писать.


 
iZEN ©   (2007-11-20 20:45) [162]


> Petr V. Abramov ©   (20.11.07 17:35) [158]
>
> > Сусл ©   (20.11.07 17:19) [157]
> > которое приводит к повышению контроля за кодом есть гуд,
>
> в богоугодном деле - главное лоб не расшибить.
> если качества становится больше на 10%, а гимра - на 100,
>  ну его нафик такое средство

поэтому и выбирают .Net — там думать меньше надо, как в Delphi. :))


 
Petr V. Abramov ©   (2007-11-20 23:09) [163]

> iZEN ©   (20.11.07 20:45) [162]
ну да java - это ж opensource, там главное побольше думать и руками по клаве стучать, чем больше, чем лучше.


 
Petr V. Abramov ©   (2007-11-20 23:16) [164]

> iZEN ©   (20.11.07 20:45) [162]
РЕЗУЛЬТАТ-то какой от этого КОНТРОЛЯ? Можно без документации прочитать, какие исключения поднимет метод . ЕЩЕ? Если все, сопровождающего гимра не стОит. И этот скромный результат можно достичь другими путями без гимра вовсе.

комментарии писать надо? надо.
давайте сделаем так, чтобы без комментариев программа не компилилась :)
комментарии от этого появятся? появятся. Чужой код читать, глаза не вывихнув, можно будет? Можно, но не чаще, чем без фичи.


 
Petr V. Abramov ©   (2007-11-20 23:29) [165]

допускаю, что при разработке драйвера тормозов ядерной ракеты
> если качества становится больше на 10%, а гимра - на 100,
такое средство оправдано.
Но в случае checked exceptions и этим не пахнет. ИМХО.
P.S. я ж разобраться в вопросе хочу :)


 
iZEN ©   (2007-11-21 08:51) [166]


> Petr V. Abramov ©   (20.11.07 23:16) [164]
>
> > iZEN ©   (20.11.07 20:45) [162]
> РЕЗУЛЬТАТ-то какой от этого КОНТРОЛЯ? Можно без документации
> прочитать, какие исключения поднимет метод . ЕЩЕ? Если все,
>  сопровождающего гимра не стОит. И этот скромный результат
> можно достичь другими путями без гимра вовсе
.

КАКИМИ путями? Если, например, исходники библиотеки потеряны. Сами class-файлы обфусцированы.

Другой пример — "AV" в Delphi аналогична java.lang.Error — в обоих случаях восстановление НЕВОЗМОЖНО. Но в Delphi при этом программа завершается аварийно с возможным сносом половины системы, причём AV можно поймать буквально на ровном месте (я, например, знаю, как подвесить WinXP из-под профиля обычного непривилегированного пользователя); в Java есть большая вероятность при Error программу завершить корректно, закрыв ресурсы, и сноса системы не будет вообще.

Java обеспечивает хоть какую-то возможность восстановления после сбоя. Delphi — практически нет.


 
Petr V. Abramov ©   (2007-11-21 09:46) [167]

> iZEN ©   (21.11.07 08:51) [166]
> Если, например, исходники библиотеки потеряны. Сами class-файлы обфусцированы.
сама библиотека потеряна, голову дома забыл :)

> КАКИМИ путями?
генерацию этих метаданных вполне можно возложить на компилятор.

> Java обеспечивает хоть какую-то возможность восстановления после сбоя. Delphi — практически нет.
как-то голословно. Дельфийская программа прекрасно работает и после AV, и после StackOverflow. Т.е. не прекрасно, а как написана, так и работает. :)Но не гибнет.


 
Romkin ©   (2007-11-21 10:53) [168]


> Java обеспечивает хоть какую-то возможность восстановления
> после сбоя. Delphi — практически нет.

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


 
Mystic ©   (2007-11-21 12:01) [169]

> допускаю, что при разработке драйвера тормозов ядерной ракеты

Там требуется доказательство правильности :)

> Но в Delphi при этом программа завершается аварийно с возможным
> сносом половины системы


Во-первых, это уже проблема операционной системы, не языка программирования. Во-вторых, только так и можно реализовывать решение системных задач :) Так что для кого-то это фича ;) В-третьих, наличие AV говорит просто об ошибку в программе. Зачастую по адресу 0x00000000. Ну замени его на Null reference exception, что поменяется?

Да, есть вероятность того, что будет запить по поврежденному указателю и что-то в памяти перезапишется. Я работал напрямую с указателями очень часто, но такая ситуация возникала почему-то очень редко. Собственно это есть плата за дополнительные возможности (начал использовать указатели, ассемблерные вставки, значит ССЗБ), и я не скажу, что это очень кошмарно.


 
pasha_golub ©   (2007-11-21 13:44) [170]


> iZEN ©   (21.11.07 08:51) [166]


> Но в Delphi при этом программа завершается аварийно с возможным
> сносом половины системы

Это ж надо. А пацаны и не знают. Да мне бы за такое ноги повырывали, ан нет, логи шлют, и после фикса еще и спасибо говорят.


 
Сусл ©   (2007-11-21 14:13) [171]


>  [164] Petr V. Abramov ©   (20.11.07 23:16)
> комментарии писать надо? надо.
> давайте сделаем так, чтобы без комментариев программа не
> компилилась :)
> комментарии от этого появятся? появятся. Чужой код читать,
> глаза не вывихнув, можно будет? Можно, но не чаще, чем без
> фичи.


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

// бла-бла-бла это коммент о функции MyFunc.
// как я круто обдурил анализатор.
// всем привет!


:)


 
pasha_golub ©   (2007-11-21 14:54) [172]


> Сусл ©   (21.11.07 14:13) [171]
>
>


> ты не поверишь, что в некоторых конторах репозитарий не
> принимает исходники

Это глупо, как по мне. Достаточно, чтобы юзер комментировал Commit.


 
Сусл ©   (2007-11-21 15:41) [173]


>  [172] pasha_golub ©   (21.11.07 14:54)
> > ты не поверишь, что в некоторых конторах репозитарий не
> > принимает исходники
> Это глупо, как по мне. Достаточно, чтобы юзер комментировал
> Commit.


В жизни часто бывает все глупо, что не по себе.

Каждый публичный метод должен быть описан. И описан хорошо: параметры, побочные эффекты, семантика, исключение и пр.


 
Mystic ©   (2007-11-21 16:04) [174]

> Как ты думаешь, почему там не делают комментарии типа, чтобы
> обламнуть анализатор


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

Лично мне комментарии в коде обычно только мешают, ибо
 (1) засоряют текст, отвлекая внимание на их изучение;
 (2) указывают на очевидные вещи, которые я и так знал;
 (3) не дают ответа на интересующий вопрос.
Например, когда есть функция memmove, то самый распространенный стиль комментариев состоит в том, чтобы описать назначение функции (что в общем-то понятно) и параметры функции (что очевидно из их названия). А вот вопрос, поддерживаются ли перекрывающиеся блоки обычно замалчивается.


 
Сусл ©   (2007-11-21 16:15) [175]


>  [174] Mystic ©   (21.11.07 16:04)
> Например, когда есть функция memmove, то самый распространенный
> стиль комментариев состоит в том, чтобы описать назначение
> функции (что в общем-то понятно) и параметры функции (что
> очевидно из их названия). А вот вопрос, поддерживаются ли
> перекрывающиеся блоки обычно замалчивается.


ну может ты не те комментарии читаешь?

ну давайте сейчас еще холивар организуем о вреде комментариев, единственной причиной которой является лень их писать.


 
Mystic ©   (2007-11-21 16:38) [176]

> ну может ты не те комментарии читаешь?

Какие написаны, такие и читаю (правда не часто). Какие не написаны, тех не читаю.

> ну давайте сейчас еще холивар организуем о вреде комментариев,
>  единственной причиной которой является лень их писать.


Были уже, и на этом форуме и не на этих...   :) Единого мнения в этом вопросе нет :)


 
iZEN ©   (2007-11-21 17:51) [177]


> Petr V. Abramov ©   (21.11.07 09:46) [167]
>
> > iZEN ©   (21.11.07 08:51) [166]
> > Если, например, исходники библиотеки потеряны. Сами class-
> файлы обфусцированы.
> сама библиотека потеряна, голову дома забыл :)

ну и

> Petr V. Abramov ©   (21.11.07 09:46) [167]
> > КАКИМИ путями?
> генерацию этих метаданных вполне можно возложить на компилятор.


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

javac, например, может разрулить использование любой библиотеки, от которой есть только .class-файлы.


> Petr V. Abramov ©   (21.11.07 09:46) [167]
>
> > Java обеспечивает хоть какую-то возможность восстановления
> после сбоя. Delphi — практически нет.
> как-то голословно. Дельфийская программа прекрасно работает
> и после AV, и после StackOverflow. Т.е. не прекрасно, а
> как написана, так и работает. :)Но не гибнет.


Правильно. Деградирует и гибнет операционная система. Программе на это наплевать. :)


 
Mystic ©   (2007-11-21 18:25) [178]

> javac, например, может разрулить использование любой библиотеки,
>  от которой есть только .class-файлы.


По сути class-файл это и есть сокращенная форма хранения исходников :)

> Деградирует и гибнет операционная система. Программе на
> это наплевать. :)


Начнем с того, что погубить операционную систему непросто. Надо знать, куда и с какой силой ударить. Случайно это у меня это выходило только с Windows 98 (один раз). С другой стороны, баг в реализации виртуальной машины может привести к аналогичным последствиям ;)


 
Юрий Зотов ©   (2007-11-21 19:01) [179]

Однако же, не все так просто...

Реальный случай. Возникла у меня на днях необходимость сделать объект клонируемым. Согласно доке, для этого нужно:

1. В заголовке класса объявить: implements Cloneable  
2. Перекрыть protected метод clone базового класса Object и сделать его public.
3. В перекрытом методе clone реализовать создание клона, сначала вызвав в нем унаследованный метод, который создает копию "бит в бит".

В базовом классе Object метод clone имеет такое объявление:
protected Object clone() throws CloneNotSupportedException
причем унаследованный метод clone возбуждает CloneNotSupportedException в том случае если в объявлении класса не объявлена реализация им интерфейса Cloneable.

Все ясно и никаких проблем нет. Но есть несколько вопросов.

Вопрос первый.
Если я перекрываю метод clone и делаю его public, то делаю это, видимо, не просто так, а именно для того, чтобы сделать объект клонируемым. Тогда зачем нужно еще и объявлять то же самое в заголовке?

Вопрос второй.
И наоборот - раз уж в заголовке моего класса объявлено, что интерфейс Cloneable им поддерживается, то унаследованный метод clone исключения CloneNotSupportedException выбросить не может. Мой перекрытый метод clone его тоже не выбрасывает. В таком случае почему мне навязывают объявление этого метода с якобы выбрасываемым исключением, если это самое исключение выбросится не может физически?

Но это все семечки - а вот самое главное.

Вопрос третий.
Перекрытый мною метод clone обращается к БД - то есть, может возникнуть исключение SQLException. Но выбросить его я не могу, потому что в заголовке метода декларировано только CloneNotSupportedException. Что ж, думаю, нет проблем - щас мы завернем одно в другое. И пишу:
try {
 ...
} catch (SQLException e) {
 throw new CloneNotSupportedException("Мое сообщение", e);
}


Казалось бы, все хорошо? А фигушки! Оказывается, у класса CloneNotSupportedException есть один конструктор с параметром String и второй конструктор вообще без параметров. А на вызов конструктора с параметрами (String, Throwable) идет ругань - хотя такой конструктор есть у класса - прародителя всех исключений Throwable и этот конструктор public.

Что ж, думаю, ладно, мы его сначала просто создадим, потом сделаем ему setCause(e), а уж потом возбудим. И все будет ОК.

А фиг-то! Нет такого метода - setCause.

Что ж это получается - что завернуть в исключение CloneNotSupportedException другое исключение, выходит, нельзя?

Но тогда сабж ветки снова обретает актуальность.


 
Сусл ©   (2007-11-21 19:06) [180]

Юра, ты папааал... :)

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

у меня вопрос: почему ты не хочешь сделать Runtime исключение?


 
C0s   (2007-11-21 19:59) [181]

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

3) если метод clone лазит в БД, то не нужно вообще это делать через clone, сделай лучше копирующий конструктор с теми исключениями, которые тебе нравятся.

ps. за 5+ лет полёта на java мне ни разу вообще не довелось додуматься до использования метода clone


 
Сусл ©   (2007-11-21 20:47) [182]

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


 
jack128_   (2007-11-21 20:59) [183]


> А на вызов конструктора с параметрами (String, Throwable)
> идет ругань - хотя такой конструктор есть у класса - прародителя
> всех исключений Throwable и этот конструктор public.

не понял, как это? у предка есть public метод, а у потомка нет???  Я думал, что такой бред тока в С++ есть.


 
Сусл ©   (2007-11-21 21:00) [184]


>  [183] jack128_   (21.11.07 20:59)

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


 
jack128_   (2007-11-21 21:01) [185]


> хотя такой конструктор есть у класса - прародителя всех
> исключений Throwable и этот конструктор public.

Ы?


 
Petr V. Abramov ©   (2007-11-21 21:05) [186]

> Сусл ©   (21.11.07 14:13) [171]
> почему там не делают комментарии типа, чтобы обламнуть анализатор
думаю, потому что там так принято. И БЕЗ УЩЕРБА наработанному можно перейти на политику "давать нормальные имена переменным". В той же VCL комментариев откровенно мало, но они почти все по делу, а не
commit; // в базу!

> iZEN ©   (21.11.07 17:51) [177]
> Возложите "генерацию метаданных" на компилятор  Delphi, чтобы он
> поддержал статическую линковку вашей программы с левоприобретённой BPL-библиотекой.
статическая линковка и BPL - вещи из разных опер.

> Сусл ©   (21.11.07 15:41) [173]
> Каждый публичный метод должен быть описан.
описано ЧТО он делает или КАК он делает?
если КАК - значит, надо выкинуть нафик идею виртуальных методов и предложить что-то свое. Или сказать, что виртуальные методы - хорошо, но от них столько гимра, что использовать их не надо. И обосновать.


 
Сусл ©   (2007-11-21 21:12) [187]


> [185] jack128_   (21.11.07 21:01)
> > хотя такой конструктор есть у класса - прародителя всех
> > исключений Throwable и этот конструктор public.
> Ы?


Что Ы? Справку по языку просто Юре надо читать :)
Ну взять Эккеля, например. И всего его прочесть за 3-4 недели.
Тогда и проблем будет меньше.

Если по сути твоего Ы, то конструкторы нужно явно объявлять.


 
Сусл ©   (2007-11-21 21:14) [188]


> [186] Petr V. Abramov ©   (21.11.07 21:05)

Ты видел доку к методам в стандартной библе от java?

Вот например. Чем плохо?

/**
    * Constructs a new exception with the specified detail message and
    * cause.  <p>Note that the detail message associated with
    * cause is not automatically incorporated in
    * this exception"s detail message.
    *
    * @param  message the detail message (which is saved for later retrieval
    *         by the {@link #getMessage()} method).
    * @param  cause the cause (which is saved for later retrieval by the
    *         {@link #getCause()} method).  (A <tt>null</tt> value is
    *         permitted, and indicates that the cause is nonexistent or
    *         unknown.)
    * @since  1.4
    */
   public Exception(String message, Throwable cause) {
       super(message, cause);
   }


Вообще, поставь себе JDK+NetBeans. Много времени не займет. Зато многие вопросы уйдут.


 
jack128_   (2007-11-21 21:19) [189]


> Если по сути твоего Ы, то конструкторы нужно явно объявлять.
в _каждом_ классе?? то есть чтобы сделать конструктор public - нуно явно в каждом потомке его объявить?  Ну.. Возможно что то в этом есть. Если в джаве нет метаклассов.


 
Сусл ©   (2007-11-21 21:23) [190]


> [189] jack128_   (21.11.07 21:19)

Я сам java плохо знаю (вернее почти не знаю). Иногда к товарищу своему обращаюсь за констуальтацией (C0s, кстати - это он), когда хочу что-то понять получше, ну и сам пробую в NetBeans.

Могу по поводу java сказать одно - у нее есть философия. Возможно, что не совсем привычная программисту на Дельфи. Но знать ее, если собираешься писать на java, нужно обязательно. Благо и одноименная книга есть :)


 
Petr V. Abramov ©   (2007-11-21 21:23) [191]

> Сусл ©   (21.11.07 21:14) [188]
к VCL Help есть, в котором это все написано.
если в java этот хелп - в комментариях в заголовках - тоже сойдет. А почему бы и список exception`ов там не прописать?

> Вообще, поставь себе JDK+NetBeans. Много времени не займет. Зато многие вопросы уйдут.
а у меня их нет :)
если использование виртуальных методов, скажем так, затруднено, нафик эту  жабу. про какие-то дополнительные ПОЛЕЗНЫЕ фичи сопоставимой полезности никто, по крайней мере в этой ветке, не сказал


 
Petr V. Abramov ©   (2007-11-21 21:26) [192]

> Могу по поводу java сказать одно - у нее есть философия.
ну отсутствием ЭТОГО никто не страдает :)
А философам, как известно, даже ластики не нужны.


 
Petr V. Abramov ©   (2007-11-21 21:29) [193]

Еще раз - кроме того, что список поднимаемых исключений МОЖНО ПОСМОТРЕТЬ
результат какой-нить есть от фичи?


 
tesseract ©   (2007-11-21 21:41) [194]


> а у меня их нет :)


У меня есть - как на этой *не чего нить сделать. Включая весьма интересные комменты самой Sun по поводу кривого инсталера. Работать можно, но вот гемор с IDE......


 
Petr V. Abramov ©   (2007-11-21 21:49) [195]

> tesseract ©   (21.11.07 21:41) [194]
> У меня есть - как на этой *не чего нить сделать.
судя по всему, ответ универсальный: ректально :)


 
Petr V. Abramov ©   (2007-11-21 22:36) [196]

ИМХО, надо на каком-нить жабогуруссом форуме задать вопрос от имени Delphimaster:
сhecked exceptions с витруальными методами совместимы хорошо или плохо?
ветку (эту) закрыть, открыть новую со ссылкой на жабский форум, читать и между собой комментировать
:)
А то тут большинство в жабе чайники, за exception относительгно очень малого числа читателей/писателей
:)))


 
Суслик ©   (2007-11-22 00:52) [197]


> Petr V. Abramov ©   (21.11.07 22:36) [196]
> ИМХО, надо на каком-нить жабогуруссом форуме задать вопрос
> от имени Delphimaster:сhecked exceptions с витруальными
> методами совместимы хорошо или плохо?

Такой флейм регулярно возникает в разных форумах.
Он просто не интересен уже, ибо имеет одну отличительную черту - противники мало читали книг по java. Не то, чтобы эти книги нужно читать, как мантру. Дело в том, что сложно спорить, если имеешь мало знаний в предмете. В любом случае для спора нужна платформа знаний предмета + опыт. Будешь спорить?


 
Юрий Зотов ©   (2007-11-22 10:05) [198]

> Сусл ©   (21.11.07 19:06) [180]

> почему ты не хочешь сделать Runtime исключение?


Каким образом в этой конкретной ситуации сделать Runtime исключение?
Если вот таким:
try {
 ...
} catch (IOException e) {
 throw new RuntimeException(...)
}

то точно так же я могу возбудить и CloneNotSupportedException. Что именно возбуждать - это вообще не вопрос и не проблема. Проблема в том, что в любом случае будет подмена исключения - а это есть бред. И скажи - почему программеру навязывается вот такой бредовый стиль кодинга?

> C0s   (21.11.07 19:59) [181]

> если метод clone лазит в БД, то не нужно вообще это делать через
> clone, сделай лучше копирующий конструктор с теми исключениями,
> которые тебе нравятся.


Это ясно, что никто не запрещает сделать для создания клона вообще ЛЮБОЙ метод. Хоть конструктор, хот makeClone, хоть что угодно еще. И ясно, что заткнется этот компилятор как миленький, вместе со своими выкрутасами. Но с какой-такой радости я должен изобретать велосипед, ежели существует механизм, специально для того и сделанный? Только лишь потому, что механизм этот сделан через не то место?

Не верю. Понимаете, я не верю, что класс Object писали дураки. Наоборот, я не сомневаюсь, что его писали очень умные и очень опытные люди. И если они сделали именно так - значит, какой-то смысл в этом есть, что-то они в виду имели. Вот в ЭТОМ и хочется разобраться.

> за 5+ лет полёта на java мне ни разу вообще не довелось
> додуматься до использования метода clone


А мне ни разу не довелось писать 3D-игру. А кто-то только этим и занимается. Но не решает диффуров. А кто-то только их и решает. И что?

> Сусл ©   (21.11.07 21:12) [187]

Дим, огромное спасибо за ценный совет читать книги. Только это... видишь ли, Эккеля я как бы читал. И как бы далеко не раз. И что конструктор может в потомке стать недоступным - это я в курсе. Но не могу понять - а почему и зачем так сделано? Неудобно ведь.

Вот в данном конкретном случае - никто не мешает написать потомка CloneNotSupportedException и объявить в нем конструктор с параметрами (String, Throwable). И все завернется, как миленькое. Но остается тот же вопрос - порождать потомка класса лишь для того, чтобы сделать доступным нужный конструктор - это есть бред. И почему этот бред мне навязывают? Что, модель ООП для джавы дураки придумывали? Не верю. Тогда чего они хотели этим скрытием конструкторов добиться?

А насчет того, что у джавы философия есть - может, и есть. Но слова твои прозвучали, тем не менее, голословно. Потому что оттого, что кто-то перевел "Thinking in Java" как "Философия Java", никакой философии еще не возникло - а никаких других доказательств ты не привел.

То, что броско названо какой-то там "философией" называется на самом деле проще, понятнее и конкретнее - "реализованная модель ООП". И она есть в ЛЮБОМ ОО-языке, потому что иначе не бывает. Ну так вот - некоторые аспекты этой реализации в Jav"е выглядят, как минимум, недостаточно продуманными. Что очень странно - и в чем и хочется разобраться.

Я уж не говорю о странной логике, когда отцы-основатели:

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

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


 
Сусл ©   (2007-11-22 10:35) [199]


>  [198] Юрий Зотов ©   (22.11.07 10:05)

Ладно, про Эккеля извини. Читал - хорошо. Нет повода тебе не верить.

Не отвечая никакой конкретной твоей фразе я попробую ответить тебе в общем.

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

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

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

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

Вот ты говоришь, что не веришь, что создатели Object дураки. А может они и дураки? Почему нет? Я, например, не имею четкого мнения по этому поводу. Согласись, что любому ублюдству можно найти оправдание. Если ты знаешь это оправдание, то ты в теме и перестаешь удивляться нелогичным на твой взгляд вещам. Тебе нужно просто понять и согласиться с нелогичностиями. Ну или идти обратно к нам, на Дельфи писать :)

Вообще, если тебе интересно пофилософствовать на тему Checked Exceptions, то тебе дорога на java форум на RSDN. Там есть любители пообщаться на тему философии java. Если и не ответят, то пошлют на буржуинский форум почитать на эту тему.

Извини, но странно выглядит твоя попытка обсудить это здесь, на форуме по дельфи. Тут java разработчиков мало. Вот iZen есть, но он же как пророк java среди дельфистов. Другие серьезные java разработчики сюда не ходят (простите, если ошибаюсь). Вот C0s заходил. Если интересно, то можешь с ним сцепится (если получится, конечно) на упомянутом выше RSDN. Могу тебя заверить, что он очень серьезный собеседник.


 
euru ©   (2007-11-22 10:55) [200]


> Юрий Зотов ©   (22.11.07 10:05) [198]

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


 
Юрий Зотов ©   (2007-11-22 11:06) [201]

> euru ©   (22.11.07 10:55) [200]

И от чего же тут надо защищаться?

Вот есть конструктор Throwable(String, Throwable).
Есть потомок этого класса CloneNotSupportedException.
Почему нельзя написать new CloneNotSupportedException("...", e)?
В чем тут опасность, от которой надо защищаться?


 
Сусл ©   (2007-11-22 11:13) [202]


>  [201] Юрий Зотов ©   (22.11.07 11:06)
> > euru ©   (22.11.07 10:55) [200]
>
> И от чего же тут надо защищаться?
>
> Вот есть конструктор Throwable(String, Throwable).
> Есть потомок этого класса CloneNotSupportedException.
> Почему нельзя написать new CloneNotSupportedException("...",
> e)?
> В чем тут опасность, от которой надо защищаться?


Позволь я отвечу?
Здесь как бы 2 направления мысли есть - почему в языке конструкторы не наследуются, почему конкретный разработчик класса CloneNotSupportedException (ты же недумаешь, что именно придумывал язык) не отнаследовал требуемый тебе конструктор?

по первому вопросу сказать нечего - для этого и топик заведен :) авось ближе к концу ясно станет, почему так сделано.

по второму же скажу, что конкретному разработчику показалось, что так правильно - класс CloneNotSupportedException должен иметь всего 2 контструктора () и (String) ибо исключение предполагает информирование о том, что клонирование не поддерживается как функционал, а не для того, чтобы сообщать об ошибках SQL.


 
Юрий Зотов ©   (2007-11-22 11:35) [203]

> конкретному разработчику показалось, что так правильно

И он, конечно же, был настолько глуп, что не подумал о том, что клон может создаваться из внешнего источника данных (файл, БД, сеть); что при обращении к этому источнику могут возникать свои исключения, что метод clone выбрасывания этих исключений не допускает и возникнет необходимость их оборачивания...

Дим, ну не верю я что он настолько дурак. Тут что-то другое.


 
Сусл ©   (2007-11-22 11:41) [204]


> Дим, ну не верю я что он настолько дурак. Тут что-то другое.

может быть не стоит нагружать такой функциональнсотью клон?
почитай в Эккеле 3-е издание Приложение А раздел "клонирование"
там страниц 20 текста, есть кстати подраздел "почему сделано так странно?".

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


 
euru ©   (2007-11-22 11:56) [205]


> Юрий Зотов ©   (22.11.07 11:06) [201]

> Почему нельзя написать new CloneNotSupportedException("...", e)?

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


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


 
Petr V. Abramov ©   (2007-11-22 13:23) [206]

> Юрий Зотов ©   (22.11.07 11:35) [203]
> Дим, ну не верю я что он настолько дурак. Тут что-то другое.

"не ищите сложные объяснения простых вещей" :)))


 
iZEN ©   (2007-11-22 14:28) [207]



> Юрий Зотов ©   (22.11.07 10:05) [198]
> Не верю. Понимаете, я не верю, что класс Object писали дураки.
>  Наоборот, я не сомневаюсь, что его писали очень умные и
> очень опытные люди. И если они сделали именно так - значит,
>  какой-то смысл в этом есть, что-то они в виду имели. Вот
> в ЭТОМ и хочется разобраться.


Знаете что, на это я могу посоветовать почитать книжки в такой последовательности:

• Кен Арнолд, Джеймс Гослинг, Дэвид Холмс, «Язык программирования Java», 3-е издание (изд. Вильямс, 2001г);
• Стивен Стелтинг «Java без сбоев: обработка исключений, тестирование, отладка» (изд. КУДИЦ-ОБРАЗ, 2005г);
• Джошуа Блох «Java. Эффективное программирование» (изд. Лори, 2002г).

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


 
iZEN ©   (2007-11-22 14:47) [208]

Можно я влезу в вашу дискуссию?

Влезаю.

> Юрий Зотов ©   (22.11.07 10:05) [198]
>
> Дим, огромное спасибо за ценный совет читать книги. Только
> это... видишь ли, Эккеля я как бы читал. И как бы далеко
> не раз. И что конструктор может в потомке стать недоступным
> - это я в курсе. Но не могу понять - а почему и зачем так
> сделано? Неудобно ведь.


Почему неудобно? Вы про образцы проектирования слышали? Про Фабричный метод, про Синглтон?
Так оно для поддержки всего этого и сделано.
А ещё есть такое понятие как КОНТРАКТ.


> Юрий Зотов ©   (22.11.07 10:05) [198]
>
> Вот в данном конкретном случае - никто не мешает написать
> потомка CloneNotSupportedException и объявить в нем конструктор
> с параметрами (String, Throwable). И все завернется, как
> миленькое.


Не факт.
Метод Object.clone() может быть весьма нетривиален в потомках: как делать клонирование ГЛУБОКО (строить клоны всех полей и объектов, всю композицию объекта) или ПОВЕРХНОСТНО (только для нефинальных полей примитивного типа)?

Интерфейс Cloneable — это интерфейс-метка. Он предопределяет МИКСИН (примесь), которую можно приделать к потомкам. Обычные интерфейсы кроме этого определяют больше семантики, а именно доопределяют КОНТРАКТ. Интерфейс Cloneable не задаёт контракт.

Почему так сделали — я лично не понял — слишком много степеней свободы дали методу клонирования, а вот что не додали — вопрос.


> Юрий Зотов ©   (22.11.07 10:05) [198]
> Но остается тот же вопрос - порождать потомка
> класса лишь для того, чтобы сделать доступным нужный конструктор
> - это есть бред. И почему этот бред мне навязывают? Что,
>  модель ООП для джавы дураки придумывали? Не верю. Тогда
> чего они хотели этим скрытием конструкторов добиться?


Скрытие конструкторов очень помогает заменить наследование агрегацией. Иерархическая ООП-модель системы довольно часто не выдерживает критики по сложности реализации.


> Юрий Зотов ©   (22.11.07 10:05) [198]
>
> А насчет того, что у джавы философия есть - может, и есть.
>  Но слова твои прозвучали, тем не менее, голословно. Потому
> что оттого, что кто-то перевел "Thinking in Java" как "Философия
> Java", никакой философии еще не возникло - а никаких других
> доказательств ты не привел.


Брюса Эккеля лучше не читать. У него какая-то "своя" философия. Например, он не уверен надёжности реализации многопоточности.


> Юрий Зотов ©   (22.11.07 10:05) [198]
>
> То, что броско названо какой-то там "философией" называется
> на самом деле проще, понятнее и конкретнее - "реализованная
> модель ООП". И она есть в ЛЮБОМ ОО-языке, потому что иначе
> не бывает. Ну так вот - некоторые аспекты этой реализации
> в Jav"е выглядят, как минимум, недостаточно продуманными.
>  Что очень странно - и в чем и хочется разобраться.


Выглядит "иначе", чем в любых других ООП-языках. Ещё нужно учсть, что в своём развитии язык Java претерпевал изменения и философия языка тоже преобразовывалась в силу того, что системными библиотеками занимались и занимаются разные люди. Переписать всё с нуля невозможно, так как Java поддерживает обратную совместимость до сих пор с версией 1.0.2.


 
euru ©   (2007-11-22 15:19) [209]


> iZEN ©   (22.11.07 14:47) [208]

> Про Фабричный метод, про Синглтон? Так оно для поддержки
> всего этого и сделано.

> Скрытие конструкторов очень помогает заменить наследование
> агрегацией.
А это точно не следствие архитектуры Java?


 
DiamondShark ©   (2007-11-22 17:36) [210]


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



> ну не верю я что он настолько дурак. Тут что-то другое


Это другое сильно напоминает байку про диаметр ракеты-носителя и ширину конской задницы.

Берём Ц++, пишем:

class Foo
{
public:
Foo(int i, int j)
{
}
};

class Bar: Foo
{
};

Foo* foo = new Foo(1,2); // Ok
Bar* bar = new Bar(1,2);  // Figvam
return 0;

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

Нафига это в managed языках, где поля экземпляра инициализируются значениями по умолчанию (иначе бы GC не работал!) -- лешему известно.
В Яву и СиШарп такое поведение явно собезьяничали с того, что было вдолблено в головы.

Все умные слова про шаблоны и фабрики -- это уже рационализация задним числом.


 
iZEN ©   (2007-11-22 17:39) [211]


> euru ©   (22.11.07 15:19) [209]
>
> > iZEN ©   (22.11.07 14:47) [208]
>
> > Про Фабричный метод, про Синглтон? Так оно для поддержки
> > всего этого и сделано.
>
> > Скрытие конструкторов очень помогает заменить наследование
> > агрегацией.
> А это точно не следствие архитектуры Java?


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


 
DiamondShark ©   (2007-11-22 18:00) [212]


> привело к рождению на свет таких сущностей как "класс-одиночка",
>  "фабричный метод"

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

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


 
Petr V. Abramov ©   (2007-11-22 23:24) [213]

> DiamondShark ©   (22.11.07 17:36) [210]
у тебя ссылки нет живой.
а то нифигандекс на слова ракета и сопутствующие выдает из цензурного про покупку лошадей
:)


 
J_f_S   (2007-11-22 23:41) [214]


> а то нифигандекс на слова ракета и сопутствующие выдает
> из цензурного про покупку лошадей:)

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



Страницы: 1 2 3 4 5 6 вся ветка

Форум: "Прочее";
Текущий архив: 2007.12.23;
Скачать: [xml.tar.bz2];

Наверх





Память: 1.27 MB
Время: 0.046 c
9-1164018658
Ярослав Ерёменко
2006-11-20 13:30
2007.12.23
Алгоритм отрисовки тайлов методом альфа-блендинга


15-1195764332
Mul
2007-11-22 23:45
2007.12.23
А есть какие-нибудь статьи у Анатолия Подгоретского?


15-1195800245
KSergey
2007-11-23 09:44
2007.12.23
Пресловутый переход на висту


15-1195829870
Cyrax
2007-11-23 17:57
2007.12.23
Как лучше всего организовать следующие действия


1-1191232247
Yurikon
2007-10-01 13:50
2007.12.23
Директивы компилятору





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский