Можно ли выбрасывать исключение в предикатах?
===============================================

 Доброго дня.  

Вопрос касается чистоты кода и стройности архитектуры. Не секрет, что предикаты - функции, которые должны возвращать булево значение, отвечая на какой-либо вопрос (is directory exists?). Поскольку я год назад начал плотно угорать по исключениям (ибо они рулят), ныне я редко возвращаю false или null в случаях, когда false или null должны вести за собой прекращение работы программы. Я продолжаю их возвращать, когда ситуация допустима, но когда это ошибка - всегда выбрасываю исключение.  
  

Собственно, суть вопроса в том, что в ряде случаев удобно сунуть выброс исключения в предикат. Таким образом, он, в ряде случаев, будет возвращать только true или выбрасывать исключение. Так лучше не делать, верно? И как делать в таких случаях, если код, генерящий исключение, хочется инкапсулировать в функцию? Делать дополнительную функцию-обертку над предикатом?  
  
**Закончу вопрос примером.**
```
<?php

class CheckForNewPhoto
{
    public function handle(Repositories\MosaicRepository $MosaicRepository)
    {
        if($this->isDirectoryNameCorrect()) {
            // ранее исключение выбрасывалось тут, я считаю, это некрасиво
            // do stuff
        }

        throw new Exceptions\UnexpectedError(
            'Something wrong here'
        );
    }

    /**
     * Вот это - предикат. Я сделал так, чтобы избавить entry point,
     * функцию handle, от ада выбросов исключений, когда проверяется много
     * условий и выкидывается много исключений в одном методе.
     * Когда один метод > одна проверка > строго связанные с ней исключения,
     * это красиво.
     */
    private function isDirectoryNameCorrect()
    {
        if(!config('mosaic.directory', null)) {
            throw new Exceptions\InvalidSettingsException(
                'Directory for mosaic photos is not setup properly'
            );
        }

        return true;
    }
}
```
  

Заранее спасибо. 

> Держащий в руке молоток видит только гвозди

  
  

Это про вас. Предикат обязан возвращать true/false. Эксепшены нужны для того чтобы отлавливать ошибки и передавать из вверх по стеку.  
  

Пример из жизни: на вопрос есть ли пирожки продавец или говорит да или разворачивается и уходит 

 Предикаты возвращают логическое выражение и точка. Если он возвращает что-то еще, то это уже не предикат.   

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

 Приведу пример:  

```
void checkDirectory( const Dir& dir ) {
    if (isDirBad( dir ))
       throw "The directory is bad bad directory";
}

void File::open( const FileName& fn ) {
    try {
       checkDirectory( Dir( fn ));
       openFile(fn);
    }
    catch( const char* msg ) {
        std::cerr << msg << std::endl;
    }
}
```
  

Логично, что предикат `isDirBad()` не должен вызывать исключение, потому что это будет масло масленное.  

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

 Пример как раз отлично иллюстрирует то, что исключений тут и даром не надо.  
  

На вопрос isDirectoryNameCorrect мы хотим получить только "да" или "нет".  

При этом нас совершенно не беспокоит, почему "нет" - то ли набор символов в имени недопустим, то ли диск посыпался, то ли прав не хватает - нам это не интересно. 

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

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

 Исключения - это хорошее название. Точное. Удачное.  

Они должны использоваться в непредусматриваемых ситуациях.  
  

Описанная вами ситуация - штатная.  

Тут правильно возвращать истину или ложь. 

 Исключения - это плохое название. Запутывающее. Неудачное.  

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

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

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