What is the output of the following program?
namespace colors
public class Color
public method Color
in req a_red, int
in req a_green, int
in req a_blue, int
proc
m_red = (a_red & ^x(ff))
m_green = (a_green & ^x(ff))
m_blue = (a_blue & ^x(ff))
endmethod
public virtual property RgbValue, int
method get
proc
mreturn m_red | (m_green * ^x(100)) | (m_blue * ^x(10000))
endmethod
endproperty
public static method op_Addition, @Color
in req a_color1 ,@Color
in req a_color2 ,@Color
proc
mreturn new Color(a_color1.m_red|a_color2.m_red,
& a_color1.m_green|a_color2.m_green,
& a_color1.m_blue|a_color2.m_blue)
endmethod
protected m_red, int
protected m_green, int
protected m_blue, int
endclass
public class TransparentColor extends Color
public method TransparentColor
in req a_alpha, int
in req a_red, int
in req a_green, int
in req a_blue, int
parent(a_red,a_green,a_blue)
proc
m_alpha = (a_alpha & ^x(ff))
endmethod
public override property RgbValue, int
method get
proc
mreturn parent.RgbValue | (m_alpha * ^x(1000000))
endmethod
endproperty
public static method op_Addition, @TransparentColor
in req a_color1, @TransparentColor
in req a_color2, @Color
proc
mreturn new TransparentColor(a_color1.m_alpha,
& a_color1.m_red|a_color2.m_red,
& a_color1.m_green|a_color2.m_green,
& a_color1.m_blue|a_color2.m_blue)
endmethod
protected m_alpha, int
endclass
endnamespace
main
record
black ,@Color
blue ,@TransparentColor
which ,@Color
proc
open(1,o,"TT:")
black = new Color(2,2,2) ;Almost black
blue = new TransparentColor(42,0,0,255) ;A translucent blue
which = black + blue
writes(1,hex(which.RgbValue))
end
a. 42FF0202
b. 2AFF0202
c. 00FF0202
d. This does not compile
Explanation
In this example, we provide a simple Color class that enables you to compose an RGB color value from red, green, and blue components. It also provides an overload for the “+” operator that mixes the two colors by combining the intensities of those three components.
Next, we derive a TransparentColor class that adds an alpha component (for transparency). When adding a Color (or another TransparentColor) to a TransparentColor, we want to keep the transparency of the original while mixing the color components the same as we did for Color.
In our usage example, we add a Color and a TransparentColor. Because the first operand is a Color, the argument signature for the TransparentColor.op_Addition method does not match, because it defines the first argument as a TransparentColor. Instead, Color.Addition is called (because a TransparentColor is also a Color), so the transparency value is lost. Thus, (c) is the correct response.
If we had wanted (b) instead, we could have done one of two things: (1) change “black + blue” to “blue + black”, or better yet, (2) define another version of TransparentColor.op_Addition that defines the arguments as Color and TransparentColor, in that order. Otherwise, you need to know which is which and who is who.
As you can see, it’s very easy to define an overload that makes addition not commutative. That’s counterintuitive for even a first-grade mathematician and should be avoided. In a case like the above, it’s probably more intuitive to avoid operator overloading altogether and create a virtual Mix() method instead. Reserve overloading mathematical operators for instances in which they have clear mathematical meaning and utility, and then ensure the consistency of their behavior.