Size: a a a

2020 July 28

ИI

И Ivan in pro.cxx
Ofee
Думаю, что не только можно, но и нужно добавить сначала языковую возможность, как автор верно заметил, это очень похоже на корутины. И корутины тоже приняты без библиотечной поддержки. Я не считаю это катастрофой, в любом случае у пользователя должна оставаться возможность сделать собственную реализацию, независимо от наличия или отсутствия средств в стандартной библиотеке. А уж если у пользователя возможность появится рано или поздно — в чём проблема, если появится рано?

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

То есть на уровне 1 вложенности можно написать чтото типа '?' rust, ну тоесть

void g() {
func1()?;
func2()?;
}

А что будет на следующем уровне вложенности? Тоесть как вызвать функцию g? Тоже ставить вопросики типа

g()?;

Не получится ли тогда, что все везде будут ставить вопросы не задумываясь, и в результате получим теже самые исключения только в профиль?
источник
2020 July 29

O

Ofee in pro.cxx
И Ivan
А как вообще обрабатываются монадические ошибки (не знаю как их правильно назвать) в реальном коде?

То есть на уровне 1 вложенности можно написать чтото типа '?' rust, ну тоесть

void g() {
func1()?;
func2()?;
}

А что будет на следующем уровне вложенности? Тоесть как вызвать функцию g? Тоже ставить вопросики типа

g()?;

Не получится ли тогда, что все везде будут ставить вопросы не задумываясь, и в результате получим теже самые исключения только в профиль?
Да, это возможно, но есть существенная разница.

В случае с исключениями, пользователь функции g() может и не знать, прилетит ли ему исключение, а если да – то какое и откуда, из func1(), func2()?

По сути, автор функции g() может просто взять и забить переложить ответственность за обработку ошибок вызываемых им функций на пользователя функции g(), по сути, оставляя прямое взаимодействие между пользователем функции и частью внутренней имплементации – func1(), func2(). Это не очень красиво, у нас протекла абстракция в случае, если требуется хоть сколько-нибудь нетривиальная обработка ошибки.

В случае же с монадами... Ну, автор функции g(), в идеале, явно укажет тип возвращаемого значения. А ещё ему придется позаботиться, чтобы в случае ошибок, возвращался один и тот же тип ошибки, ведь func1() и func2() могут вернуть разные монады для обработки разных типов ошибок. В любом случае, у пользователя больше понимания о том, как может себя вести функция g(), её контракт выражен возвращаемым типом и способов его нарушить (в идеале) у автора g() просто нет.

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

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

ИI

И Ivan in pro.cxx
>  А ещё ему придется позаботиться, чтобы в случае ошибок, возвращался один и тот же тип ошибки

Ну в нормальных яп типов ошибки (точнее базового класса) и так немного, 1-2 штуки. Так что с этим проблем обычно нет.

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

ГH

Гласси Hudobin in pro.cxx
А там разве не .then/.else для обработки ошибок?
источник

АР

Андрей Руссков... in pro.cxx
И Ivan
>  А ещё ему придется позаботиться, чтобы в случае ошибок, возвращался один и тот же тип ошибки

Ну в нормальных яп типов ошибки (точнее базового класса) и так немного, 1-2 штуки. Так что с этим проблем обычно нет.

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

АР

Андрей Руссков... in pro.cxx
как со старым throws
источник

АР

Андрей Руссков... in pro.cxx
только с ним была скорее проблема полиморфизма
источник

CD

Constantine Drozdov in pro.cxx
Андрей Руссков
да блин noexcept уже принципиально не допилишь. Должно быть наоборот - методы которые кидают дополнительно помечены
Хм... Ты пробовал писать noexcept код?
источник

АР

Андрей Руссков... in pro.cxx
да, проблема не в том чтобы его писать, а в плохом значении по умолчанию
источник

АР

Андрей Руссков... in pro.cxx
скажем надо тебе старый код модернизиировать, покрыв noexcept'ами
источник

АР

Андрей Руссков... in pro.cxx
и пошла возня
источник

D

Danya in pro.cxx
Андрей Руссков
как со старым throws
Со старым throw
И возможно новым throws
))
источник

CD

Constantine Drozdov in pro.cxx
Андрей Руссков
да, проблема не в том чтобы его писать, а в плохом значении по умолчанию
Ну не знаю, у меня проблемы типа конкатенация путей умеет бросать bad_alloc была
источник

АР

Андрей Руссков... in pro.cxx
тут есть нюанс. bad_alloc это исключение которые довольно-таки многие программы не обрабатывают )
источник

АР

Андрей Руссков... in pro.cxx
в отличие от других
источник

CD

Constantine Drozdov in pro.cxx
Андрей Руссков
тут есть нюанс. bad_alloc это исключение которые довольно-таки многие программы не обрабатывают )
Ну вот для начала надо считать, что аллокатор - noexcept
источник

АР

Андрей Руссков... in pro.cxx
в расте такой же принцип примерно - там есть механизм а-ля исключений но только для ошибок аллокации и паник
источник

AD

Apache DOG™ in pro.cxx
Ofee
Да, это возможно, но есть существенная разница.

В случае с исключениями, пользователь функции g() может и не знать, прилетит ли ему исключение, а если да – то какое и откуда, из func1(), func2()?

По сути, автор функции g() может просто взять и забить переложить ответственность за обработку ошибок вызываемых им функций на пользователя функции g(), по сути, оставляя прямое взаимодействие между пользователем функции и частью внутренней имплементации – func1(), func2(). Это не очень красиво, у нас протекла абстракция в случае, если требуется хоть сколько-нибудь нетривиальная обработка ошибки.

В случае же с монадами... Ну, автор функции g(), в идеале, явно укажет тип возвращаемого значения. А ещё ему придется позаботиться, чтобы в случае ошибок, возвращался один и тот же тип ошибки, ведь func1() и func2() могут вернуть разные монады для обработки разных типов ошибок. В любом случае, у пользователя больше понимания о том, как может себя вести функция g(), её контракт выражен возвращаемым типом и способов его нарушить (в идеале) у автора g() просто нет.

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

Ещё не стоит забывать и о том, что монады – не только про обработку ошибок, их функционал несколько шире, это, например, возврат какой-то дополнительной информации или даже возврат полноценного лога. Или более сложный пример – корутины, по сути, тоже монады, просто другая их форма, предназначенная для другой цели
По хорошему для этого юзают F[+_,+_], который для безошибочных функций отдает F[Nothing, T], для ошибочных F[Error, T]и собирает их F[Err1|Err2, T] для f flatMap g
источник

АК

Александр Караев... in pro.cxx
Существуют ли способы проверить, что какой-либо метод класса реализован именно в классе T, а не в одном из его родителей?

struct A { void foo(); };
struct B : A { void bar(); };

static_assert(is_B_method(&B::bar));
static_assert(!is_B_method(&B::foo));


Способы, требующие явного перечисления родителей каждого класса, очевидно, не подходят
источник

AS

Anatoly Shirokov in pro.cxx
Александр Караев
Существуют ли способы проверить, что какой-либо метод класса реализован именно в классе T, а не в одном из его родителей?

struct A { void foo(); };
struct B : A { void bar(); };

static_assert(is_B_method(&B::bar));
static_assert(!is_B_method(&B::foo));


Способы, требующие явного перечисления родителей каждого класса, очевидно, не подходят
источник