Ну конкретно растовская, вроде, с равенством (есть трейт EQ<P,Q> который реализуем только EQ<T,T>). Возможно, достаточно потребовать даже что-то более слабое (или даже ничего), сходу действительно не очевидно.
Подождите, откуда в этой ветке берутся продуктовые требования? Мы же обсуждали требования к дизайну языка, или, точнее, к дизайну исключений в компиляторе.
Вопросики нужны только для функций, которые могут возвращать ошибочное значение. Для тех, которые не могут возвращать (при этом и вызываемая функция может не возвращать, и вызывающая, достаточно любого одного) вопросики писать не нужно.
В традиционных исключениях тоже нужно писать два разных слова return и throw, чтобы отличать основной путь выполнения и ошибочный. Если так не нравится писать Ok/Err никто не мешает себе завести макрос throw!, заворачивающий в Err, и retur!, заворачивающий в Ok.
Потому что проблема останова неразрешима. В тьюринг-полной системе эту задачу (для конкретной машины на конкретном входе) можно (вычислимо) сформулировать, что даёт сведение.
Бесплатность нужно сравнивать относительно T. Если бы мы были готовы (по производительности) жить в мире, где любая функция может вернуть result, были бы более холиварные вопросы типизации.
Так эксепшены без try-блоков неотличимы по поведению от паники, разве нет?
Лаконичность теряется только в взаимодействии с другими библиотеками, и, естественным образом, делается один раз на каждую функцию максимум (при этом не один раз в каждом проекте, а прямо глобально один раз).
match result - это, скорее, аналог try/catch блока, если с err что-то происходит. А если ошибку нужно просто пробросить, то в расте бойлерплейт не нужен.
Если типы только по mainflow и никакой обработки (try-except) в коде нет, то Result вообще не нужны, сегодняшний rust так тоже умеет, достаточно писать unwrap. Если какая-то обработка ошибок всё-таки ожидается, то как они должны меняться?
До тех пор, пока эксепшены не случаются - они стоят столько же. В тот момент когда случаются - да, за наличие трейса нужно платить, это, вроде, ожидаемо.
Enum - это плохое решение, потому что если в функцию можно запихнуть возвращающий E-вариант callback, то функция должна сама уметь возвращать exception (и тогда её нужно пометить как бросающую эксепшен).
Есть возможность сделать два варианта функции с колбеком - когда на входе колбек не бросает и функция сама по себе не бросает, и вариант для колбеков, которые бросают.
Если выбор функции случается автоматически (без участия человека), появляется проблема с тем, что выбраться не та, которую ожидал человек и всё станет катастрофически медленнее.
Для кода, который не может бросать эксепшены - настолько же быстрый. Для кода, который может бросать, но не бросает - да, чуть медленнее C++. Для кода, который может бросать и бросает - быстрее C++.
Не может, мы это обсуждали уже. Потому что, например, у колбеков тип "возвращает int32" и "возвращает Result<int32, IOError>" - это два разных типа (после препроцессора, но не до!) и возникает проблема с функциями высшего порядка.
Если написать Result<T, Box<dyn std::error::Error>>, то вопросы начинают работать ровно так, как Вам хочется - любой тип ошибки (со стиранием типа) к нему приводится. Поймать конкретную ошибку становится нельзя, зато очень лаконично.
Ну конкретно растовская, вроде, с равенством (есть трейт EQ<P,Q> который реализуем только EQ<T,T>). Возможно, достаточно потребовать даже что-то более слабое (или даже ничего), сходу действительно не очевидно.
Подождите, откуда в этой ветке берутся продуктовые требования? Мы же обсуждали требования к дизайну языка, или, точнее, к дизайну исключений в компиляторе.
Простите, вечером прислал не ту ссылку.
Вот правильная ссылка: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=2662fec2621b9d9f65660649551d21ff
Объединят, как и ожидалось, std::io::Error и yaml::scanner::ScanError без дополнительных усилий.
Вопросики нужны только для функций, которые могут возвращать ошибочное значение. Для тех, которые не могут возвращать (при этом и вызываемая функция может не возвращать, и вызывающая, достаточно любого одного) вопросики писать не нужно.
В традиционных исключениях тоже нужно писать два разных слова return и throw, чтобы отличать основной путь выполнения и ошибочный. Если так не нравится писать Ok/Err никто не мешает себе завести макрос throw!, заворачивающий в Err, и retur!, заворачивающий в Ok.
Потому что проблема останова неразрешима. В тьюринг-полной системе эту задачу (для конкретной машины на конкретном входе) можно (вычислимо) сформулировать, что даёт сведение.
Растовская - точно не разрешима, она тьюринг-полная: https://sdleffler.github.io/RustTypeSystemTuringComplete/
Бесплатность нужно сравнивать относительно T.
Если бы мы были готовы (по производительности) жить в мире, где любая функция может вернуть result, были бы более холиварные вопросы типизации.
Где бойлерплейт вот в этом решении: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=6786c5d8cc73f485c0a6780a01b229d4 ?
Так эксепшены без try-блоков неотличимы по поведению от паники, разве нет?
Лаконичность теряется только в взаимодействии с другими библиотеками, и, естественным образом, делается один раз на каждую функцию максимум (при этом не один раз в каждом проекте, а прямо глобально один раз).
Не бесплатно. Нет языков, в которых эксепшены (даже без трейса) бесплатны.
match result - это, скорее, аналог try/catch блока, если с err что-то происходит.
А если ошибку нужно просто пробросить, то в расте бойлерплейт не нужен.
Если типы только по mainflow и никакой обработки (try-except) в коде нет, то Result вообще не нужны, сегодняшний rust так тоже умеет, достаточно писать unwrap.
Если какая-то обработка ошибок всё-таки ожидается, то как они должны меняться?
До тех пор, пока эксепшены не случаются - они стоят столько же.
В тот момент когда случаются - да, за наличие трейса нужно платить, это, вроде, ожидаемо.
Нет, конечно. Можно пример if err != nil в каком-нибудь достаточно известном проекте на расте?
Так это, собственно, задача прописывания типов. Если типы прописаны (напрямую или с помощью дженериков) - понятно. Если не прописаны - непонятно.
Enum - это плохое решение, потому что если в функцию можно запихнуть возвращающий E-вариант callback, то функция должна сама уметь возвращать exception (и тогда её нужно пометить как бросающую эксепшен).
Есть возможность сделать два варианта функции с колбеком - когда на входе колбек не бросает и функция сама по себе не бросает, и вариант для колбеков, которые бросают.
Если выбор функции случается автоматически (без участия человека), появляется проблема с тем, что выбраться не та, которую ожидал человек и всё станет катастрофически медленнее.
Для кода, который не может бросать эксепшены - настолько же быстрый.
Для кода, который может бросать, но не бросает - да, чуть медленнее C++.
Для кода, который может бросать и бросает - быстрее C++.
Не может, мы это обсуждали уже. Потому что, например, у колбеков тип "возвращает int32" и "возвращает Result<int32, IOError>" - это два разных типа (после препроцессора, но не до!) и возникает проблема с функциями высшего порядка.
Зависит от E. Есть стандартные решения, которые в E записывают stacktrace (например, уже упомянутый anyhow по умолчанию пишет трейс).
Если написать Result<T, Box<dyn std::error::Error>>, то вопросы начинают работать ровно так, как Вам хочется - любой тип ошибки (со стиранием типа) к нему приводится. Поймать конкретную ошибку становится нельзя, зато очень лаконично.