--[[ Complex Number Object-Oriented Module H. Conrad Cunningham, Professor Computer and Information Science University of Mississippi Developed for CSci 658, Software Language Engineering, Fall 2013 1234567890123456789012345678901234567890123456789012345678901234567890 2013-10-01: Developed object-oriented version from data-directed The names and semantics of the methods follow that in SICP and the other complex number examples used in this course. --]] -- Load complex number utilities module local util = require "complexUtilities" -- local definitions for convenience local square = util.square local show_data = util.show_data -- COMPLEX NUMBER CLASS HIERARCHY -- Type tags local COMPLEX = "Complex" local RECTANGULAR = "Rectangular" local POLAR = "Polar" -- ABSTRACT SUPERCLASS Complex prototype local Complex = { tag = COMPLEX } function Complex:new(o) o = o or {} setmetatable(o,self) self.__index = self return o end -- Accessors function Complex:get_tag() return self.tag end -- Deferred "hook" method "display" is used by method "to_string" to -- display the body of the string. It must be implemented -- appropriately by each subclass to return a table of strings to be -- concatenated, separated by commas. function Complex:display() return { " ERROR: Complex:display() called " } end -- Concrete "template" method "to_string" converts the object to a -- string representation of form ObjectType( body ). It calls down to -- "hook" method "display" from the subclass to convert the body of -- the expression to a string. function Complex:to_string() print("in to_string get_tag = " .. self:get_tag()) return self:get_tag() .. "(" .. table.concat(self:display(), ", ") .. ")" end -- Deferred accessor (selector) methods to be defined by subclasses function Complex:real_part() error("Error: Accessing real part of abstract type Complex",2) end function Complex:imag_part() error("Error: Accessing imaginary part of abstract type Complex",2) end function Complex:magnitude() error("Error: Accessing magnitude part of abstract type Complex",2) end function Complex:angle() error("Error: Accessing angle part of abstract type Complex",2) end -- Concrete complex arithmetic operations function Complex:add_complex(z2) return self:make_from_real_imag(self:real_part() + z2:real_part(), self:imag_part() + z2:imag_part() ) end function Complex:sub_complex(z2) return self:make_from_real_imag(self:real_part() - z2:real_part(), self:imag_part() - z2:imag_part() ) end function Complex:mul_complex(z2) return self:make_from_mag_ang(self:magnitude() * z2:magnitude(), self:angle() + z2:angle() ) end function Complex:div_complex(z2) return self:make_from_mag_ang(self:magnitude() / z2:magnitude(), self:angle() - z2:angle() ) end -- CONCRETE SUBCLASS Rectangular prototype local Rectangular = Complex:new { tag = RECTANGULAR } -- Factory (constructor/initializer) methods function Rectangular:make_from_real_imag(x,y) return Rectangular:new { real = x, imag = y } end function Rectangular:make_from_mag_ang(r,a) return Rectangular:new { real = r * math.cos(a), imag = r * math.sin(a) } end -- Concrete accessor (selector) methods function Rectangular:real_part() return self.real end function Rectangular:imag_part() return self.imag end function Rectangular:magnitude() return math.sqrt(square(self:real_part()) + square(self:imag_part())) end function Rectangular:angle() return math.atan2(self:imag_part(), self:real_part()) end function Rectangular:display() return { tostring(self:real_part()), tostring(self:imag_part()) } end -- CONCRETE SUBCLASS Polar prototype local Polar = Complex:new { tag = POLAR } -- Factory (constructor/initializer) methods function Polar:make_from_real_imag(x,y) return Polar:new { mag = math.sqrt(square(x) + square(y)), ang = math.atan2(y,x) } end function Polar:make_from_mag_ang(r,a) return Polar:new { mag = r, ang = a } end -- Concrete accessor (selector) methods function Polar:magnitude() return self.mag end function Polar:angle() return self.ang end function Polar:real_part() return self:magnitude() * math.cos(self:angle()) end function Polar:imag_part() return self:magnitude() * math.sin(self:angle()) end function Polar:display() return { tostring(self:magnitude()), tostring(self:angle()) } end -- CONTINUATION of Complex class -- Generic factory methods for complex numbers -- These are unusual in that they call down to specific subclass -- factory (constructor/initializer) methods; they are thus strongly -- coupled with specific subclasses. They are at the end because they -- refer to the Rectangular and Polar subclasses. function Complex:make_from_real_imag(x,y) return Rectangular:make_from_real_imag(x,y) end function Complex:make_from_mag_ang(r,a) return Polar:make_from_mag_ang(r,a) end -- MODULE EXPORT return { Complex = Complex, Rectangular = Rectangular, Polar = Polar, show_data = show_data }