c# - How to make multiplication operator (*) behave as short-circuit? -
i have lots of computations, specially multiplication, first part 0 , don't want evaluate second operand in case. there @ least 2 short-circuit operators in c#: &&
, ||
evaluate second operand if necessary. want achieve similar behavior multiplication operator.
in .net can't overload &&
operator directly, can overload &
, false
operators, can use extension points change behavior of short-circuit operator. can find more details @ article c# operator overloading: ‘&&’ operator
is there means achieve or similar behavior multiplication operator?
this pure syntax question, because implementation simple. next method achieves want in terms of functionality:
public static double shortcircuitmultiply(double val, func<double> anothervalue) { var epsilon = 0.00000001; return math.abs(val) < epsilon ? 0 : val * anothervalue(); }
note: implementation not full: in c# if multiply 0.0
double.nan
or double.negativeinfinity
or double.positiveinfinity
, you'll nan
, in terms of shortcircuitmultiply
- zero. let's ignore detail , it's irrelevant in domain.
so if call shortcircuitmultiply(0.0, longoperation)
longoperation
func<double>
, last term won't evaluated , result of operation zero.
the problem is, stated, have lots of shortcircuitmultiply
calls , want make code more readable. want code similar 0.0 * longoperation()
if possible.
another note: i've tried build wrapper on double
, create implicit casting double , overload *
operator. understand, redundant: wanted acheive readability, trying build yet wrapper. anyway, next code demonstrates intent:
class mydouble { double value; public mydouble(double value) { this.value = value; } public static mydouble operator *(mydouble left, mydouble right) { console.writeline ("* operator call"); return new mydouble(left.value * right.value); } public static implicit operator double(mydouble mydouble) { console.writeline ("cast double"); return mydouble.value; } public static implicit operator mydouble(double value) { console.writeline ("cast mydouble"); return new mydouble(value); } }
now if go with:
mydouble 0 = 0; console.writeline (zero * longoperation()); //longoperation still func<double>
i've receive:
cast mydouble called longoperation <-- want avoid (it's printed longoperation body) cast double cast mydouble * operator call cast double 0
but can see, longoperation
evaluated long before overloaded operator called, , can't substitute 1 of parameters func
or expression
make lazy.
the problem mydouble
wrapper class use calling longoperation
directly. *
not short circuiting, called directly.
instead, make wrapper accept func<double>
second parameter instead of double value itself. work shortcircuitmultiply
function:
public static mydouble operator *(mydouble left, func<double> right) { return math.abs(left.value) < epsilon ? new mydouble(0) : new mydouble(left.value * right()); }
then use this:
mydouble x = 0; console.writeline(x * longoperation);
and chaining works:
mydouble x = 5; console.writeline(x * operationreturingzero * longoperation);
full example
class program { static void main() { mydouble x = 0; console.writeline(x * longoperation); mydouble y = 5; console.writeline(y * operationreturningzero * longoperation); console.readline(); } private static double longoperation() { console.writeline("longoperation"); return 5; } private static double operationreturningzero() { console.writeline("operationreturningzero"); return 0; } } class mydouble { private static double epsilon = 0.00000001; private double value; public mydouble(double value) { this.value = value; } public static mydouble operator *(mydouble left, func<double> right) { console.writeline("* (mydouble, func<double>)"); return math.abs(left.value) < epsilon ? new mydouble(0) : new mydouble(left.value * right()); } public static mydouble operator *(mydouble left, mydouble right) { console.writeline("* (mydouble, mydouble)"); return new mydouble(left.value * right.value); } public static implicit operator double(mydouble mydouble) { console.writeline("cast double"); return mydouble.value; } public static implicit operator mydouble(double value) { console.writeline("cast mydouble"); return new mydouble(value); } }
output:
cast mydouble * (mydouble, func<double>) cast double 0 cast mydouble * (mydouble, func<double>) operationreturningzero * (mydouble, func<double>) cast double 0
Comments
Post a Comment