Здравствуйте, AlexRK, Вы писали:
C>>В Rust принципиально в сигнатуре функции указывают весь контракт для типов. Хотя можно в качестве сахара на уровне компилятора, конечно, сделать. ARK>Я не очень понятно выразился, я имел в виду — оставить в сигнатуре все, что есть, но убрать из тела "try" и "?".
Можно, причём несложными изменениями в компиляторе. Остаётся вопрос не лучше ли оставить явные ? для улучшения читабельности.
Здравствуйте, alex_public, Вы писали:
_>Преимущества исключений появляются, только если обработка ошибки идёт где-то намного выше (по стеку вызова, не по линейному коду) вызова Save.
Я так и думал — у тебя вызываемый код знает детали реализации вызывающего кода. Браво !
I>>То есть, ты предлагаешь переписывать весь слой, если мы начнем вызывать его немного другим способом. Правильно тебя понимаю ?
_>При проектирование приложения такие вещи (что критично, а что нет) сразу понятны, так что по нормальному никаких переписываний не должно быть. А вот в случае библиотек оптимальным было бы наличие обоих видов интерфейсов...
Ну да, дизайн сразу очевиден на любой срок наперёд. В твоих проектах похоже треботвания никогда не менялись.
ребята послушали alex_public и пришли к тому, от чего хотели убежать. Собтсвенно демонстрация того, что возврат значения даёт хаос уже на самом первом уровне
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, uncommon, Вы писали:
C>>>Вот теперь делаем так, чтобы write кидал исключение, а потом в деструкторе socket'а ещё раз исключение вылезало (вполне реальная ситуация!). U>>Вот так говоришь с человеком, вроде как всё нормально. А потом бабах! Он выдаёт тебе такое. И не знаешь, что думать. C>Ну а что делать? В деструкторе сокета, очевидно, будет вызываться библиотечный close(). Который может возвращать ошибки: http://linux.die.net/man/2/close
close() может возвратить ошибку, а деструктор socket'а исключение выбросить не может. Подумай сам, что этот деструктор делает. И посмотри реализацию твоей любимой библиотеки для работы с файлами или с сетью.
C>В некоторых условиях эти ошибки будут важны, так как они могут означать, что буферизованные данные не были записаны в сокет/файл/пайп.
Хочешь, чтобы была уверенность в том, что буферизованные данные были записаны, вызывай явно функцию в конце работы с socket-ом. На деструктор нельзя в этом случае надеяться.
Здравствуйте, alex_public, Вы писали:
_>Я говорю тебе, что всё зависит от точки обработки ошибок, а не от наличия/отсутствия цепочек. Если у нас точка обработки идёт на следующем уровне, то разницы между исключениями и кодами возврата не будет. Ну или даже исключения похуже выглядят:
ой ли?
_>
_>void Save()
_>{
_> ...
_> if(...) throw MyException("не могу открыть файл");
_> ...
_> if(...) throw MyException("не могу сериализовать данные");
_> ...
_> if(...) throw MyException("не могу записать данные в файл");
_> ...
_>}
_>...
_>try{
_> Save();
_>}catch(MyException& e){
_> ShowError("Не могу сохранить данные , случилось страшное: " + e.what());
_>}
_>
_>
_>
_>const int OK = 0, ERROR_OPEN = 1, ERROR_SERIAL = 2, ... ; // да, надо вести список кодов ошибок. Кстати это глобальные ошибки или ошибки функции Save() ?
_>string getSaveErrorString(int);// и поддерживать в согласованном состоянии соотв функцию
_>int Save()
_>{
_> ...
_> if(...) return ERROR_OPEN;
_> ...
_> if(...) return ERROR_SERIAL;
_> ...
_> if(...) return ERROR_WRITE;
_> doSomething();// ой, забыли проверить код
_> switch(doSomethingElse()) { // ой, надо перекодировать
_> case ELSEERR_OK: break;
_> case ELSEERR_SOME_WRONG: return ERROR_SERIALIZE;
_> default: return ERROR_UNKNOWN;
_> }
_> ...
_> return OK;
_>}
_>...
_>auto err = Save()
_>if(err!=OK) ShowError("Не могу сохранить данные. Случилось страшное: " + getSaveErrorString(err)); // А как получить вложенный код ошибки? - упс, int мало, надо городить что-то свое...
_>
Здравствуйте, Cyberax, Вы писали:
C>Ну а что делать? В деструкторе сокета, очевидно, будет вызываться библиотечный close(). Который может возвращать ошибки: http://linux.die.net/man/2/close
C>В некоторых условиях эти ошибки будут важны, так как они могут означать, что буферизованные данные не были записаны в сокет/файл/пайп.
ну вестимо должен быть явный метод close(), который можно позвать, если важна судьба буферизованных данных. А деструктор исключение глотает, возможно что-то записывая в лог...
А, кстати, как это разруливается в питоне/шарпе/яве (деструкторов там нет, но есть with)?
И что нам по этому поводу предлагают коды возврата?
Здравствуйте, enji, Вы писали:
C>>В некоторых условиях эти ошибки будут важны, так как они могут означать, что буферизованные данные не были записаны в сокет/файл/пайп. E>ну вестимо должен быть явный метод close(), который можно позвать, если важна судьба буферизованных данных. А деструктор исключение глотает, возможно что-то записывая в лог...
А как быть с библиотечным кодом, который может не знать в какой лог ему писать?
E>А, кстати, как это разруливается в питоне/шарпе/яве (деструкторов там нет, но есть with)? E>И что нам по этому поводу предлагают коды возврата?
Пользователя заставят явно обработать возможную ошибку.
Здравствуйте, uncommon, Вы писали:
C>>Я подобный подход и в С++ использовал. U>Подкинь ссылочку? Интересно посмотреть.
Лень искать, что-то типа такого:
Здравствуйте, uncommon, Вы писали:
C>>Ну а что делать? В деструкторе сокета, очевидно, будет вызываться библиотечный close(). Который может возвращать ошибки: http://linux.die.net/man/2/close U>close() может возвратить ошибку, а деструктор socket'а исключение выбросить не может. Подумай сам, что этот деструктор делает.
У деструктора есть магические силы, позволяющие ему избегать ошибок в close()?
U>И посмотри реализацию твоей любимой библиотеки для работы с файлами или с сетью.
Дефолтная реализация паникует задачу. При использовании явной обработки через вызов drop — на совести пользователя.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, vsb, Вы писали:
PD>Добавлю свои три копейки.
PD>1. Скорость обработки. Впрочем, от среды исполнения зависит. В нативных средах Винде+MSVC исключения реализуются через переход в кольцо 0 и обратным возвратом. Обработка исключений далеко не так проста, как кое-кому тут кажется.
Я исправил у тебя ошибку там.
Это в чистом виде артефакут MSVC, все вопросы к нему. Мало того, что Винда — не единственная ось на рынке, так и MSVC — не единственный компилятор под винду. Ходить в ядро, потому что в пользовательском коде что-то не распарсилось — это бред, потому что мешает всем работающим процессам.
С другой стороны, даже если это и так, то и хрен бы с ним.
Во-первых, нам нужна скорость работы код в отсутствие исключений, а не когда они летят как лепестки сакуры; а во-вторых, Винда — это ось для домохозяек, кто там в ней походы в ядро считает, "косынка" работает — и ладно...
Здравствуйте, AlexRK, Вы писали:
ARK>Здравствуйте, uncommon, Вы писали:
ARK>>>А в моей присутствует. Кто из нас прав? U>>Покажи свой код. Дьявол, как обычно, в деталях.
ARK>Код принадлежит не мне, поэтому показать его я не могу. ARK>Но могу ответить на любые уточняющие вопросы.
Это беспредметный разговор. Речь идет именно о коде.
Так что покажи код. Переименуй там все классы/переменные, чтоб не было ничего секретного.
ARK>Хотя, честно говоря, не вижу смысла в этом. То, что многие (а из мною лично виденных — все без исключения) крупные системы содержат кучу мусора с try/catch/finally — это факт. То, что это можно переписать лучшим образом — тоже факт. То, что это не переписывается — тоже факт. О чем спор?
Упоминание finally намекает, что код, о котором ты говоришь — не С++. Тогда да, вопросов нет — там ад и израиль.
Здравствуйте, Pzz, Вы писали:
Pzz>Этим исключениям хорошо бы как-то законодательно синтаксически ограничить дальность полета. Потому что когда в ваш высокоуровневый код, работающий в терминах высокоуровневых абстракций, откуда-нибудь с самого нижнего уровня прилетит исключение про то, чего вы в своем высокоуровневом коде сказать-то и не можете, то что вы с ним будете делать?
Мне нравится как в джаве сделано, все функции генерирующие исключения специально помечаются. И либо ты его обрабатываешь, либо тоже генерируешь исключение. И это все видно в коде.
PD>>1. Скорость обработки. Впрочем, от среды исполнения зависит. В нативных средах Винде+MSVC исключения реализуются через переход в кольцо 0 и обратным возвратом. Обработка исключений далеко не так проста, как кое-кому тут кажется.
J>Я исправил у тебя ошибку там.
Не понял. Где там исправил и как ? И что за ошибка ?
J>Это в чистом виде артефакут MSVC, все вопросы к нему. Мало того, что Винда — не единственная ось на рынке, так и MSVC — не единственный компилятор под винду.
Я про другие ОС и не говорил. Что же касается MSVC — не знаю, как там GNU C++ с ними обходится, если знаешь — расскажи.
>Ходить в ядро, потому что в пользовательском коде что-то не распарсилось — это бред, потому что мешает всем работающим процессам.
Тем не менее это так. Мешает — согласен.
J>С другой стороны, даже если это и так, то и хрен бы с ним. J>Во-первых, нам нужна скорость работы код в отсутствие исключений,
Это спорный вопрос. Исключения — не всегда ошибки, а порой и контракт.
До ошибок , действительно, лучше дело не доводить, вместо того, чтобы доводить и обрабатывать — насколько возможно. К примеру, выход индекса за границы массива лучше просто не допускать.
А вот контракт предполагает, что вполне законными являются действия по всем его вариантам : как с нормальным выходом, так и с исключением.
Вот тебе пример, позаимствованный у Рихтера.
Сильно разреженная очень большая матрица. Операция всего одна — занести элемент. Память надо экономить. Поэтому резервируем АП под всю матрицу (VirtualAlloc/MEM_RESERVE), при этом ни одного байта не выделяется, а потом, ничтоже сумняшеся, пишем по нужному адресу. Естественно, получаем exception (AV), коммитируем 4Кб, включающие нужный адрес (VirtualAlloc/MEM_COMMIT), повторяем операцию. Следующий раз мы либо попадем в эти 4 Кб, тогда доступ без AV, либо в другое место, тогда еще 4 Кб и т.д.
Как видишь, исключения здесь не есть что-то ненормальное, а есть вполне нормальный code flow. Да, они не при каждом обращении будут происходить. Но будут, и это нормально.
>а не когда они летят как лепестки сакуры; а во-вторых, Винда — это ось для домохозяек, кто там в ней походы в ядро считает, "косынка" работает — и ладно...
Устраивать холивар насчет Windows против других осей я не буду. И без того на RSDN мегабайты на этот счет написаны.
Здравствуйте, Cyberax, Вы писали:
E>>ну вестимо должен быть явный метод close(), который можно позвать, если важна судьба буферизованных данных. А деструктор исключение глотает, возможно что-то записывая в лог... C>А как быть с библиотечным кодом, который может не знать в какой лог ему писать?
Банально. Код получает колбэк, который и дергает в таком случае...
C>Пользователя заставят явно обработать возможную ошибку.
коды возврата заставят? Скорее — программист может разрулить ситуацию вручную, если не забудет об этом... Та же штука и с close в деструкторе — ты можешь позвать его явно и разрулить ошибку. А можешь не звать, тогда деструктор поступит умолчательным образом (ошибку проглотит)
Здравствуйте, uncommon, Вы писали:
U>Всё ясно видно: обработка ошибок делегируется на уровень выше. Абсолютно одинаково с кодом на расте, только там делегирование надо производить явно. С исключениями надо привыкнуть к одному лишь правилу, что если нет обработки на данном уровне, то она делегируется на уровень выше.
Ничего ясно не видно. Если функцию, бросающую исключения, писали не мы, то надо лезть в документацию (если она есть) или вообще в исходники, чтобы понять кидаются ли какие-то исключения или нет. В случае же кодов возврата (к примеру) всё сразу видно по заголовочному файлу.
Ну во-первых если делать всё всё по правильному, то не забудь ещё реализацию своего класса исключений для данной функции... )
А во-вторых я на практике обычно не использую даже коды возврата — только булево значение, т.к. обычно пользователю вообще не нужно знать низкоуровневые детали. А в данном примере я написал так, чтобы никто не придрался (мол с исключениями передаётся больше информации).
Здравствуйте, jazzer, Вы писали:
J>Я исправил у тебя ошибку там. J>Это в чистом виде артефакут MSVC, все вопросы к нему. Мало того, что Винда — не единственная ось на рынке, так и MSVC — не единственный компилятор под винду. Ходить в ядро, потому что в пользовательском коде что-то не распарсилось — это бред, потому что мешает всем работающим процессам.
J>С другой стороны, даже если это и так, то и хрен бы с ним. J>Во-первых, нам нужна скорость работы код в отсутствие исключений, а не когда они летят как лепестки сакуры; а во-вторых, Винда — это ось для домохозяек, кто там в ней походы в ядро считает, "косынка" работает — и ладно...
Вообще то seh как раз лучше других реализаций. dwarf имеет такие же нулевые накладные расходы, но имеет проблемы при работе со смешанным кодом. sjlj без проблем работает со смешанным кодом, но имеет приличные накладные расходы. Естественно здесь речь про режим работы без запуска исключений. А кого-то волнует быстродействие исключительной ситуации? ) Ну разве что тех, кто применяет исключения для обработки всех ошибок...
Кстати, seh не применяли в других компиляторах (в 32 битном коде) из-за патентных ограничений. Но как раз совсем недавно патент вышел и теперь его спешно реализуют и для 32-ых битного mingw (64 битная реализация есть давно).
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Вот тебе пример, позаимствованный у Рихтера.
PD>Сильно разреженная очень большая матрица. Операция всего одна — занести элемент. Память надо экономить. Поэтому резервируем АП под всю матрицу (VirtualAlloc/MEM_RESERVE), при этом ни одного байта не выделяется, а потом, ничтоже сумняшеся, пишем по нужному адресу. Естественно, получаем exception (AV), коммитируем 4Кб, включающие нужный адрес (VirtualAlloc/MEM_COMMIT), повторяем операцию. Следующий раз мы либо попадем в эти 4 Кб, тогда доступ без AV, либо в другое место, тогда еще 4 Кб и т.д.
PD>Как видишь, исключения здесь не есть что-то ненормальное, а есть вполне нормальный code flow. Да, они не при каждом обращении будут происходить. Но будут, и это нормально.
Ну это вообще немного не в тему нашего обсуждение. Это скорее пример специфической оптимизации на базе аппаратных исключений.
Здравствуйте, alex_public, Вы писали:
_>Ну это вообще немного не в тему нашего обсуждение. Это скорее пример специфической оптимизации на базе аппаратных исключений.
Согласен, немного не то. Но и речь-то в моем предыдущем ответе jazzer шла немного не о том — я говорил, что исключения могут быть частью контракта метода, а поэтому аппелировать к тому, что нам нужна хорошая скорость, когда их не будет — не совсем верно.