C++ Logo

std-discussion

Advanced search

Re: short-circuiting logical operations on constexpr predicates

From: Zamfir Yonchev <zamfir.yonchev_at_[hidden]>
Date: Thu, 17 Nov 2022 17:51:32 +0200
Sorry, not sure how to reply to this thread only (probably because I set my
mailing list subscription to "digest once per day").

> `if constexpr` has explicit rules allowing it to discard statements
> depending on the result of the constant expression. But that is a
> special grammatical construct explicitly designed with this
> functionality in mind.

This is exactly what I'm talking about. Why `if constexpr` can discard
statements but boolean operations cannot?
I would imagine that the behaviour of the following two code snippets is
identical:
```
if constexpr (a)
{
  if constexpr (b)
  {
    //do something
  }
}
```

```
if constexpr (a && b)
{
  //do something
}
```

But it is not in the case where `a` is true and `b` is not evaluatable.
Of course, `b` should still be checked for basic syntax the same way
templates are checked even before they're instantiated.
You cannot compile a template with broken syntax but you can still write a
template which doesn't make sense for specific types as long as you don't
instantiate the template with those types.
I think the same logic should apply here. `b` should be valid only if it is
instantiated/evaluated. And this instantiation should only happen if the
expression's value is needed (i.e. `a` was true).
This is what I refer to as "short-circuiting".
Think of it as a lazy evaluation.
If `a` is false the compiler should not even consider evaluating `b` and
should not generate any compilation errors if `b` is not a valid expression.

I realize I'm complaining about syntactic sugar but syntactic sugar is
sometimes needed to adhere to the DRY principle and in this case I think it
would make the code more readable and less error-prone. Also, it would make
the generic world look and feel more like the runtime world.
I would go even further and add a constexpr ternary operator, so you can
reduce code duplication even more. But that's a totally different topic.

--
Zamfir Yonchev
On Thu, Nov 17, 2022 at 2:00 PM <std-discussion-request_at_[hidden]>
wrote:
> Send Std-Discussion mailing list submissions to
>         std-discussion_at_[hidden]
>
> To subscribe or unsubscribe via the World Wide Web, visit
>         https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
> or, via email, send a message with subject or body 'help' to
>         std-discussion-request_at_[hidden]
>
> You can reach the person managing the list at
>         std-discussion-owner_at_[hidden]
>
> When replying, please edit your Subject line so it is more specific
> than "Re: Contents of Std-Discussion digest..."
>
>
> Today's Topics:
>
>    1. Re: short-circuiting logical operations on constexpr
>       predicates (Jason McKesson)
>    2. Re: short-circuiting logical operations on constexpr
>       predicates (Edward Catmur)
>    3. Re: short-circuiting logical operations on constexpr
>       predicates (Thiago Macieira)
>
>
> ----------------------------------------------------------------------
>
> Message: 1
> Date: Wed, 16 Nov 2022 09:42:58 -0500
> From: Jason McKesson <jmckesson_at_[hidden]>
> To: std-discussion_at_[hidden]
> Subject: Re: [std-discussion] short-circuiting logical operations on
>         constexpr predicates
> Message-ID:
>         <CANLtd3UfeDJ53Hm5zJXHUv0hNp-c=Yfn0Q6MTRzm=
> OeWiioNUw_at_[hidden]>
> Content-Type: text/plain; charset="UTF-8"
>
> On Wed, Nov 16, 2022 at 5:00 AM Zamfir Yonchev via Std-Discussion
> <std-discussion_at_[hidden]> wrote:
> >
> > Hi,
> >
> > I was wondering why the language doesn't support short-circuiting on
> logical operations in constexpr context.
>
> It does. The rules of short-circuit evaluation don't change because
> something is in a constant expression. Your problem is not a lack of
> short-circuit evaluation; your problem is that short-circuit
> evaluation doesn't mean what you think it does.
>
> `std::invoke_result_t<F, T>` is ill-formed if `F` is not invokable.
> That is not a matter of expression evaluation; that's a matter of
> template instantiation. It's not the result of the evaluation that is
> ill-formed; it's the *existence* of the expression itself. The literal
> text of the source code makes no sense, as far as the language is
> concerned. It is no different than if you wrote `a + - + - + c`.
>
> The compiler doesn't get to the point where it would even consider
> evaluating the expression because the code doesn't make sense.
>
> `if constexpr` has explicit rules allowing it to discard statements
> depending on the result of the constant expression. But that is a
> special grammatical construct explicitly designed with this
> functionality in mind.
>
> So the reason why what you wrote doesn't work is because there is no
> special expression-level construct that was added to the language to
> allow discarding of subexpressions in the same way that `if constexpr`
> can discard statements.
>
>
> ------------------------------
>
> Message: 2
> Date: Wed, 16 Nov 2022 15:02:26 +0000
> From: Edward Catmur <ecatmur_at_[hidden]>
> To: std-discussion_at_[hidden]
> Subject: Re: [std-discussion] short-circuiting logical operations on
>         constexpr predicates
> Message-ID:
>         <
> CAJnLdOaTNma9xmW82jtKY0z4XYnBtCn++D5SyzARw37H6eCA1w_at_[hidden]>
> Content-Type: text/plain; charset="utf-8"
>
> On Wed, 16 Nov 2022 at 14:44, Jason McKesson via Std-Discussion <
> std-discussion_at_[hidden]> wrote:
>
> > On Wed, Nov 16, 2022 at 5:00 AM Zamfir Yonchev via Std-Discussion
> > <std-discussion_at_[hidden]> wrote:
> > >
> > > Hi,
> > >
> > > I was wondering why the language doesn't support short-circuiting on
> > logical operations in constexpr context.
> >
> > It does. The rules of short-circuit evaluation don't change because
> > something is in a constant expression. Your problem is not a lack of
> > short-circuit evaluation; your problem is that short-circuit
> > evaluation doesn't mean what you think it does.
> >
> > `std::invoke_result_t<F, T>` is ill-formed if `F` is not invokable.
> > That is not a matter of expression evaluation; that's a matter of
> > template instantiation. It's not the result of the evaluation that is
> > ill-formed; it's the *existence* of the expression itself. The literal
> > text of the source code makes no sense, as far as the language is
> > concerned. It is no different than if you wrote `a + - + - + c`.
> >
> > The compiler doesn't get to the point where it would even consider
> > evaluating the expression because the code doesn't make sense.
> >
> > `if constexpr` has explicit rules allowing it to discard statements
> > depending on the result of the constant expression. But that is a
> > special grammatical construct explicitly designed with this
> > functionality in mind.
> >
> > So the reason why what you wrote doesn't work is because there is no
> > special expression-level construct that was added to the language to
> > allow discarding of subexpressions in the same way that `if constexpr`
> > can discard statements.
> >
>
> Ahem. Actually, we do have such a construct in the evaluation of
> constraints. You can make use of that mode by wrapping your test in
> `requires requires`:
>
>   constexpr bool test = requires { requires std::is_invocable_v<F, T> &&
> std::is_same_v<std::invoke_result_t<F, T>, int>; };
>
> Demo: https://godbolt.org/z/7q5dvKnsn
>
> https://eel.is/c++draft/expr.prim.req.general#5.sentence-3
> -------------- next part --------------
> HTML attachment scrubbed and removed
>
> ------------------------------
>
> Message: 3
> Date: Wed, 16 Nov 2022 11:17:22 -0800
> From: Thiago Macieira <thiago_at_[hidden]>
> To: std-discussion_at_[hidden]
> Subject: Re: [std-discussion] short-circuiting logical operations on
>         constexpr predicates
> Message-ID: <1805684.QCnGb9OGeP_at_[hidden]>
> Content-Type: text/plain; charset="us-ascii"
>
> On Wednesday, 16 November 2022 06:42:58 PST Jason McKesson via
> Std-Discussion
> wrote:
> > The literal
> > text of the source code makes no sense, as far as the language is
> > concerned. It is no different than if you wrote `a + - + - + c`.
>
> Note, this expression *does* make sense and is allowed. The first + is the
> binary addition operator; all the rest are unary prefixes. So this
> expression
> is
>
>   a + (-(+(-(+c))))
>
> If you remove the idempotent unary plus, you get
>
>   a + (-(-c))
>
> And two negations is the same as doing nothing (ignoring the UB at
> INT_MIN),
> resulting in a simple addition
>
>   a + c
>
> Similarly, both a+++c and a---c are permitted, as are a*/*/*/c and
> a/*/*/*c.
>
> None of those should pass a code review, of course.
>
> --
> Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
>    Software Architect - Intel DCAI Cloud Engineering
>
>
>
>
>
> ------------------------------
>
> Subject: Digest Footer
>
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>
>
> ------------------------------
>
> End of Std-Discussion Digest, Vol 44, Issue 3
> *********************************************
>

Received on 2022-11-17 15:51:45