Recipe3.10.Making Error-Free Expressions


Recipe 3.10. Making Error-Free Expressions

Problem

A complex expression in your code is returning incorrect results. For example, if you wanted to find the average area given two circles, you might write the following expression:

 double radius1 = 2; double radius2 = 4; double aveArea = .5 * Math.PI * Math.Pow(radius1, 2) + Math.PI *                  Math.Pow(radius2, 2); 

However, the result is always incorrect.

Complex mathematical and Boolean equations in your code can easily become the source of bugs. You need to write bug-free equations, while at the same time making them easier to read.

Solution

The solution is quite simple: use parentheses to explicitly define the order of operations that will take place in your equation. To fix the expression presented in the Problem section, rewrite it as follows:

 double radius1 = 2; double radius2 = 4; double aveArea = .5 * (Math.PI * Math.Pow(radius1, 2) + Math.PI *                  Math.Pow(radius2, 2)); 

Notice the addition of the parentheses; these parentheses cause the area of the two circles to be calculated and added together first. Then the total area is multiplied by .5. This is the behavior you are looking for. An additional benefit is that the expression can become easier to read as the parentheses provide clear distinction of what part of the expression is to be evaluated first. This technique works equally well with Boolean equations.

part of the expression is to be evaluated first. This technique works equally well with Boolean equations.

Discussion

Parentheses are key to writing maintainable and bug-free equations. Not only is your intention clearly spelled out, but you also override any operator precedence rules that you might not have taken into account. In fact, the only way to override operator precedence is to use parentheses (you can use temporary variables to hold partial results, which aids in readability, but can increase the size of the IL code). Consider the following equation:

 int x = 1 * 2 - -50 / 4 + 220 << 1; Console.WriteLine("x = " + x); 

The value 468 is displayed for this equation.

This is the same equation written with parentheses:

 int y = ((1 * 2) - ((-50) / 4) + 220) << 1; Console.WriteLine("y = " + y); 

The same value (468) is also displayed for this equation. Notice how much easier it is to read and understand how this equation works when parentheses are used. It is possible to get carried away with the use of parentheses in an equation:

 int z = ((((1 * 2) - ((-50) / 4)) + 220) << (1)); Console.WriteLine("z = " + z); 

This equation also evaluates to 468, but due to the overuse of parentheses, you can get lost determining where one set of parentheses begins and where it ends. You should try to balance your placement of parentheses in strategic locations to prevent oversaturating your equation with parentheses.

Another place where you can get into trouble with operator precedence is when using a ternary operator (?:), defined as follows:

 boolean-expression ? true-case-expression : false-case-expression 

Each type of expression used by this operator is defined as follows:


boolean-expression

This expression must evaluate to a Boolean value or to a value with a type that has an implicit conversion to bool or one that has a true operator. Depending on the outcome of this expression, either the true-case-expression or the false-case-expression will be executed.


true-case-expression

This expression is evaluated when the boolean-expression evaluates to TRue.


false-case-expression

This expression is evaluated when the boolean-expression evaluates to false.

Either the true-case-expression or the false-case-expression will be evaluated; never both.

The ternary operator is able to compact several lines of an if-else statement into a single expression that can fit easily on a single line. This ternary statement is also usable inline with a statement or another expression. The following code example shows the use of the ternary operator inline with an expression:

 byte x = (byte)(8 + ((foo == 1) ? 4 : 2)); 

By examining the order of operator precedence, you can see that the == operator is evaluated first and then the ternary operator. Depending on the result of the Boolean expression foo == 1, the ternary operator will produce either the value 4 or 2. This value is then added to 8 and assigned to the variable x.

This operator is considered to have right-associative properties, similar to the assignment operators. Because of this, you can get into trouble using ternary expressions as expressions within other ternary expressions. Consider the following code:

 // foo currently equals 1 // Assume that all methods will always return a Boolean true, except for Method3, // which always returns a Boolean false. Console.WriteLine(Method1( ) ? Method2( ) : Method3( ) ? Method4( ) : Method5( )); 

Which methods will be called? If you started evaluating this expression from the left, your expression would essentially look like the following:

 Console.WriteLine((Method1( ) ? Method2( ) : Method3( )) ? Method4( ) : Method5( )); 

Notice the extra highlighted parentheses added to clarify how the expression will be evaluated in this manner. The answer that the methods Method1, Method2, and Method4 will be called is wrong. The ternary operators are evaluated from right to left, not left to right, as are most other common operators. The correct answer is that only Method1 and Method2 will be called. Extra highlighted parentheses have been added to this expression, in order to clarify how it is evaluated:

 Console.WriteLine(Method1( ) ? Method2( ) :     (Method3( ) ? Method4( ) : Method5( ))); 

This technique will cause Method1 and Method2 to be called in that order. If any of these methods produced side effects, the application might produce unexpected results.

If you must use nested ternary expressions, make liberal use of parentheses around each ternary expression to clearly specify your intentions.




C# Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2004
Pages: 424

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net