Re[5]: Почему в расте отсутствует выброс исключений?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 02.12.22 18:25
Оценка:
Здравствуйте, alex_public, Вы писали:

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


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


Чем это отличается? Что мешает в C++? У меня для плюсов, кстати, написан свой Result. Иногда использую. Иногда нет. Иногда использую исключения, когда ошибку не исправить, но можно отловить на каком-то уровне и вывести пользователю или записать в лог и похромать дальше — что-то типа assert'а, только более контролируемого
Маньяк Робокряк колесит по городу
Re[7]: Почему в расте отсутствует выброс исключений?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 02.12.22 18:46
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Ну, то что ты описал — это как раз случай не исключительной ситуации, а обычной обработки ошибок и соответственно удобнее это обрабатывать не исключениями, а через Result.


Ошибки могут возникать на всех уровнях, а ловить удобно на одном. Пробрасывать Result руками через 100500 уровней — то ещё удовольствие. Поэтому нет, не то же самое


_>А насчёт твоего универсального обработчика ошибок... Так он всегда возвращает именно 500? А если где-то надо 404 вернуть или 401, то как тогда? А если случается OOM, то он тоже пытается вернуть запрос (на создание которого опять же нужна память, которой уже нет) с 500?


404 или 401 — их возвращают согласно бизнес логике. А 5XX — это как раз "произошла какая-то неведомая херня, как обработать не знаем, мы сломались"


vsb>>Поэтому мне что раст, что голанг жутко неудобны и я не понимаю, как на них люди могут что-то писать. А вот обычные тупые исключения вроде питоновских — то, что доктор прописал.


_>А что именно неудобно в работе с Result?


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

Я делал как-то свой Result. Что-то типа пары {код_ошибки, результат}, результат валиден, если код ошибки — НЕТ_ОШИБКИ. Иногда использую, но в целом — не очень.

Еще делал мега подсистему для работы с ошибками. Хранил в TLS для каждого потока. Что-то типа GetLastError на стероидах. Можно было делать цепочки ошибок — если где-то внизу произошла ошибка, то можно было не просто её отправить выше, а подвесить ещё свою интерпретацию. До пользователя доходит последнее, но при желании он может посмотреть всю цепочку событий. В принципе, получилось неплохо, до сих пор использую иногда. Там просто другая проблема — получилось уже что-то фреймворка, не всегда его тащит хочется
Маньяк Робокряк колесит по городу
Re[6]: Почему в расте отсутствует выброс исключений?
От: T4r4sB Россия  
Дата: 02.12.22 19:19
Оценка: +1
Здравствуйте, Marty, Вы писали:

M>Чем это отличается? Что мешает в C++?


Ацуцтвие сахара для этого дела.
Писать
auto MaybeResult = foo();
if (auto Error = Result.takeError()) {
  return Error;
}
auto Result = MaybeResult.takeResult();

Немного более утомительно, чем
auto Result = foo()?;
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[6]: Почему в расте отсутствует выброс исключений?
От: ArtDenis Россия  
Дата: 02.12.22 19:49
Оценка: +1
Здравствуйте, Marty, Вы писали:

M>Чем это отличается? Что мешает в C++?


В расте добавлен очень приятный синтаксический сахар в виде оператора "?", который сокращает код, где надо просто пробросить ошибку на уровень выше.
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[7]: Почему в расте отсутствует выброс исключений?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 03.12.22 07:51
Оценка:
Здравствуйте, T4r4sB, Вы писали:


TB>Ацуцтвие сахара для этого дела.

TB>Писать
TB>
TB>auto MaybeResult = foo();
TB>if (auto Error = Result.takeError()) {
TB>  return Error;
TB>}
TB>auto Result = MaybeResult.takeResult();
TB>



Я сахар сам написал, работало как-то так:
if (auto res = foo())
{
    doSomething(res.value);
}



TB>Немного более утомительно, чем

TB>
TB>auto Result = foo()?;
TB>


А что тут вообще происходит?
Маньяк Робокряк колесит по городу
Отредактировано 03.12.2022 7:55 Marty . Предыдущая версия .
Re[8]: Почему в расте отсутствует выброс исключений?
От: T4r4sB Россия  
Дата: 03.12.22 10:56
Оценка:
Здравствуйте, Marty, Вы писали:

TB>>Немного более утомительно, чем

TB>>
TB>>auto Result = foo()?;
TB>>


M>А что тут вообще происходит?


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

Кстати, а где в твоём примере разные коды ошибок? Где немедленный возврат из функции в случае ошибки? Больше похоже на Optional.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Отредактировано 03.12.2022 10:58 T4r4sB . Предыдущая версия .
Re[9]: Почему в расте отсутствует выброс исключений?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 03.12.22 11:20
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Кстати, а где в твоём примере разные коды ошибок?


В Result есть поле error


TB>Где немедленный возврат из функции в случае ошибки?


Такого нету, надо через if. Но можно намакросить, будет достаточно коротко


TB>Больше похоже на Optional.


Это он почти и есть, с некоторым дополнениями. Есть ещё Error, который почти как Result, но содержит только код ошибки. Наверно оно аналогично Result<void>, я уже не помню, нафига я его отдельно сделал. Error и Result умеют конвертироваться друг в друга. Есть ещё хитрый оператор !, точно не помню как работает, смотреть лень, он нужен для немного странной записи:

[сcode]
if (auto res = getResult())
{
// Делаем полезное с валидным результатом
}

if (auto res = !getResult())
{
// Результат не валиден
return Error(res);
}

[/сcode]


А в расте оператор ?, как я понял, проверяет на ошибку и делает return из текущей функции? Ну может и удобно, но как я понимаю, у всей иерархии тип результата одинаковый? Это не особо часто таки бывает. Или как оно работает?
Маньяк Робокряк колесит по городу
Re[10]: Почему в расте отсутствует выброс исключений?
От: T4r4sB Россия  
Дата: 03.12.22 11:30
Оценка:
Здравствуйте, Marty, Вы писали:

M>А в расте оператор ?, как я понял, проверяет на ошибку и делает return из текущей функции? Ну может и удобно, но как я понимаю, у всей иерархии тип результата одинаковый? Это не особо часто таки бывает. Или как оно работает?


Ты имеешь в виду наверное не "тип результата", а "тип ошибки"? Да, если он разный, то проблемка. Ну либо вручную делать

auto Result = foo().map_err(|e| foo_error_to_bar_error(e))?

Либо на каком-то уровне иерархии возвращать Box<dyn Err>, ну и типа сразу наиболее общий тип ошибки возвращать.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[10]: Почему в расте отсутствует выброс исключений?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 03.12.22 11:32
Оценка:
Здравствуйте, Marty, Вы писали:

Если интересно, то как-то так

Трюк с оператором ! вот какой — он просто ставит в поле ошибки флаг, оператор преобразования в bool его сбрасывает, т.е. первая проверка на истинность в if'е восстанавливает нормальный код ошибки

    UMBA_EXPLICIT
    operator bool() const
    {
        if ((result&errors::invertFlag)==0) // invert flag not set
            return isSuccess();

        result &= ~ errors::invertFlag;
        return isFail();
    }

    //! Использование в операторе if с инверсией
    /*! Проверка на фейл вызова:

        if (auto a = !someFunction()) { Ветка по неудаче }
     */
    Error operator!() const
    {
        return Error(result | errors::invertFlag);
    }



Ну, и ещё я не доделал случай, когда конструктор по умолчанию недоступен


  errors.h
#pragma once

//----------------------------------------------------------------------------

/*! \file
    \brief Ошибки, и связанные с ними определения
*/

//----------------------------------------------------------------------------

#include "umba/preprocessor.h"
#include "umba/stl.h"

#if defined(UMBA_WIN32_USED)
    #include <stdio.h>
#endif

//----------------------------------------------------------------------------




//----------------------------------------------------------------------------

namespace umba{


typedef uint32_t  ErrorCode; //!< Сырой целочисленный тип кода ошибки



//----------------------------------------------------------------------------
namespace errors
{
    const ErrorCode errorFlag              = 0x80000000;  //!< Флаг - ошибка
    const ErrorCode invertFlag             = 0x40000000;  //!< Флаг инверсии

    const ErrorCode errorSubsystemMask     = 0x0F000000;  //!< Маска подсистемы

    const ErrorCode errorSubsystemUmba     = 0x00000000;  //!< Подсистема UMBA
    const ErrorCode errorSubsystemWindows  = 0x01000000;  //!< Подсистема Windows - проброс виндового кода ошибки
    const ErrorCode errorSubsystemPosix    = 0x02000000;  //!< Подсистема Posix - проброс Posix ошибки - Linux ошибка или (под Windows) - ошибка CRT
    const ErrorCode errorSubsystemQt       = 0x03000000;  //!< Подсистема Qt - ошибка фреймворка Qt


    //! Код ошибки из виндового кода
    inline ErrorCode makeFromWindows( ErrorCode errorCode )
    {
     return errorFlag | errorSubsystemWindows | (errorCode & ~(errorSubsystemMask | errorFlag));
    }

    //! Код ошибки из Posix кода
    inline ErrorCode makeFromPosix( ErrorCode errorCode )
    {
     return errorFlag | errorSubsystemPosix | (errorCode & ~(errorSubsystemMask | errorFlag));
    }

    //! Код ошибки из Qt кода
    inline ErrorCode makeFromQt( ErrorCode errorCode )
    {
     return errorFlag | errorSubsystemQt | (errorCode & ~(errorSubsystemMask | errorFlag));
    }

#ifndef DOXYGEN_SHOULD_SKIP_THIS

    #ifdef UMBA_DECLARE_ERROR_CODE
        #undef UMBA_DECLARE_ERROR_CODE
    #endif

    #ifdef UMBA_DECLARE_ERROR_CODE_ALIAS
        #undef UMBA_DECLARE_ERROR_CODE_ALIAS
    #endif

    /* info */
    #define UMBA_DECLARE_ERROR_CODE(name, code, info) \
                 const ErrorCode name = code; 
    #define UMBA_DECLARE_ERROR_CODE_ALIAS(name, code, info) \
                 const ErrorCode name = code; 

#endif /* DOXYGEN_SHOULD_SKIP_THIS */

    #include "zz_error_codes.h"

#ifndef DOXYGEN_SHOULD_SKIP_THIS

    #undef UMBA_DECLARE_ERROR_CODE
    #undef UMBA_DECLARE_ERROR_CODE_ALIAS

#endif /* DOXYGEN_SHOULD_SKIP_THIS */

} // namespace errors

//----------------------------------------------------------------------------




//----------------------------------------------------------------------------
template <typename TValue>
struct Result;

#if 0
    //! Конструктор по умолчанию
    //! Конструктор из объекта "ошибка"
    //! Конструктор из кода ошибки и результата (не все ошибки - фатальные)
    //! Конструктор копирования
    //! Конструктор перемещения
#endif



//! Плейс-холдер для кода ошибки
class Error
{

public:

    mutable ErrorCode    result; //!< Код ошибки

    //! Конструктор по умолчанию - создаёт "Ок - Нет ошибки"
    Error()               : result(errors::ok) {}
    //! Конструктор из кода ошибки
    Error(ErrorCode ec)   : result(ec) {}
    //! Конструктор копирования
    Error(const Error &e) : result(e.result) {}

    //! Оператор присваивания кода ошибки
    Error& operator=(const ErrorCode &e) { result = e;        return *this; }
    //! Оператор присваивания
    Error& operator=(const Error &e)     { result = e.result; return *this; }

    //! Преобразование в Result
    template <typename TValue>
    Error( const Result<TValue> &r );

    //! Проверка на сбой
    bool isFail() const
    {
        return (result & errors::errorFlag) ? true : false;
    }

    //! Проверка на успех
    bool isSuccess() const
    {
        return !isFail();
    }

    //! Проверка на полный успех
    bool isClean() const
    {
        return result == 0;
    }

    //! Использование в операторе if и сравнение с bool
    /*! Проверка на успешность вызова:

        if (auto a = someFunction()) { Ветка по успеху }
     */
    UMBA_EXPLICIT
    operator bool() const
    {
        if ((result&errors::invertFlag)==0) // invert flag not set
            return isSuccess();

        result &= ~ errors::invertFlag;
        return isFail();
    }

    //! Использование в операторе if с инверсией
    /*! Проверка на фейл вызова:

        if (auto a = !someFunction()) { Ветка по неудаче }
     */
    Error operator!() const
    {
        return Error(result | errors::invertFlag);
    }

    #ifdef UMBA_MCU_USED

      #ifndef DOXYGEN_SHOULD_SKIP_THIS

        // errors:: 
        #define UMBA_DECLARE_ERROR_CODE(name, code, info) \
                     case name : return UMBA_STRINGIFY(name);
        #define UMBA_DECLARE_ERROR_CODE_ALIAS(name, code, info)

      #endif /* DOXYGEN_SHOULD_SKIP_THIS */


        //! Возвращает строку с сообщением об ошибке
        const char* what() const
        {
            switch(result & ~errors::invertFlag)
            {
                using namespace errors;
                #include "zz_error_codes.h"
                #undef UMBA_DECLARE_ERROR_CODE
                #undef UMBA_DECLARE_ERROR_CODE_ALIAS
                default:
                {
                     return "Unknown error";
                }
            };
        }

        //! Возвращает Unicode строку сообщением об ошибке
        const wchar_t* whatWide() const
        {
            return L"Some error";
        }

    #else

      #ifndef DOXYGEN_SHOULD_SKIP_THIS

        // errors:: 
        #define UMBA_DECLARE_ERROR_CODE(name, code, info) \
                     case name : return info;
        #define UMBA_DECLARE_ERROR_CODE_ALIAS(name, code, info)

      #endif /* DOXYGEN_SHOULD_SKIP_THIS */

        //! Возвращает строку с сообщением об ошибке
        const char* what() const
        {
            switch(result & ~errors::invertFlag)
            {
                using namespace errors;
                #include "zz_error_codes.h"
                #undef UMBA_DECLARE_ERROR_CODE
                #undef UMBA_DECLARE_ERROR_CODE_ALIAS
                default:
                {
                    #if defined(_WIN32) || defined(WIN32)
                        ErrorCode cleanCode = result & ~(errorSubsystemMask|errorFlag|invertFlag);
                        const char* fmt = "Unknown error %d (0x%08X)";
                        switch(result&errorSubsystemMask)
                        {
                            case errorSubsystemUmba:     fmt = "Umba error %d (0x%08X)";    break;
                            case errorSubsystemWindows:  fmt = "Windows error %d (0x%08X)"; break;
                            case errorSubsystemPosix:    fmt = "Posix error %d (0x%08X)";   break;
                            case errorSubsystemQt:       fmt = "Qt error %d (0x%08X)";      break;
                            //default:                     return "Unknown error";
                        };

                        #if defined(UMBA_CXX_HAS_STD11)
                            thread_local 
                        #else
                            #if defined(_MSC_VER)
                                __declspec( thread )
                            #endif
                        #endif
                        static char buf[64];

                        sprintf(buf, fmt, cleanCode, result);
                        return buf;
                    #else
                        switch(result&errorSubsystemMask)
                        {
                            case errorSubsystemUmba:     return "Umba error";
                            case errorSubsystemWindows:  return "Windows error";
                            case errorSubsystemPosix:    return "Posix error";
                            case errorSubsystemQt:       return "Qt error";
                            default:                     return "Unknown error";
                        };
                    #endif
                }
            };
        }

      #ifndef DOXYGEN_SHOULD_SKIP_THIS

        //errors::
        #define UMBA_DECLARE_ERROR_CODE(name, code, info) \
                     case  name : return L##info;
        #define UMBA_DECLARE_ERROR_CODE_ALIAS(name, code, info)

      #endif /* DOXYGEN_SHOULD_SKIP_THIS */

        //! Возвращает Unicode строку сообщением об ошибке
        const wchar_t* whatWide() const
        {
            switch(result & ~errors::invertFlag)
            {
                using namespace errors;
                #include "zz_error_codes.h"
                #undef UMBA_DECLARE_ERROR_CODE
                #undef UMBA_DECLARE_ERROR_CODE_ALIAS
                default:
                {
                    #if defined(_WIN32) || defined(WIN32)
                        ErrorCode cleanCode = result & ~(errorSubsystemMask|errorFlag|invertFlag);
                        const wchar_t* fmt = L"Unknown error %d (0x%08X)";
                        switch(result&errorSubsystemMask)
                        {
                            case errorSubsystemUmba:     fmt = L"Umba error %d (0x%08X)";    break;
                            case errorSubsystemWindows:  fmt = L"Windows error %d (0x%08X)"; break;
                            case errorSubsystemPosix:    fmt = L"Posix error %d (0x%08X)";   break;
                            case errorSubsystemQt:       fmt = L"Qt error %d (0x%08X)";      break;
                            //default:                     return "Unknown error";
                        };
                        #if defined(UMBA_CXX_HAS_STD11)
                            thread_local 
                        #else
                            #if defined(_MSC_VER)
                                __declspec( thread )
                            #endif
                        #endif
                        static wchar_t buf[64];

                        swprintf(buf, fmt, cleanCode, result);
                        return buf;
                    #else
                        switch(result&errorSubsystemMask)
                        {
                            case errorSubsystemUmba:     return L"Umba error";
                            case errorSubsystemWindows:  return L"Windows error";
                            case errorSubsystemPosix:    return L"Posix error";
                            case errorSubsystemQt:       return L"Qt error";
                            default:                     return L"Unknown error";
                        };
                    #endif
                }
            };
        }

    #endif

}; // struct Error

//----------------------------------------------------------------------------




//----------------------------------------------------------------------------
//! Проверка двух Error между собой на равенство
inline
bool operator==(Error e1, Error e2)
{
    return e1.result == e2.result;
}

//------------------------------
//! Проверка двух Error между собой на неравенство
inline
bool operator!=(Error e1, Error e2)
{
    return e1.result != e2.result;
}

//------------------------------
//! Проверка Error и ErrorCode на равенство
inline
bool operator==(Error e1, ErrorCode e2)
{
    return e1.result == e2;
}

//------------------------------
//! Проверка Error и ErrorCode на неравенство
inline
bool operator!=(Error e1, ErrorCode e2)
{
    return e1.result != e2;
}

//------------------------------
//! Проверка ErrorCode и Error на равенство
inline
bool operator==(ErrorCode e1, Error e2)
{
    return e1 == e2.result;
}

//------------------------------
//! Проверка ErrorCode и Error на неравенство
inline
bool operator!=(ErrorCode e1, Error e2)
{
    return e1 != e2.result;
}

//------------------------------
//! Проверка Error и bool на равенство - Error равен true, когда он успешен
inline
bool operator==(Error e1, bool e2)
{
    return e1.isSuccess() == e2;
}

//------------------------------
//! Проверка Error и bool на неравенство - Error равен true, когда он успешен
inline
bool operator!=(Error e1, bool e2)
{
    return e1.isSuccess() != e2;
}

//------------------------------
//! Проверка bool и Error на равенство - Error равен true, когда он успешен
inline
bool operator==(bool e1, Error e2)
{
    return e1 == e2.isSuccess();
}

//------------------------------
//! Проверка bool и Error на неравенство - Error равен true, когда он успешен
inline
bool operator!=(bool e1, Error e2)
{
    return e1 != e2.isSuccess();
}

//----------------------------------------------------------------------------




//----------------------------------------------------------------------------
//! Обобщенный результат
/*! Данный класс позволяет возвращать код результата (ошибки)
    одновременно с полезной нагрузкой. Когда полезная нагрузка не нужна,
    следует использовать класс Error
 */
template <typename TValue>
struct Result : public Error
{

public:

    TValue       value;  //!< Значение результата

    //! Конструктор по умолчанию
    Result( )
    : Error()
    , value()
    {}

    //! Конструктор из объекта "ошибка"
    Result( const Error &e )
    : Error(e.result)
    , value()
    {}

    //! Конструктор из кода ошибки и результата (не все ошибки - фатальные)
    Result( ErrorCode ec, const TValue &tv )
    : Error(ec)
    , value(tv)
    {}

    //! Конструктор копирования
    Result( const Result &r )
    : Error(r.result)
    , value(r.value)
    {}

    #if defined(UMBA_CXX_HAS_STD11)
    //! Конструктор перемещения
    Result(Result &&r)
    : Error(r.result)
    , value()
    {
        value = std::move(r.value);
    }
    #endif

    //! Конструктор из значения результата
    Result( const TValue &tv )
    : Error(0)
    , value(tv)
    {}

/*
    explicit operator Error() const
    {
        return Error(result);
    }
*/
    //! Оператор присваивания
    Result& operator=(const Result &r)
    {
        if (&r==this) return *this;
        result = r.result;
        value  = r.value;
        return *this;
    }

    #if defined(UMBA_CXX_HAS_STD11)
    //! Присваивающий оператор присваивания
    Result& operator=(Result &&r)
    {
        if (&r==this) return *this;
        result = std::move(r.result);
        value  = std::move(r.value);
        return *this;
    }
    #endif


    //! Использование в операторе if и сравнение с bool
    /*! Проверка на успешность вызова:

        if (auto a = someFunction()) { Ветка по успеху }

        if (auto a = !someFunction()) { Ветка по неудаче }

     */
    UMBA_EXPLICIT
    operator bool() const
    {
        if ((result&errors::invertFlag)==0) // invert flag not set
            return isSuccess();

        result &= ~ errors::invertFlag;
        return isFail();
    }

    //! Использование в операторе if с инверсией
    /*! Проверка на фейл вызова:

        if (auto a = !someFunction()) { Ветка по неудаче }
     */
    Result operator!() const
    {
        return Result( result | errors::invertFlag, value );
    }

}; // struct Result




template <typename TValue>
inline
Error::Error( const Result<TValue> &r ) : result(r.result)
{
}


} // namespace umba

  zz_error_codes.h
/*! \file
\brief Коды ошибок
*/
UMBA_DECLARE_ERROR_CODE      (ok                      ,  0, "Ok, no error")
UMBA_DECLARE_ERROR_CODE_ALIAS(success                 , ok, "Ok, operation successfully completed")
UMBA_DECLARE_ERROR_CODE_ALIAS(done                    , ok, "Ok, operation done")
UMBA_DECLARE_ERROR_CODE_ALIAS(no_error                , ok, "Ok, no error")
UMBA_DECLARE_ERROR_CODE_ALIAS(bool_true               , ok, "True condition")
UMBA_DECLARE_ERROR_CODE      (already                 ,  1, "Ok, but already done")
UMBA_DECLARE_ERROR_CODE      (need_reopen             ,  2, "Device need to be reopened before changes will take effect")
                                                     
UMBA_DECLARE_ERROR_CODE(bool_false                    ,  0 | errorFlag, "False condition")
UMBA_DECLARE_ERROR_CODE(fail                          ,  1 | errorFlag, "Generic fail")
UMBA_DECLARE_ERROR_CODE(not_implemented               ,  2 | errorFlag, "Method/function not implemented")
UMBA_DECLARE_ERROR_CODE(would_block                   ,  3 | errorFlag, "Blocking mode required / Operation would block")
UMBA_DECLARE_ERROR_CODE(connection_in_progess         ,  4 | errorFlag, "Asynchonous connection in progress")
UMBA_DECLARE_ERROR_CODE(shutdown_in_progess           ,  5 | errorFlag, "Asynchonous shutdown in progress")
UMBA_DECLARE_ERROR_CODE(wrong_io_mode                 ,  6 | errorFlag, "Wrong IO mode - attempt to read on write only, attemp to write to read only etc")
UMBA_DECLARE_ERROR_CODE(bus_addr_not_bound            ,  7 | errorFlag, "Attempt to write to bus stream, but device bus address not bound")
UMBA_DECLARE_ERROR_CODE(invalid_bus_addr              ,  8 | errorFlag, "Invalid bus adress taken")
UMBA_DECLARE_ERROR_CODE(unknown_bus_addr              ,  9 | errorFlag, "Unknown bus adress")
UMBA_DECLARE_ERROR_CODE(not_required                  , 10 | errorFlag, "Operation not required")
UMBA_DECLARE_ERROR_CODE(permission_denied             , 11 | errorFlag, "Permission denied")
UMBA_DECLARE_ERROR_CODE(not_found                     , 12 | errorFlag, "Requested object not found")
UMBA_DECLARE_ERROR_CODE(device_not_opened             , 13 | errorFlag, "Device is not opened")
UMBA_DECLARE_ERROR_CODE(device_busy                   , 14 | errorFlag, "Device is busy (temporary)")
UMBA_DECLARE_ERROR_CODE(device_already_online         , 15 | errorFlag, "Device is already opened/online")
UMBA_DECLARE_ERROR_CODE(device_required_online        , 16 | errorFlag, "Device must be online to perform this operation")
UMBA_DECLARE_ERROR_CODE(device_removed                , 17 | errorFlag, "Device unexpectedly removed from the system")
UMBA_DECLARE_ERROR_CODE(read_failed                   , 18 | errorFlag, "Read operation failed (generic read error)")
UMBA_DECLARE_ERROR_CODE(write_failed                  , 19 | errorFlag, "Write operation failed (generic write error)")
UMBA_DECLARE_ERROR_CODE(not_supported                 , 20 | errorFlag, "Operation is not supported")
UMBA_DECLARE_ERROR_CODE(prohibited                    , 21 | errorFlag, "Operation prohibited by the underlying layer")
UMBA_DECLARE_ERROR_CODE(timed_out                     , 22 | errorFlag, "Operation was timed out")
UMBA_DECLARE_ERROR_CODE(invalid_param                 , 23 | errorFlag, "Invalid parameter taken")
UMBA_DECLARE_ERROR_CODE(invalid_state                 , 24 | errorFlag, "Object is in invalid state")
UMBA_DECLARE_ERROR_CODE(invalid_prerequisites         , 25 | errorFlag, "Invalid prerequisites")
UMBA_DECLARE_ERROR_CODE(protocol_not_ready            , 26 | errorFlag, "Protocol not ready to perform this operation")
UMBA_DECLARE_ERROR_CODE(too_much_data                 , 27 | errorFlag, "Too much data")
UMBA_DECLARE_ERROR_CODE(stream_not_assigned           , 28 | errorFlag, "Stream not assigned")
UMBA_DECLARE_ERROR_CODE(unknown_interface             , 29 | errorFlag, "Unknown (unsupported) interface")
UMBA_DECLARE_ERROR_CODE(header_crc_error              , 30 | errorFlag, "Header CRC error")
UMBA_DECLARE_ERROR_CODE(crc_error                     , 31 | errorFlag, "CRC error")
UMBA_DECLARE_ERROR_CODE(out_of_sync                   , 32 | errorFlag, "Protocol is out of sync")
UMBA_DECLARE_ERROR_CODE(invalid_protocol_headeer      , 33 | errorFlag, "Protocol header contains invalid data")
UMBA_DECLARE_ERROR_CODE(wellknown_addr_not_supported  , 34 | errorFlag, "Wellknown address not supperted")
UMBA_DECLARE_ERROR_CODE(temporary_failure             , 35 | errorFlag, "Temporary failure (often hardware)")
UMBA_DECLARE_ERROR_CODE(too_many_opened               , 36 | errorFlag, "Too many opened files (sockets, handles etc)")
UMBA_DECLARE_ERROR_CODE(error_aborted                 , 37 | errorFlag, "The operation was aborted")
UMBA_DECLARE_ERROR_CODE(open_error                    , 38 | errorFlag, "Open operation generic error")
UMBA_DECLARE_ERROR_CODE(resize_error                  , 39 | errorFlag, "Can't resize stream/IO device (is it pipe etc?)")
UMBA_DECLARE_ERROR_CODE(not_seekable                  , 40 | errorFlag, "IO device not seekable")
UMBA_DECLARE_ERROR_CODE(file_operation_error          , 41 | errorFlag, "File operation error (remove/rename/copy/etc)")
UMBA_DECLARE_ERROR_CODE(eof_reached                   , 42 | errorFlag, "End of file reached")



//UMBA_DECLARE_ERROR_CODE(       ,  | errorFlag, "")
Маньяк Робокряк колесит по городу
Re[11]: Почему в расте отсутствует выброс исключений?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 03.12.22 11:36
Оценка:
Здравствуйте, T4r4sB, Вы писали:

M>>А в расте оператор ?, как я понял, проверяет на ошибку и делает return из текущей функции? Ну может и удобно, но как я понимаю, у всей иерархии тип результата одинаковый? Это не особо часто таки бывает. Или как оно работает?


TB>Ты имеешь в виду наверное не "тип результата", а "тип ошибки"? Да, если он разный, то проблемка. Ну либо вручную делать


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


TB>
TB>auto Result = foo().map_err(|e| foo_error_to_bar_error(e))?
TB>

TB>Либо на каком-то уровне иерархии возвращать Box<dyn Err>, ну и типа сразу наиболее общий тип ошибки возвращать.

Ну хз, как-то не удобно
Маньяк Робокряк колесит по городу
Re[12]: Почему в расте отсутствует выброс исключений?
От: T4r4sB Россия  
Дата: 03.12.22 11:37
Оценка:
Здравствуйте, Marty, Вы писали:

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


Result это такой TaggedUnion, который либо ошибка, либо результат. Тип ошибки и результата не особо ограничиваются. А оператор заточен именно вот Result из стандартной библиотеки.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[13]: Почему в расте отсутствует выброс исключений?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 03.12.22 11:49
Оценка:
Здравствуйте, T4r4sB, Вы писали:

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


TB>Result это такой TaggedUnion, который либо ошибка, либо результат. Тип ошибки и результата не особо ограничиваются. А оператор заточен именно вот Result из стандартной библиотеки.


А, ясно.

А я делал немного не так — у меня success состояние может содержать какое-то значение, типа всё хорошо, но были кой какие проблемки. В COM-овском HRESULT стырил идею
Маньяк Робокряк колесит по городу
Re: Почему в расте отсутствует выброс исключений?
От: Zhendos  
Дата: 03.12.22 12:05
Оценка: +1
Здравствуйте, vaa, Вы писали:

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

vaa>Или быть может существует более продвинутый механизм наподобие Common Lisp Condition System ?

На мой взгляд совершенно неудобный. По крайней мере в C++ это все просто ужасно,
как будто пишешь обработчик прерываний, который должен работать в условиях возможных вложенных прерываний,
а что произойдет если `operator=` выбросить исключение, а что произойдет если при передаче параметра в функцию,
но до ее вызова будет исключение и т.д. и т.п.

Предсказуемость и понимание того, что будет если эта функция завершиться с ошибкой,
а также контроль во время компиляции того, что `Result` будет обработан,
дорого стоит.

Ну плюс отсутствие исключение позволяет оптимизатору компилятора действительно в некоторых
случаях абстракции которые как бы "zero cost" превращать в действительно "zero cost".
Был пару лет назад доклад про `std::unique_ptr` и там были фундаментальные проблемы к сведению его
к простому указателю на в генерируемом ассебмлерном коде в том числе и из-за исключений.
Re[11]: Почему в расте отсутствует выброс исключений?
От: ArtDenis Россия  
Дата: 03.12.22 15:10
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Ты имеешь в виду наверное не "тип результата", а "тип ошибки"? Да, если он разный, то проблемка. Ну либо вручную делать


TB>
TB>auto Result = foo().map_err(|e| foo_error_to_bar_error(e))?
TB>


Либо более высокоуровневая ошибка должна реализовывать трейт From для исходной ошибки. Тогда просто оператора "?" достаточно безо всяких map_err (хотя и map_err тоже полезная штука). В крейтах thiserror и anyhow есть полезные макросы и типы для того, чтобы не заморачиваться этим вручную.
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[12]: Почему в расте отсутствует выброс исключений?
От: johny5 Новая Зеландия
Дата: 04.12.22 22:36
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Либо более высокоуровневая ошибка должна реализовывать трейт From для исходной ошибки. Тогда просто оператора "?" достаточно безо всяких map_err (хотя и map_err тоже полезная штука). В крейтах thiserror и anyhow есть полезные макросы и типы для того, чтобы не заморачиваться этим вручную.


Да, хотел как раз об этом написать, обычно пишутся автоконверторы ошибок с помощью thiserror макросов, либо всё коллапсируется в единую строковую ошибку с колстеком (anyhow).

Первое нужно если хочется в интерфейсе какой то набор возможных ошибок, например io::error, db::error, и туда автоматически склеивать разнообразные ошибки с нижних уровней. Второе, если не хочется парится а просто вернуться при любой ошибке. Оператор '?' работает и там и там.
Re[5]: Почему в расте отсутствует выброс исключений?
От: flаt  
Дата: 05.12.22 11:34
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Здравствуйте, FR, Вы писали:


FR>>И кроме того есть режим компиляции panic = abort и при его использовании любая паника в любом потоке прибивает процесс

TB>Но будь осторожен. Я комбо словил, случается именно в вин7 в х32 проге. Там паника это особая инструкция которая кидает исключение, а винда гасит исключения, что произошли внутри вндПрок, просто гасит и продолжает исполнение

И..? А что ожидалось? Паникам и исключениям нельзя пересекать языковые барьеры, так как ОС не знает о Rust, а Rust — об исключениях ОС и С++.
Re[6]: Почему в расте отсутствует выброс исключений?
От: T4r4sB Россия  
Дата: 05.12.22 11:41
Оценка:
Здравствуйте, flаt, Вы писали:

F>И..? А что ожидалось?


А почему нельзя просто завалить приложение?! Почему для х64 так и сделано, а для х86, запускаемом на х64, нет?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[11]: Почему в расте отсутствует выброс исключений?
От: flаt  
Дата: 05.12.22 11:47
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Здравствуйте, Marty, Вы писали:


M>>А в расте оператор ?, как я понял, проверяет на ошибку и делает return из текущей функции? Ну может и удобно, но как я понимаю, у всей иерархии тип результата одинаковый? Это не особо часто таки бывает. Или как оно работает?


TB>Ты имеешь в виду наверное не "тип результата", а "тип ошибки"? Да, если он разный, то проблемка. Ну либо вручную делать


TB>
TB>auto Result = foo().map_err(|e| foo_error_to_bar_error(e))?
TB>

TB>Либо на каком-то уровне иерархии возвращать Box<dyn Err>, ну и типа сразу наиболее общий тип ошибки возвращать.

Не только. try работает с конвертацией типрв, поэтому если BarError умеет создаваться из FooError (impl From<FooError> for BarError), то ? работает прозрачно: foo()?;
Re[13]: Почему в расте отсутствует выброс исключений?
От: flаt  
Дата: 05.12.22 11:49
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Здравствуйте, Marty, Вы писали:


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


TB>Result это такой TaggedUnion, который либо ошибка, либо результат. Тип ошибки и результата не особо ограничиваются. А оператор заточен именно вот Result из стандартной библиотеки.


Оператор ? поддерживает ещё Option и некоторые другие: https://doc.rust-lang.org/std/ops/trait.Try.html#implementors
Re[7]: Почему в расте отсутствует выброс исключений?
От: Zhendos  
Дата: 05.12.22 14:21
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Здравствуйте, flаt, Вы писали:


F>>И..? А что ожидалось?


TB>А почему нельзя просто завалить приложение?! Почему для х64 так и сделано, а для х86, запускаемом на х64, нет?


Можно скомпилировать с panic=abort (https://doc.rust-lang.org/book/ch09-01-unrecoverable-errors-with-panic.html), тогда никакой раскрутки стека,
просто будет падать при панике.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.