# Solution to the triple dispatch exercise # NOTE: This example is a bit contrived, because we don't actually use the # values x, y, and z. In general, the "base cases" of a multimethod (the third # level in this case) will behave differently based on the classes that the # dispatched arguments are determined to have (e.g., by calling different # methods or by doing different computation altogether). # Kick off the process for a given x, y, and z def f(x, y, z) puts x.f(y, z) end class A # The first dispatch level def f(y, z) # x is self, and must be an instance of A y.f_A(self, z) end # The second dispatch level def f_A(x_A, z) # x (now named x_A) was an instance of A # y is self, which must be an instance of A z.f_AA(x_A, self) end def f_B(x_B, z) # x (now named x_B) was an instance of B # y is self, which must be an instance of A z.f_BA(x_B, self) end # The third dispatch level def f_AA(x_A, y_A) # x (now named x_A) was an instance of A # y (now named y_A) was an instance of A # z is self, which must be an instance of A "(A, A, A)" end def f_AB(x_A, y_B) # x (now named x_A) was an instance of A # y (now named y_B) was an instance of B # z is self, which must be an instance of A "(A, B, A)" end def f_BA(x_B, y_A) # x (now named x_B) was an instance of B # y (now named y_A) was an instance of A # z is self, which must be an instance of A "(B, A, A)" end def f_BB(x_B, y_B) # x (now named x_B) was an instance of B # y (now named y_B) was an instance of B # z is self, which must be an instance of A "(B, B, A)" end end class B # The first dispatch level def f(y, z) # x is self, which must be an instance of B y.f_B(self, z) end # The second dispatch level def f_A(x_A, z) # x (now named x_A) was an instance of A # y is self, which must be an instance of B z.f_AB(x_A, self) end def f_B(x_B, z) # x (now named x_B) was an instance of B # y is self, which must be an instance of B z.f_BB(x_B, self) end # The third dispatch level def f_AA(x_A, y_A) # x (now named x_A) was an instance of A # y (now named y_A) was an instance of A # z is self, which must be an instance of B "(A, A, B)" end def f_AB(x_A, y_B) # x (now named x_A) was an instance of A # y (now named y_B) was an instance of B # z is self, which must be an instance of B "(A, B, B)" end def f_BA(x_B, y_A) # x (now named x_B) was an instance of B # y (now named y_A) was an instance of A # z is self, which must be an instance of A "(B, A, B)" end def f_BB(x_B, y_B) # x (now named x_B) was an instance of B # y (now named y_B) was an instance of B # z is self, which must be an instance of A "(B, B, B)" end end # Solution to the bonus exercise, using reflection def g(x, y, z) puts "(" + x.class.to_s + ", " + y.class.to_s + ", " + z.class.to_s + ")" end