Imply Logical Operators

Feature

Add a new logical operators imply, which follow this logical table:
KiJ8A

Motivation

Let’s use a dummy exemple:

from typing import Literal

def dummy(mode: Literal[0,1,2,3], a=None):
   """
   The mode 3 requiert the paramater 'a' to be passed
   """
   assert (mode!=3) or (a is not None), "You need to pass a parameter a, when using the mode 3!"
   ...

In my opinion, these logical operations are not easily readable, so I propose we use a logical operator ‘imply’ to make it clearer:

from typing import Literal

def dummy(mode: Literal[0,1,2,3], a=None):
   """
   The mode 3 requiert the paramater 'a' to be passed
   """
   assert (mode==3) imply (a is not None), "You need to pass a parameter a, when using the mode 3!"
   ...

Logically, imply: p => q is the same as not(p) or q

Techical side

imply can be build-in from or, and, not, so by construction, there should be no issue.

I don’t think this comes up often enough to warrant an operator, although you’re of course free to use an auxiliary function.

I think the example you give would be commonly written as

if mode == 3:
    assert a is not None, "..."
3 Likes

(Side note: Don’t use assert to test your arguments, outside of simple/trivial demos for the purpose of argument. In real code, be sure to use actual tests and actual exception raising.)

4 Likes

There are 16 ways to combine 2 boolean variables.

It is rare to see a language implement all 16.
Usually it is true, false, not, or, and, xor.

As the others are rarely used or have simple expressions they are not usually seen as necessary to provide as ops.

I am not sure if there are accepted names for the other ops.

And also == and != which gives you two more.

1 Like

Some have names, but I wouldn’t call them commonly known/used. OP’s imply is called ‘material conditional’ on Wikipedia.

xor and != are one in the same, same truth table. == is xnor

Exclusive or, logical biconditional, same thing.

Exclusive or is also the logical conjunction of material conditional and it’s converse

2 Likes

My opinion, I don’t think this is clearer than writing


if mode == 3 and a is None:
    raise ValueError("if mode is 3 then a must be passed")
5 Likes

That’s how I would put it as well. not(p) or q is not(p and not q) which makes for much easier parsing, at least to me.

I read all your comments, thanks for giving you’re opinion :smile:

I think we kinda lose the focus of the discussion about ‘imply’, because of ‘assert’ was replaced by ‘if’, probably because my example wasn’t that good :sweat_smile:

So I would like to show you a new concrete use case where ‘imply’ would be a good fit:

# 1) Without imply
def dummy(show_errors, is_verbose):
    if (not show_errors) or is_verbose:
        raise ValueError("When 'show_errors' is true, 'is_verbose' should be true!")
    ...

# 2) Without imply
def dummy(show_errors, is_verbose):
    if not (show_errors and not is_verbose):
        raise ValueError("When 'show_errors' is true, 'is_verbose' should be true!")
    ...

# 3) With imply
def dummy(show_errors, is_verbose):
    if show_errors imply is_verbose:
        raise ValueError("When 'show_errors' is true, 'is_verbose' should be true!")
    ...

I think, in my POV that it is much more simpler and natural to understand with imply in the 3)…

It would be if anyone were used to it. But since no one is, IMO, the ordinary Boolean operators are better code.

2 Likes

Oh, we do have an infix operator for it already, it’s p <= q if both are bool. But that’s just confusing

4 Likes

This seems like it could be fixed with a simple user-defined function. Something like:

def imply(gate: bool, test: bool) -> bool:
    return gate and not test

def dummy(show_errors, is_verbose):
    if imply(show_errors, is_verbose):
        raise ValueError("When 'show_errors' is true, 'is_verbose' should be true!")
    ...
2 Likes

I’ve TA’d enough undergraduates who struggled with material implication[1] that I don’t think adding this complexity would be a benefit. The word “imply” has “plain language” connotations that are really not helpful here (e.g. of a causal relationship between the “if” part and the “then” part).


  1. I’ve never personally seen it called material “conditional” :person_shrugging: ↩︎

6 Likes

No we are focused, we simply do not agree that this is a needed addition.
Its not intuitive and has to be learnt, would be a maintenance burden.
Its easier to understand using the current boolean operations.

I think we are focused, it’s just that your idea of creating a material implication operator, when it can be perfectly defined using boolean algebra, is not that helpful. Mainly because it’s easier for most to understand as a boolean algebra statement. I don’t think a lot of CS people learn traditional logic? I mean, hey if we do a material implication operator, why not a biconditional operator then <=>, we already have that, ==

As a matter of fact, I think we have operators for every truth function except nand and nor?

for op in ('p != p', 'p == p', 'p', 'not p', 'q', 'not q',
           'p and q', 'not (p and q)', 'p or q', 'not (p or q)',
           'p > q', 'p <= q', 'p < q', 'p >= q', 'p != q', 'p == q'):
    tt = tuple(eval(op) for p in (False, True) for q in (False, True))
    print(op, ':', ''.join(map(lambda b: str(bool(b))[0], tt)))
(not p) and (not q)
(not p) or (not q)

Or any i missing something?

Those are just not (p or q) and not (p and q), respectively, by application of De Morgan’s laws, and both of those were included in Nicolas’s list.

I was responding to no nand and no nor.