Implication Operator

Topics: C# Language Design
Oct 31, 2014 at 4:27 PM
Any consideration for an implication operator? How about using the naj operator?

It would certainly come in handy when writing code contracts:

Proposed
Contract.Invariant(isAuthority ~> authoritativeIdRanges != null);
Read as: "isAuthority implies authoritativeIdRanges != null"

-vs-

Current C#
Contract.Invariant(!isAuthority || authoritativeIdRanges != null);
Read as: Huh?!
Oct 31, 2014 at 4:49 PM
  • if you run then I'll kill you.
  • don't run or I'll kill you.
Easy to remember, Is worth a new operator? We already have XOR that is exactly the same as != for bool...
Oct 31, 2014 at 4:58 PM
Edited Oct 31, 2014 at 4:58 PM
Honestly, I don't know what you're talking about in those bullets.

Yes, it's easy to remember, not so easy to infer though. It always takes me a moment to recognize !x || y as an implication.

Isn't clarity in programming important to you?
Oct 31, 2014 at 5:44 PM
Sorry maybe I was too cryptic.
  • [you run] ~> [I will kill you].
  • ![run] || [I will kill you].
Isn't clarity in programming important to you?
Of course, but the number of tokens is relatively small and I'm not sure if implication operation is common enough to take one and add one more thing that a developer has to learn, given that the alternative is not that bad.

Also I know how to manipulate boolean expression symbolically as long as there are only NOT / OR / AND. But with XOR or implication I don't.
!(!isAuthority || authoritativeIdRanges != null) 
(!!isAuthority && !(authoritativeIdRanges != null)
isAuthority && authoritativeIdRanges  == null
!(isAuthority ~> authoritativeIdRanges != null) 
//harder to continue
Oct 31, 2014 at 5:57 PM
Edited Oct 31, 2014 at 6:01 PM
It wasn't too cryptic, I understood the analogy :)

What I didn't understand is why you think English sentences have any relevance. The intention of !someExpr || someOtherExpr is not immediately obvious to me.
Oct 31, 2014 at 6:00 PM
Your last example marked "harder to continue" is interesting, but I'm not sure that's a good argument against this feature. I can do this:
var r = x++-+-++y;
but that doesn't mean we shouldn't have unary operators. :-)
Oct 31, 2014 at 6:07 PM
Edited Oct 31, 2014 at 6:07 PM
It seems your arguments against the feature so far are as follows:
  1. The difference between alternatives is minimal or zero.
  2. Developers may be able to form strange expressions with it.
Frankly, I think #1 is subjective and I actually disagree.

#2 just doesn't seem like a good reason not to include a potentially useful feature.

The only good arguments against this feature I've thought of are:
  1. Its usage scenarios are a bit esoteric. (Not if you use Code Contracts.)
  2. There are more important features to include. (Yes, probably.)
  3. It's too complex to implement. (Doubtful; it could just be syntactic sugar for !x || y couldn't it?)
Oct 31, 2014 at 6:13 PM
I also wonder whether the "harder to continue" problem is just a training issue. Using that expression frequently may change both of our opinions on it.
Oct 31, 2014 at 6:27 PM
davedev wrote:
I also wonder whether the "harder to continue" problem is just a training issue. Using that expression frequently may change both of our opinions on it.
I also think the feature looks a little bit myopic. I'm not aware of any interesting patterns that it enables:
a~>(b~>c)
!a || (b~>c)
!a || !b || b
This pattern is extremely rare.
(a~> b) && (c~>d)
This is also hard to understand.

So the sweet spot is saving 1 character (and maybe some parenthesis) and for that yo have to teach one new operator, learn about precendence and associativity... really worth?

You can quite easily write an extension method like:
a.Implies(b)
You'll lose shout-circuit but still could do the job in most of the cases.
Oct 31, 2014 at 7:02 PM
It's certainly myopic. I intended to improve real code contracts that I write.
So the sweet spot is saving 1 character
Well, I don't really care about saving characters at all. That's not the point. I'd accept this: x ~impl~> y
You can quite easily write an extension method like:
Agreed, that's actually a really good point because in fact I don't care about short-circuiting in every scenario that I'd used it. Code contracts must be pure anyway.

The remaining problem is that everyone has to write their own Implies operator, and most people won't, so essentially nothing will change. Of course, I can write the operator for my own code, but then I'm doing something that just feels hacky and should be a native C# feature.

Ultimately, the only really good argument against this feature is that its cost outweighs its benefits, but again that's a bit subjective. You perhaps don't use DbC and thus have little to no use for such an operator; however, I find myself wondering about this feature all the time as I write code like !x || y strictly with the intention of meaning x ~> y.
Oct 31, 2014 at 7:14 PM
Here's a funny thought: What if the ternary operator simply allowed the "else" part to be omitted?
Contract.Invariant(x ? y);
Terrible?
It's interesting to me how easily the implied semantics seems to be lost by completing the ternary expression:
Contract.Invariant(x ? y : true);
Oct 31, 2014 at 7:17 PM
Just one more point about the subjective nature of your argument:
This pattern is extremely rare.
(a~> b) && (c~>d)
Actually that's not rare at all in DbC, though the Code Contracts team has suggested that we create 2 separate invariants because it helps the analyzer:
Contract.Invariant(a ~> b);
Contract.Invariant(c ~> d);
... additional invariants ....
Nov 7, 2014 at 11:13 PM
Edited Nov 7, 2014 at 11:18 PM
@davedev, I'm not sure I would like the ternary without else. Some developers might think of the else as returning false, since that is the default value for a Boolean:
x ? y : false
which is equivalent to x && y.

I personally would be tempted to read it as a coalescing operator, like ?? but for Boolean values, which leads to yet a different semantic interpretation if you mentally replace null with false:
x == false ? y : x
which is the same as x || y.

I'd stick with x ~> y.