Date: Mon, 14 Sep 2020 22:59:52 +0200
#define check_optional(x) if(!x) return std::nullopt
No need to define a new control flow logic for multi level returns. If you
just need a short form for eliminating duplicated null checks, then a
classic macro is perfectly fine for that purpose. Debug capabilities
fortunately don't degrade too much if the content of the macro contains no
data transforms but only control flow logic .
Or just keep it verbose like that, it clearly states the intent and all
possible exception points.
Even what you proposed can be expressed as a macro with ease.
True, a macro also smells, but so does any form of hidden control flow in
that place.
A rigid mindset that you can only get out of the function with a `return`
(in a codebase not allowing exceptions for this precise reason), would not
permit hiding that `return` within another helper function either.
Asking for (inlined) macros to be expressable as real, strictly typed
functions (albeit with modified scope for return/break), what I suppose is
what you actually meant, certainly has been suggested before.
Dmitry Dmitry via Std-Proposals <std-proposals_at_[hidden]> schrieb am
Mo., 14. Sept. 2020, 20:44:
> TL;DR: What do you think about creating a new flavour of control-flow
> statements (in particular "return") that could return from outer/parent
> scope?
>
> In the thread "*Initialisers in ternary operators*" we had this example:
> std::optional<std::string> FindUsersCity(bool non_default) {
> std::optional<ContactsServer> contacts =
> GetOrOpenContactsServerConnection();
> if(!contacts)
> return std::nullopt;
> std::optional<UserId> uid = contacts->GetUserId();
> if(!uid)
> return std::nullopt;
> std::optional<GeoServer> geo = GetOrOpenGeoServerConnection();
> if(!geo)
> return std::nullopt;
> std::optional<Location> uloc = geo->GetLocation(*uid);
> if(!uloc)
> return std::nullopt;
> return uloc->GetCityName();
> }
>
> It seems, that there are many situations with the following pattern:
>
> 1. there is a type
> 2. that defines some invalid state (in case of iterator the state is
> "being equal to end()", in case of Result/Outcome/Expected the state is
> "representing an error", in case of optional it is "nullopt", and so on...)
> 3. attempts of using which in the invalid state are supposed to
> "return" (from the scope where it is used). We can take a step back and
> consider other control-flow statements.
>
>
> Without going into implementation details, what do you think about the
> idea (on a conceptual level) of being able to describe this pattern
> somewhere somehow?
>
> If conceptually it is fine, then what do you think about implementing the
> idea by creating another flavour of return statements that can return not
> only from its own scope, but also from outer/parent scope?
> If you wish, this new flavour can be viewed as a middle ground between (1)
> regular return's (which often requires boilerplate for handling the pattern
> above) and (2) exceptions (which are too non-local and implicit and can
> "jump" at an arbitrary place).
>
> The code above would look like this:
> std::optional<std::string> FindUsersCity() {
> std::optional<ContactsServer> contacts =
> GetOrOpenContactsServerConnection();
> std::optional<UserId> uid = contacts.
> *GetOrReturnNullOpt()*->GetUserId();
> std::optional<GeoServer> geo = GetOrOpenGeoServerConnection();
> std::optional<Location> uloc = geo.*GetOrReturnNullOpt()*
> ->GetLocation(*uid);
> return uloc.*GetOrReturnNullOpt()*->GetCityName();
> }
> where *GetOrReturnNullOpt()* is a method that (1) either returns a value
> if std::optional is not empty, (2) or returns from FindUsersCity() if
> std::optional is empty.
>
>
> I think it could solve
>
> - Initial problem mentioned in "Initialisers in ternary operators": we
> could have something like this: return Cont.find(42).GetOrReturn(0).
> - The problem of using optional without boilerplate (see above).
> - The problem of Error-handling via Result<> without boilerplate,
> which has been a constant source of pain and complaints and holy wars
> between exceptions and return-values for error handling.
> - It also eliminates one more reason to exist for macros (that is how
> people are solving it right now: 1
> <https://stackoverflow.com/questions/51608396/how-to-exit-current-function-if-error-on-current-statement-in-c>,
> 2
> <https://stackoverflow.com/questions/6932401/elegant-error-checking/6933170>
> ).
>
>
> Any thoughts?
>
>
> --
> Dmitry
> *Sent from gmail*
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
No need to define a new control flow logic for multi level returns. If you
just need a short form for eliminating duplicated null checks, then a
classic macro is perfectly fine for that purpose. Debug capabilities
fortunately don't degrade too much if the content of the macro contains no
data transforms but only control flow logic .
Or just keep it verbose like that, it clearly states the intent and all
possible exception points.
Even what you proposed can be expressed as a macro with ease.
True, a macro also smells, but so does any form of hidden control flow in
that place.
A rigid mindset that you can only get out of the function with a `return`
(in a codebase not allowing exceptions for this precise reason), would not
permit hiding that `return` within another helper function either.
Asking for (inlined) macros to be expressable as real, strictly typed
functions (albeit with modified scope for return/break), what I suppose is
what you actually meant, certainly has been suggested before.
Dmitry Dmitry via Std-Proposals <std-proposals_at_[hidden]> schrieb am
Mo., 14. Sept. 2020, 20:44:
> TL;DR: What do you think about creating a new flavour of control-flow
> statements (in particular "return") that could return from outer/parent
> scope?
>
> In the thread "*Initialisers in ternary operators*" we had this example:
> std::optional<std::string> FindUsersCity(bool non_default) {
> std::optional<ContactsServer> contacts =
> GetOrOpenContactsServerConnection();
> if(!contacts)
> return std::nullopt;
> std::optional<UserId> uid = contacts->GetUserId();
> if(!uid)
> return std::nullopt;
> std::optional<GeoServer> geo = GetOrOpenGeoServerConnection();
> if(!geo)
> return std::nullopt;
> std::optional<Location> uloc = geo->GetLocation(*uid);
> if(!uloc)
> return std::nullopt;
> return uloc->GetCityName();
> }
>
> It seems, that there are many situations with the following pattern:
>
> 1. there is a type
> 2. that defines some invalid state (in case of iterator the state is
> "being equal to end()", in case of Result/Outcome/Expected the state is
> "representing an error", in case of optional it is "nullopt", and so on...)
> 3. attempts of using which in the invalid state are supposed to
> "return" (from the scope where it is used). We can take a step back and
> consider other control-flow statements.
>
>
> Without going into implementation details, what do you think about the
> idea (on a conceptual level) of being able to describe this pattern
> somewhere somehow?
>
> If conceptually it is fine, then what do you think about implementing the
> idea by creating another flavour of return statements that can return not
> only from its own scope, but also from outer/parent scope?
> If you wish, this new flavour can be viewed as a middle ground between (1)
> regular return's (which often requires boilerplate for handling the pattern
> above) and (2) exceptions (which are too non-local and implicit and can
> "jump" at an arbitrary place).
>
> The code above would look like this:
> std::optional<std::string> FindUsersCity() {
> std::optional<ContactsServer> contacts =
> GetOrOpenContactsServerConnection();
> std::optional<UserId> uid = contacts.
> *GetOrReturnNullOpt()*->GetUserId();
> std::optional<GeoServer> geo = GetOrOpenGeoServerConnection();
> std::optional<Location> uloc = geo.*GetOrReturnNullOpt()*
> ->GetLocation(*uid);
> return uloc.*GetOrReturnNullOpt()*->GetCityName();
> }
> where *GetOrReturnNullOpt()* is a method that (1) either returns a value
> if std::optional is not empty, (2) or returns from FindUsersCity() if
> std::optional is empty.
>
>
> I think it could solve
>
> - Initial problem mentioned in "Initialisers in ternary operators": we
> could have something like this: return Cont.find(42).GetOrReturn(0).
> - The problem of using optional without boilerplate (see above).
> - The problem of Error-handling via Result<> without boilerplate,
> which has been a constant source of pain and complaints and holy wars
> between exceptions and return-values for error handling.
> - It also eliminates one more reason to exist for macros (that is how
> people are solving it right now: 1
> <https://stackoverflow.com/questions/51608396/how-to-exit-current-function-if-error-on-current-statement-in-c>,
> 2
> <https://stackoverflow.com/questions/6932401/elegant-error-checking/6933170>
> ).
>
>
> Any thoughts?
>
>
> --
> Dmitry
> *Sent from gmail*
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2020-09-14 16:00:12