does not exist
От: Alexéy Sudáchen Чили  
Дата: 10.07.11 16:31
Оценка:
В файловых операциях, да и вообще операциях с внешними объектами, есть такая замечательная ошибка — нету такого файла/объекта.

Есть два способа обработки такой ошибки в среде с поддержкой исключений, можно вернуть нулевой объект (NULL, null, None), а можно кинуть исключение как и с любой другой ошибкой. Суть как бы в том что это ошибка принципиально отличается от остальных. Она уведомительная. Иначе говоря алгоритм после такой ошибки, как минимум в моём коде, очень часто продолжает работать.

Буквально есть три варианта — ну и фиг с ним что нет такого; раз нет — создадим; и опа, приехали! Первый и второй самые частые.

Отсюда вопрос, как идеологически более верно возвращать такую ошибку — как исключение или как возврат нулевого объекта? Вопрос производительности здесь очевидно не стоит, так как даже если создание кадра обработки исключения не быстро — всё равно не сравнимо с открытием файла.
Re: does not exist
От: Sinix  
Дата: 10.07.11 16:45
Оценка:
Здравствуйте, Alexéy Sudáchen, Вы писали:

AS>Отсюда вопрос, как идеологически более верно возвращать такую ошибку — как исключение или как возврат нулевого объекта?

Зависит от языка/фреймворка. Для дотнета принято не возвращать null-ы (они могут быть и верными значениями). Как правило, метод просто бросается исключениями. Иногда (для случаев, когда отсутствие значения/невозможность выполнения операции вполне легально и ожидаемо) вводится парный метод с сигнатурой наподобие
bool TryDoSomething(int arg1, int arg2, out string result);
Re: does not exist
От: uzhas Ниоткуда  
Дата: 10.07.11 16:57
Оценка: +1
Здравствуйте, Alexéy Sudáchen, Вы писали:


AS>Отсюда вопрос, как идеологически более верно возвращать такую ошибку — как исключение или как возврат нулевого объекта?

однозначного ответа нет, т.к. все зависит от семантики вашей операции, хотя и с ее помощью нельзя дать конкретный ответ
я могу дать такой совет:
пусть операция кидает исключение, если файла нет; заведите себе функцию, которая будет сообщать есть ли файл вообще, чтобы в ситуациях, когда вы можете прожить без файла, исключение не кидалось
пример
if (DoesFileExist(filename))
{
  CreateFile(filename);
}

f = OpenFile(filename);
Re[2]: does not exist
От: uzhas Ниоткуда  
Дата: 10.07.11 16:59
Оценка:
Здравствуйте, uzhas, Вы писали:

отрицание забыл=\
исправил:
if (!DoesFileExist(filename))
{
  CreateFile(filename);
}

f = OpenFile(filename);
Re[2]: does not exist
От: Temoto  
Дата: 10.07.11 17:00
Оценка: +1
U>
U>if (DoesFileExist(filename))
U>{
U>  CreateFile(filename);
U>}

U>f = OpenFile(filename);
U>


Race condition.
Re: does not exist
От: okman Беларусь https://searchinform.ru/
Дата: 10.07.11 17:59
Оценка: +1
Здравствуйте, Alexéy Sudáchen, Вы писали:


AS>В файловых операциях, да и вообще операциях с внешними объектами, есть такая замечательная ошибка — нету такого файла/объекта.


AS>Есть два способа обработки такой ошибки в среде с поддержкой исключений, можно вернуть нулевой объект (NULL, null, None), а можно кинуть исключение как и с любой другой ошибкой. Суть как бы в том что это ошибка принципиально отличается от остальных. Она уведомительная. Иначе говоря алгоритм после такой ошибки, как минимум в моём коде, очень часто продолжает работать.


AS>Буквально есть три варианта — ну и фиг с ним что нет такого; раз нет — создадим; и опа, приехали! Первый и второй самые частые.


AS>Отсюда вопрос, как идеологически более верно возвращать такую ошибку — как исключение или как возврат нулевого объекта? Вопрос производительности здесь очевидно не стоит, так как даже если создание кадра обработки исключения не быстро — всё равно не сравнимо с открытием файла.


Вряд ли открою Америку — ответ на этот вопрос зависит от контекста, в которой выполняется файловая операция.

Вариант 1.
Файл используется для хранения пользовательских настроек.
Если он отсутствует, то будет создан заново.

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

if (open_settings_file() == null)
{
    create_settings_file();
}


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

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

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

open_config_file();


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

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

IMHO.
Re[2]: does not exist
От: Alexéy Sudáchen Чили  
Дата: 10.07.11 18:23
Оценка:
Здравствуйте, okman, Вы писали:

O>Вряд ли открою Америку — ответ на этот вопрос зависит от контекста, в которой выполняется файловая операция.


Ну дык функция то одна. Фактически нужно две — одна бросает, другая нет. Ну или ещё один параметр. Соответственно перефразируя вопрос — какая из функций имеет более короткое имя, или какой вариант не требует параметра? Тот что бросает или тот что нет?

O>Ну в общем, при выборе ответа на подобные вопросы нужно руководствоваться

O>соображениями структурности и прозрачности кода (особенно клиентского), а не "идеологией".

Должна ли функция Open_File(name) бросать исключение если файла нет? У неё нет контекста. Она просто с файлами работает.
Re[2]: does not exist
От: Alexéy Sudáchen Чили  
Дата: 10.07.11 18:25
Оценка:
Здравствуйте, uzhas, Вы писали:

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


Имхо, дешевле и короче поймать исключение.
Re[3]: does not exist
От: uzhas Ниоткуда  
Дата: 10.07.11 18:30
Оценка: 1 (1)
Здравствуйте, Alexéy Sudáchen, Вы писали:


AS>Должна ли функция Open_File(name) бросать исключение если файла нет? У неё нет контекста. Она просто с файлами работает.

уже сказали, что она может бросать, а может и не бросать. все зависит от того, как ее задизайнили. и это желательно отразить в документации. посмотрите http://msdn.microsoft.com/en-us/library/aa363858(v=vs.85).aspx. функция может создать файл, а может вернуть ошибку. зависит от флажков, а флажки как раз регулируют стратегию поведения. в нефлажковых API это отражается в названии функции
OpenFileIfExist
OpenOrCreateFile
и тд
можно смастерить функцию RemoveOrCreateFile, которая будет удалять существующий файл либо создавать новый файл, если его не было. вот потеха
Re[3]: does not exist
От: uzhas Ниоткуда  
Дата: 10.07.11 19:53
Оценка:
Здравствуйте, Alexéy Sudáchen, Вы писали:

AS>Имхо, дешевле и короче поймать исключение.

имхо и не дешевле и не короче и семантика размытая
не забывайте, что не всякое исключение говорит об отсутствии файла, хотя вам может быть неважно что за ошибка
Re[4]: does not exist
От: Alexéy Sudáchen Чили  
Дата: 10.07.11 20:27
Оценка:
Здравствуйте, uzhas, Вы писали:

U>имхо и не дешевле и не короче и семантика размытая

U>не забывайте, что не всякое исключение говорит об отсутствии файла, хотя вам может быть неважно что за ошибка


BUFFER *buffer = 0;
__Try
buffer = Qj_Read_All(Cfile_Open("",""));
__Catch(ERROR_DOESNT_EXIST) ;

/* bla-bla-bla */

Стопитсот за то что быстрее и короче! Пример практически реальный. Язык С, но в С++ будет примерно то же самое.
Re[5]: does not exist
От: uzhas Ниоткуда  
Дата: 10.07.11 20:51
Оценка:
Здравствуйте, Alexéy Sudáchen, Вы писали:

AS>Стопитсот за то что быстрее и короче! Пример практически реальный. Язык С, но в С++ будет примерно то же самое.

хорошо, уговорили
можно было еще как-нибудь так:
BUFFER content = READ_FILE_CONTENT(filename);
Re[3]: does not exist
От: okman Беларусь https://searchinform.ru/
Дата: 10.07.11 21:51
Оценка: 5 (2)
Здравствуйте, Alexéy Sudáchen, Вы писали:

AS>Должна ли функция Open_File(name) бросать исключение если файла нет? У неё нет контекста. Она просто с файлами работает.


Клиентский код выглядит чище, когда избавлен от многочисленных проверок возвращаемых функциями значений.
Поэтому лично я — за исключения, если только это не связано с какими-нибудь существенными потерями.
Функция открытия файла,- open_file,- может возвращать файловый объект, либо бросать исключение, если
файл отсутствует, или используется эксклюзивно другим процессом, или же отсутствуют права доступа.
А ловить это исключение можно уровнем выше, и со всеми "удобствами". Все это хорошо известно, разумеется.

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

Кстати, здесь начинается территория, где выбор еще связан с конкретными языками программирования и реализациями.
Предположим, что мы выбрали возвращать указатель на файловый объект и NULL в случае ошибки.
Для C++, где отсутствует сборка мусора, это означает возню с освобождением памяти, занимаемой объектом (в
лучшем случае этим будут заниматься смартпоинтеры, в худшем — operator delete), а еще нужно получать
откуда-то точный id ошибки и, желательно, ее текстовое описание (аналоги GetLastError/FormatMessage в Win32).

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

Возвращаясь в русло.
Должна ли функция Open_File(name) бросать исключение если файла нет?

Должна, тем более если она бросает исключения в других ситуациях — это оберегает от путаницы и
способствует написанию более согласованного кода. И в названии функции не заявлено ни о создании
нового файла (иначе ее следовало бы назвать open_or_create_file), ни о возвращении пустого (null) объекта.
Re: does not exist
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 10.07.11 22:23
Оценка: 2 (2)
Здравствуйте, Alexéy Sudáchen, Вы писали:


AS>В файловых операциях, да и вообще операциях с внешними объектами, есть такая замечательная ошибка — нету такого файла/объекта.


AS>Есть два способа обработки такой ошибки в среде с поддержкой исключений, можно вернуть нулевой объект (NULL, null, None), а можно кинуть исключение как и с любой другой ошибкой. Суть как бы в том что это ошибка принципиально отличается от остальных. Она уведомительная. Иначе говоря алгоритм после такой ошибки, как минимум в моём коде, очень часто продолжает работать.


AS>Буквально есть три варианта — ну и фиг с ним что нет такого; раз нет — создадим; и опа, приехали! Первый и второй самые частые.


AS>Отсюда вопрос, как идеологически более верно возвращать такую ошибку — как исключение или как возврат нулевого объекта? Вопрос производительности здесь очевидно не стоит, так как даже если создание кадра обработки исключения не быстро — всё равно не сравнимо с открытием файла.


А может не парить мозг и сделать пару функций OpenFile и TryOpenFile? первая кидает исключение в случае неуспеха, а вторая возвращает true\false или Nullable тип.
Re[2]: does not exist
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 10.07.11 22:24
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, Alexéy Sudáchen, Вы писали:



AS>>Отсюда вопрос, как идеологически более верно возвращать такую ошибку — как исключение или как возврат нулевого объекта?

U>однозначного ответа нет, т.к. все зависит от семантики вашей операции, хотя и с ее помощью нельзя дать конкретный ответ
U>я могу дать такой совет:
U>пусть операция кидает исключение, если файла нет; заведите себе функцию, которая будет сообщать есть ли файл вообще, чтобы в ситуациях, когда вы можете прожить без файла, исключение не кидалось
U>пример
U>
U>if (DoesFileExist(filename))
U>{
U>  CreateFile(filename);
U>}

U>f = OpenFile(filename);
U>


Вообще говоря межу вызовами DoesFileExist и CreateFile файл могут удалить, как и между CreateFile и OpenFile
Re[3]: does not exist
От: uzhas Ниоткуда  
Дата: 10.07.11 23:19
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Вообще говоря межу вызовами DoesFileExist и CreateFile файл могут удалить, как и между CreateFile и OpenFile

об этом уже упоминали выше
не вижу ничего критичного в таких ситуациях
к тому же не стоит делать синхронизацию через файлы, для этого придуманы более подходящие средства типа именованных мьютексов, критических секций и семафоров
Re[4]: does not exist
От: Temoto  
Дата: 10.07.11 23:24
Оценка:
G>>Вообще говоря межу вызовами DoesFileExist и CreateFile файл могут удалить, как и между CreateFile и OpenFile
U>об этом уже упоминали выше
U>не вижу ничего критичного в таких ситуациях
U>к тому же не стоит делать синхронизацию через файлы, для этого придуманы более подходящие средства типа именованных мьютексов, критических секций и семафоров

Если файл могут удалить между проверкой на существование и созданием, то в этой проверке нет смысла, ведь всё равно придётся обрабатывать ошибку создания. Это не вопрос синхронизации, потому что удалить файл может совершенно другое приложение, которое не знает о мьютексах.
Re[2]: does not exist
От: Pavel Dvorkin Россия  
Дата: 11.07.11 02:57
Оценка: +1 :)
Здравствуйте, uzhas, Вы писали:

U>пример

U>
U>if (DoesFileExist(filename))
U>{
U>  CreateFile(filename);
U>}

U>f = OpenFile(filename);
U>


Так делать в общем случае не надо. Что бы ни вернула DoesFileExist(filename) , файл на момент CreateFile или OpenFile может существовать или не существовать. Мы не в MS-DOS.
With best regards
Pavel Dvorkin
Re: does not exist
От: __kot2  
Дата: 11.07.11 05:34
Оценка: +1
Здравствуйте, Alexéy Sudáchen, Вы писали:
AS>В файловых операциях, да и вообще операциях с внешними объектами, есть такая замечательная ошибка — нету такого файла/объекта.
тут много правильных подходов обсудили, но забыли еще про один — принцип минимальной неожиданности поведения для программиста.
насколько я помню, в С++ iostream исключения не кидает. люди к этому уже привыкли и пусть лучше так и будет
Re[3]: does not exist
От: uzhas Ниоткуда  
Дата: 11.07.11 07:34
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Так делать в общем случае не надо

хорошо, уговорили
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.