# Why no if-but-not-else construct?

**URL:** <https://swi-prolog.discourse.group/t/why-no-if-but-not-else-construct/4149>\
**Category:** Predicate\
**Tags:** discussion\
**Created:** [July 9, 2021, 2:52pm UTC](https://swi-prolog.discourse.group/t/why-no-if-but-not-else-construct/4149 "2021-07-09T14:52:25Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![dmchurch](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/dmchurch/32/3427_2.png) [@dmchurch](https://swi-prolog.discourse.group/u/dmchurch)\
**Post date:** [July 9, 2021, 2:52pm UTC](https://swi-prolog.discourse.group/t/why-no-if-but-not-else-construct/4149/1 "2021-07-09T14:52:25Z")

</div>

I often find myself using the `(P -> Q; true)` formulation, when I need to do an extra check or take an extra action _but only_ when a certain precondition is true; when it isn’t, the clause can proceed as it would otherwise. Why isn’t there a built-in operator or predicate that does this? Perhaps something that binds tighter than `,/2`, like say:

```prolog
:- op(800, xfy, ?).

% Whenever P succeeds, then Q must succeed, but \+P is fine
P ? Q :- P *-> Q; true.

% Match *or* generate "(At)" in text, when At is an atom
parenthesized_atom(At) -->
    `(`,
    {ground(At) ? atom_codes(At,AC)},
    string(AC),
    `)`,
    {atom_codes(At,AC)}.

```

Note that this isn’t a “how can I do this, please” - I have a number of ways I _can_ implement this, and it’s not all that cumbersome (and more to the point, I want to make sure that I am writing _idiomatic_ Prolog). It’s more of a “why was Prolog designed this way?” combined with some amount of “are there hidden pitfalls to doing this kind of thing that I’m not aware of?”

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [July 9, 2021, 6:18pm UTC](https://swi-prolog.discourse.group/t/why-no-if-but-not-else-construct/4149/2 "2021-07-09T18:18:57Z")

</div>

I don’t know the reason (I have a couple of theories), but I do know that Logtalk’s linter complains about `(P->Q)` but doesn’t complain about `(P->Q;fail)`.

Paulo Moura (author of Logtalk) doesn’t seem to be in this discussion group, but maybe somebody knows the reason?

---

<div class="post-metadata">

**Author:** ![swi](https://avatars.discourse-cdn.com/v4/letter/s/51bf81/32.png) [@swi](https://swi-prolog.discourse.group/u/swi)\
**Post date:** [July 9, 2021, 6:33pm UTC](https://swi-prolog.discourse.group/t/why-no-if-but-not-else-construct/4149/3 "2021-07-09T18:33:03Z")

</div>

I think the reason is that from a logical point of view, `P -> Q` is seen as (in logic) `P implies Q`.

Now, when `P implies Q` (in logic), you are not saying anything at all about what happens if `not P` (you could still have `Q` even if `not P`), and therefore I think it would be sensible from this point of view to always specify what happens if `not P` when you are implementing a programming language.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [July 10, 2021, 4:42pm UTC](https://swi-prolog.discourse.group/t/why-no-if-but-not-else-construct/4149/7 "2021-07-10T16:42:24Z")

</div>

Almost every time I use `(P->Q;true)`, `Q` is something “impure”, such as a print statement – I have more examples of `(P->true;Q)`.

So, maybe it’s a Good Thing that there’s no short-cut for `(P->Q;true)` because it’s a “[code smell](https://en.wikipedia.org/wiki/Code_smell)”.

---

<div class="post-metadata">

**Author:** ![swi](https://avatars.discourse-cdn.com/v4/letter/s/51bf81/32.png) [@swi](https://swi-prolog.discourse.group/u/swi)\
**Post date:** [July 10, 2021, 8:48pm UTC](https://swi-prolog.discourse.group/t/why-no-if-but-not-else-construct/4149/8 "2021-07-10T20:48:47Z")

</div>

> [@peter.ludemann](#):
>
> maybe it’s a Good Thing that there’s no short-cut for `(P->Q;true)` because it’s a “[code smell](https://en.wikipedia.org/wiki/Code_smell)”.

Yes, I don’t often need this construct.

On the other hand `(P->true;Q)` is much more common because `P` unifies what needs to be unified.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [July 13, 2021, 4:34am UTC](https://swi-prolog.discourse.group/t/why-no-if-but-not-else-construct/4149/10 "2021-07-13T04:34:34Z")

</div>

`(bad_input(X)->throw(error(bad_input(X), _));true)` … this is similar to must\_be/2 or domain\_error/2.  
Although there’s been a long discussion about failure vs throwing an exception.

Another useful case: In a DCG: `({some_test(X)}->[X];[])`.

---

<div class="post-metadata">

**Author:** ![dmchurch](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/dmchurch/32/3427_2.png) [@dmchurch](https://swi-prolog.discourse.group/u/dmchurch)\
**Post date:** [July 14, 2021, 3:06pm UTC](https://swi-prolog.discourse.group/t/why-no-if-but-not-else-construct/4149/13 "2021-07-14T15:06:54Z")

</div>

> [@anon95304481](#):
>
> Quizz, whats the result of these in terms of choice points.  
> Can you answer without running [SWI-Prolog](https://www.swi-prolog.org/pldoc/doc_for?object=manual)?

Ooh fun, I’ll play! Let’s see. I’ll mark the `true`s that get executed with `%%%%`

```prolog
?- ((true->true),true;true).
% %%%% %%%% %%%%^ Choice point here, this isn't a ->; construct
?- ((true->true);true).
% %%%% %%%% No choice points, the -> cuts the ; choice
?- ((true->true);true;(true->true)).
% %%%% %%%% ^ Choice point here, the second ; doesn't get cut
?- (((true->true);true);(true->true)).
% %%%% %%%% ^ Choice point here, syntactically equivalent to the above

```

I _think_ these are correct. Not so sure about #3, but I’m pretty sure the precedence rules group on the left `;/2`, so only that one gets cut by the `->/2`.

Well? How’d I do? 😄

---

<div class="post-metadata">

**Author:** ![dmchurch](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/dmchurch/32/3427_2.png) [@dmchurch](https://swi-prolog.discourse.group/u/dmchurch)\
**Post date:** [July 14, 2021, 3:16pm UTC](https://swi-prolog.discourse.group/t/why-no-if-but-not-else-construct/4149/15 "2021-07-14T15:16:35Z")

</div>

Ah! I had my precedence rules for `;/2` backward. I always have trouble with those… which is why `write_canonical/1` is my best friend 😄
