Is it possible to prevent death by parentheses?

2019-06-19 18:17发布

Occasionally, I will write some code with way more parentheses than I like.

 if(!(new Day((((new Date()) / millisecondsPerDay) % 75)) instanceof oldDay))) { 
    // Bonus points if that condition made any sense to you
 }

It is hard to keep track of how many parentheses I need to put, especially when I'm not using an IDE that immediately tells me when something is wrong. In fact, I bet the above example doesn't match the parentheses correctly. I've been pegged with errors from death by parentheses more than I would like to admit.

I was wondering if there was a way to circumvent this. What techniques can I use to avoid having to wrap things with so many parentheses?

Are there any languages with a mechanism that prevent the need for so many parentheses? For example, I thought adding special characters that automaticall close parentheses and one that automatically opens them might help. (< and > in the following example)

if(!(new Day<new Date()) / millisecondsPerDay) % 75> instanceof oldDay>

5条回答
在下西门庆
2楼-- · 2019-06-19 18:34

Well, first of all i always like to refactor this kind of code. If i can, i extract part of expression to the variable (or function, whichever suites best), then you can make more sense to the code itself, and you would'nt need to make such a mess

bool isOldDay(int someFactor)
{
    if(someFactor instanceof oldDay) 
    {
        return true;
    }
    return false;

}

var today = new Date();
var particularFactor = today/millisecondsPerDay;
var someFactor = particularFactor % 75
var day = new Day(someFactor);


if(!isOldDay(day)) //Do something

EDIT: By the way if you want to do something without parentheses you can try something like this: Reverse Polish Notation

Which you can make 5 + ((1 + 2) * 4) − 3 into this thing : 5 1 2 + 4 * + 3 - .Of course this form may be very close to stack representation of calculations in compilators.

查看更多
小情绪 Triste *
3楼-- · 2019-06-19 18:42

If i follow:

var a = new Date() / millisecondsPerDay) % 75
var newDay = new Day(a);

if (! newDay instanceof oldDay) {
   //do something
}

If you can't read an inline logic... just put it on multiple line! ;-)

查看更多
Explosion°爆炸
4楼-- · 2019-06-19 18:49

That many parens is a pretty good indication that

  1. The author doesn't understand the operator precedence of the language. For instance, you've wrapped a constructor invocation new Date() in a completely redundant set of parentheses (new Date()). Unless your language is different than any normal language, that prefix new operator is going to bind tighter than almost any other operator.

  2. The author doesn't care about understandability.

Make it more understandable, testable and maintainable. Somebody down the line (who might well be you, will thank you for it...or curse you for not doing so).

Some hints:

  • Understand your language's operator precedence. Don't add parentheses without good reason. Somebody who does understand operator precedence has to spend some time figuring out why you put those parens in: are you doing something non-obvious here?

  • Break the expression up. Use stack space (it's cheap).

  • Compute each simple subexpression as an independent local variable, building on the previous ones.

  • make the variable names reflect what they represent.

Then test only the final temporary. In your case, that looks to be a boolean.

Writing code like that makes it easy to under stand (there are no complex expression), it makes it easy to test (simple expressions is much easier to check for correctness). It makes it easier to identify/locate problems.

查看更多
劳资没心,怎么记你
5楼-- · 2019-06-19 18:51

One viable alternative is to precompute the parenthesized values before the conditional loop. Take your code for example:

if(!(new Day((((new Date()) / millisecondsPerDay) % 75)) instanceof oldDay))) { 
    // Bonus points if that condition made any sense to you
 }

Let's start breaking it up.

Date d1 = new Date();
var factor1 = (d1 / millisecondsPerDay ) % 75;
Day day1 = new Day (factor1);

if (!day1 instanceof oldDay) {
// do something
}

Remember that code is written for humans to read and only afterwards for machines to execute. If you find giant conditionals, then start preprocessing them and break it up. If it takes more than a second to figure out what your condition is checking, then it's probably too long.

查看更多
疯言疯语
6楼-- · 2019-06-19 18:57

I would say the answer to this is NO, because the whole point of all those parentheses is to avoid ambiguity in the expression. If you remove them, the expression may not be evaluated in the way that you think it will.

Ergo, if there was such a construct as <> to fix/add your missing parens, if may not add them in the place you were expecting it to.

Simple example (as if it were needed):

(90 / 100 - 1)

...will evaluate to either...

((90 / 100) - 1) // = -0.1

...or...

(90 / (100 - 1)) // = 0.90909090...

... and you have no real way to know which one it will be.

The only alternative is to move some of the parts outside your expression, store the results in variables so you can evaluate less in your expression.

查看更多
登录 后发表回答