--****************************************************************************** --* * --* File: Lua_04.lua Revision: 1.0 * --* * --* Contents: experiments with tag-methods for numeric operators * --* * --* Creation: 06.03.2002 Last Modification: 06.03.2002 * --* * --* Platform: IBM-compatible PC running Windows 98SE * --* * --* Environment: Lua 4.0, TkLua 4.0 * --* * --* Author: Andreas Rozek Phone: ++49 (711) 6770682 * --* Kirschblütenweg 15 Fax: - * --* D-70569 Stuttgart EMail: Andreas.Rozek@T-Online.De * --* Germany * --* * --* URL: http://www.Andreas-Rozek.de/ * --* * --* Copyright: the software is published under the "GNU Lesser General Pub- * --* lic License" (see "http://www.fsf.org/copyleft/lesser.html" * --* for additional information) * --* * --* Comments: (none) * --* * --****************************************************************************** dofile("Lua_03_Lib.lua"); --**** map numeric operators on synonymous object methods **** local add_Mapper = function (Op1, Op2) if (tag(Op1) == tag(Object)) then return Op1:__add__(Op2); -- naming convention similar to Python elseif (tag(Op2) == tag(Object)) then return Op2:__radd__(Op1); -- naming convention similar to Python else error( "error: unable to add non-numeric values (argument types are \"".. type(Op1).."\" and \""..type(Op2).."\")" ); end; end; settagmethod(tag(Object),"add",add_Mapper); local sub_Mapper = function (Op1, Op2) if (tag(Op1) == tag(Object)) then return Op1:__sub__(Op2); -- naming convention similar to Python elseif (tag(Op2) == tag(Object)) then return Op2:__rsub__(Op1); -- naming convention similar to Python else error( "error: unable to subtract non-numeric values (argument types are \"".. type(Op1).."\" and \""..type(Op2).."\")" ); end; end; settagmethod(tag(Object),"sub",sub_Mapper); local mul_Mapper = function (Op1, Op2) if (tag(Op1) == tag(Object)) then return Op1:__mul__(Op2); -- naming convention similar to Python elseif (tag(Op2) == tag(Object)) then return Op2:__rmul__(Op1); -- naming convention similar to Python else error( "error: unable to multiply non-numeric values (argument types are \"".. type(Op1).."\" and \""..type(Op2).."\")" ); end; end; settagmethod(tag(Object),"mul",mul_Mapper); local div_Mapper = function (Op1, Op2) if (tag(Op1) == tag(Object)) then return Op1:__div__(Op2); -- naming convention similar to Python elseif (tag(Op2) == tag(Object)) then return Op2:__rdiv__(Op1); -- naming convention similar to Python else error( "error: unable to divide non-numeric values (argument types are \"".. type(Op1).."\" and \""..type(Op2).."\")" ); end; end; settagmethod(tag(Object),"div",div_Mapper); local pow_Mapper = function (Op1, Op2) if (tag(Op1) == tag(Object)) then return Op1:__pow__(Op2); -- naming convention similar to Python elseif (tag(Op2) == tag(Object)) then return Op2:__rpow__(Op1); -- naming convention similar to Python else error( "error: unable to exponentiate non-numeric values (argument types are \"".. type(Op1).."\" and \""..type(Op2).."\")" ); end; end; settagmethod(tag(Object),"pow",pow_Mapper); local unm_Mapper = function (Op) if (tag(Op) == tag(Object)) then return Op:__neg__(); -- naming convention similar to Python else error( "error: unable to negate non-numeric values (argument type is \"".. type(Op).."\")" ); end; end; settagmethod(tag(Object),"unm",unm_Mapper); local lt_Mapper = function (Op1, Op2) if (tag(Op1) == tag(Object)) then return Op1:__lt__(Op2); -- naming convention similar to Python elseif (tag(Op2) == tag(Object)) then return Op2:__rlt__(Op1); -- naming convention similar to Python else error( "error: unable to compare non-numeric and non-string values ".. "(argument types are \""..type(Op1).."\" and \""..type(Op2).."\")" ); end; end; settagmethod(tag(Object),"lt",lt_Mapper); --**** provide "empty" methods within "Object" **** function Object:__add__ (Operand) -- responsible for self + Operand error("error: no implementation for \"+\" operator found"); end; function Object:__radd__ (Operand) -- responsible for Operand + self error("error: no implementation for \"+\" operator found"); end; function Object:__sub__ (Operand) -- responsible for self - Operand error("error: no implementation for \"-\" operator found"); end; function Object:__rsub__ (Operand) -- responsible for Operand - self error("error: no implementation for \"-\" operator found"); end; function Object:__mul__ (Operand) -- responsible for self * Operand error("error: no implementation for \"*\" operator found"); end; function Object:__rmul__ (Operand) -- responsible for Operand * self error("error: no implementation for \"*\" operator found"); end; function Object:__div__ (Operand) -- responsible for self / Operand error("error: no implementation for \"/\" operator found"); end; function Object:__rdiv__ (Operand) -- responsible for Operand / self error("error: no implementation for \"/\" operator found"); end; function Object:__pow__ (Operand) -- responsible for self ^ Operand error("error: no implementation for \"^\" operator found"); end; function Object:__rpow__ (Operand) -- responsible for Operand ^ self error("error: no implementation for \"^\" operator found"); end; function Object:__neg__ () -- responsible for -self error("error: no implementation for sign operator found"); end; function Object:__lt__ (Operand) -- responsible for self < Operand error("error: no implementation for \"<\" operator (or similar) found"); end; function Object:__rlt__ (Operand) -- responsible for Operand < self error("error: no implementation for \"<\" operator (or similar) found"); end; --****************************************************************************** --* * --* Complex - a simple implementation of complex numbers * --* * --****************************************************************************** Complex = Object{_re=0.0,_im=0.0}; function Complex:__add__ (Operand) if (type(Operand) == "number") then return Complex(self._re+Operand,self._im); end; if (tag(Operand) == tag(Object)) and (Operand:inheritsfrom(Complex)) then return Complex(self._re+Operand._re, self._im+Operand._im); end; error("non-numeric Operand given"); end; Complex.__radd__ = Complex.__add__; -- addition is commutative function Complex:__sub__ (Operand) if (type(Operand) == "number") then return Complex(self._re-Operand,self._im); end; if (tag(Operand) == tag(Object)) and (Operand:inheritsfrom(Complex)) then return Complex(self._re-Operand._re, self._im-Operand._im); end; error("non-numeric Operand given"); end; function Complex:__rsub__ (Operand) if (type(Operand) == "number") then return Complex(Operand-self._re,-self._im); end; if (tag(Operand) == tag(Object)) and (Operand:inheritsfrom(Complex)) then return Complex(Operand._re-self._re, Operand._im-self._im); end; error("non-numeric Operand given"); end; function Complex:__mul__ (Operand) -- responsible for self * Operand if (type(Operand) == "number") then return Complex(Operand*self._re,Operand*self._im); end; if (tag(Operand) == tag(Object)) and (Operand:inheritsfrom(Complex)) then return Complex( self._re*Operand._re - self._im*Operand._im, self._im*Operand._re + self._re*Operand._im ); end; error("non-numeric Operand given"); end; Complex.__rmul__ = Complex.__mul__; -- multiplication is commutative function Complex:__div__ (Operand) -- responsible for self / Operand if (type(Operand) == "number") then return Complex(self._re/Operand,self._im/Operand); end; if (tag(Operand) == tag(Object)) and (Operand:inheritsfrom(Complex)) then local sqr = Operand._re*Operand._re + Operand._im*Operand._im; return Complex( (self._re*Operand._re + self._im*Operand._im)/sqr, (self._im*Operand._re - self._re*Operand._im)/sqr ); end; error("non-numeric Operand given"); end; function Complex:__rdiv__ (Operand) -- responsible for Operand / self if (type(Operand) == "number") then local sqr = self._re*self._re + self._im*self._im; return Complex(self._re*Operand/sqr,-self._im*Operand/sqr); end; if (tag(Operand) == tag(Object)) and (Operand:inheritsfrom(Complex)) then local sqr = self._re*self._re + self._im*self._im; return Complex( (self._re*Operand._re + self._im*Operand._im)/sqr, (self._re*Operand._im - self._im*Operand._re)/sqr ); end; error("non-numeric Operand given"); end; function Complex:__neg__ () -- responsible for -self return Complex(-self._re, -self._im); end; function Complex:abs () return sqrt(self._re*self._re + self._im*self._im); end; function Complex:equals (Candidate) if (type(Candidate) == "number") then return (self._re == Candidate) and (self._im == 0); end; if (tag(Candidate) == tag(Object)) and (Candidate:inheritsfrom(Complex)) then return (self._re == Candidate._re) and (self._im == Candidate._im); end; return false; end; function Complex:new (Re, Im) local Result = Object{_re=0,_im=0,_prototype=Complex}; if (Re == nil) then -- no arguments given assert(Im == nil, "illegal use of constructor 'Complex': imaginary part is given while real part is not"); elseif (type(Re) == "number") then -- numeric argument(s) given Result._re = Re; if (Im ~= nil) then assert(type(Im) == "number", "illegal use of constructor 'Complex': non-numeric imaginary part"); Result._im = Im; end; -- complex argument given elseif (tag(Re) == tag(Object)) and (Re:inheritsfrom(Complex)) then Result._re,Result._im = Re._re,Re._im else -- oops: argument is neither numeric nor complex error("illegal use of constructor 'Complex': illegal type of argument ("..type(Re)..")"); end; return Result; end; function Complex:toString () if (self._im == 0) then return tostring(self._re); elseif (self._im < 0) then return tostring(self._re).."-i*"..tostring(-self._im); else return tostring(self._re).."+i*"..tostring(self._im); end; end; --****************************************************************************** --* * --* main program * --* * --****************************************************************************** print(); print("Lua_04 - experiments with tag-methods for numeric operators"); print(); local a = Complex(1.0,1.0); local b = Complex(2.0); local c = Complex(0.0,3.0); print("complex numbers:"); print(" a = 1.0+i*1.0 = ", a); print(" b = 2.0 = ", b); print(" c = i*3.0 = ", c); print(); print("basic operators:"); print(" -a = ", -a); print(" -c = ", -c); print(" a+b = ", a+b); print(" a+c = ", a+c); print(" a-b = ", a-b); print(" a-c = ", a-c); print(" a*b = ", a*b); print(" a*c = ", a*c); print(" a/b = ", a/b); print(" a/c = ", a/c); exit();